This report is an early checkpoint for a text prediction app being built using the SwiftKey dataset (English blogs, news, and Twitter text). The purpose here is simple: show that the data has been downloaded and loaded successfully, summarize its basic structure, share a few interesting patterns, and outline the plan for building the prediction algorithm and Shiny app. This is not the final product — just a progress check.
The dataset contains three English-language text files: blogs, news, and tweets. Below, each file is read in and some basic file-level statistics are calculated (file size, number of lines, number of words).
# Update these paths to match where you've unzipped the Coursera-SwiftKey data
blogs_path <- "/Users/investguru/final/en_US/en_US.blogs.txt"
news_path <- "/Users/investguru/final/en_US/en_US.news.txt"
twitter_path <- "/Users/investguru/final/en_US/en_US.twitter.txt"
blogs <- readLines(blogs_path, encoding = "UTF-8", skipNul = TRUE, warn = FALSE)
news <- readLines(news_path, encoding = "UTF-8", skipNul = TRUE, warn = FALSE)
twitter <- readLines(twitter_path, encoding = "UTF-8", skipNul = TRUE, warn = FALSE)
Here’s a quick table comparing the three files: file size (MB), number of lines, total word count, and average words per line.
file_size_mb <- function(path) round(file.info(path)$size / 1024^2, 1)
word_counts <- c(
sum(stri_count_words(blogs)),
sum(stri_count_words(news)),
sum(stri_count_words(twitter))
)
line_counts <- c(length(blogs), length(news), length(twitter))
summary_df <- data.frame(
File = c("Blogs", "News", "Twitter"),
Size_MB = c(file_size_mb(blogs_path), file_size_mb(news_path), file_size_mb(twitter_path)),
Lines = line_counts,
Words = word_counts,
Avg_Words_Line = round(word_counts / line_counts, 1)
)
knitr::kable(summary_df, caption = "Basic summary statistics for the three source files")
| File | Size_MB | Lines | Words | Avg_Words_Line |
|---|---|---|---|---|
| Blogs | 200.4 | 899288 | 37546250 | 41.8 |
| News | 196.3 | 1010242 | 34762395 | 34.4 |
| 159.4 | 2360148 | 30093413 | 12.8 |
Looking at the numbers above, Twitter has by far the most lines (2.36 million) but the shortest average line length at just 12.8 words — which makes sense given the character limits users are used to working within. Blogs and news entries run much longer per line, averaging 41.8 and 34.4 words respectively, suggesting more complete thoughts and sentences, likely because they’re written and edited rather than typed quickly on a phone. Combined, these three files add up to over 100 million words, so working from a random sample for the rest of this analysis makes sense for speed, without losing the overall patterns in the data.
Because the full files are large, a random sample is drawn from each for the exploratory work below. This keeps the analysis fast without losing the overall patterns in the data.
set.seed(1234)
sample_pct <- 0.01 # 1% sample; adjust as needed
sample_lines <- function(x, pct) {
x[rbinom(length(x), 1, pct) == 1]
}
blogs_sample <- sample_lines(blogs, sample_pct)
news_sample <- sample_lines(news, sample_pct)
twitter_sample <- sample_lines(twitter, sample_pct)
combined_sample <- c(blogs_sample, news_sample, twitter_sample)
A histogram of word counts per line gives a sense of how long a typical entry is in each source.
line_lengths <- data.frame(
words = c(stri_count_words(blogs_sample), stri_count_words(news_sample), stri_count_words(twitter_sample)),
source = c(rep("Blogs", length(blogs_sample)),
rep("News", length(news_sample)),
rep("Twitter", length(twitter_sample)))
)
ggplot(line_lengths, aes(x = words, fill = source)) +
geom_histogram(binwidth = 5, alpha = 0.6, position = "identity") +
xlim(0, 100) +
labs(title = "Distribution of Words per Line by Source",
x = "Words per Line", y = "Count") +
theme_minimal()
To understand what the prediction model will be working with, it helps to look at the most frequently used single words across the sample.
library(tidytext)
words_df <- data.frame(text = combined_sample, stringsAsFactors = FALSE) %>%
unnest_tokens(word, text) %>%
count(word, sort = TRUE)
top20 <- head(words_df, 20)
ggplot(top20, aes(x = reorder(word, n), y = n)) +
geom_col(fill = "steelblue") +
coord_flip() +
labs(title = "Top 20 Most Frequent Words", x = "", y = "Frequency") +
theme_minimal()
As expected, the most frequent words are short, common function words like “the,” “and,” and “to” rather than anything topic-specific. This confirms that if the final model weights predictions purely on frequency, it’ll lean heavily toward these common connector words — something to keep in mind when designing how the app suggests the next word, since always suggesting “the” isn’t very useful in practice.
A useful question for building the predictive model: how many unique words are needed to cover a given percentage of all word instances in the data? This helps decide how large the model’s vocabulary needs to be.
words_df <- words_df %>%
mutate(cum_freq = cumsum(n) / sum(n))
words_for_50pct <- which(words_df$cum_freq >= 0.5)[1]
words_for_90pct <- which(words_df$cum_freq >= 0.9)[1]
coverage_df <- data.frame(
Coverage = c("50%", "90%"),
Unique_Words_Needed = c(words_for_50pct, words_for_90pct)
)
knitr::kable(coverage_df, caption = "Number of unique words needed to cover a given percentage of all word instances")
| Coverage | Unique_Words_Needed |
|---|---|
| 50% | 155 |
| 90% | 7588 |
These numbers show that just 155 unique words already cover half of everything people write, and only about 7,600 unique words are needed to cover 90% of all word instances. This is a good sign for the prediction model: it means the app doesn’t need to memorize the entire English language to be useful most of the time, since a fairly compact set of common words and phrases handles the vast majority of real-world typing.
In plain terms, here’s the plan going forward:
This report shows the three data files have been successfully downloaded and loaded, provides basic statistics and visualizations describing their structure, and outlines a clear next-step plan for building an n-gram based prediction model and accompanying Shiny app.