Visualizations: {stringr}

Using dplyr and the stringr::words dataset, we can demonstrate how to extract information from a dataset. Before we get into anything, let us take a look at a few of the characteristics of the stringr::words dataset.

library(stringr) # Text Matching
library(dplyr,warn.conflicts = FALSE) # Data Wrangling
library(ggplot2) # Plotting
library(forcats) # Managing Categories
library(tidytext) # Word Tokenization
library(huxtable) # Making Tables

head(stringr::words)
[1] "a"        "able"     "about"    "absolute" "accept"   "account" 
length(words)
[1] 980

A dataset with 980 words seems like a great tool to have!

Example 1: Match Five Letter Words

The following regular expression should match the red text below:

Upon the shelf was a penny and a dime

  1. Using str_match_all we can enter a regular expression that will match words that have five characters.
five_letter <- 
  str_match(words,pattern = "\\w{5}") |> na.omit()

sample(five_letter,5)
[1] "docto" "welco" "score" "story" "durin"

Uh oh!

We are returning words that have 5 letters, but are not only five letters in length. To fix this, we will need to add a boundary element (\b) to the start and end of our expression.

five_letter_fixed <- 
  str_match_all(words, pattern = "\\b\\w{5}\\b") |> 
    unlist()

head(five_letter_fixed)
[1] "about" "admit" "after" "again" "agent" "agree"
Note

The use of unlist() coerces the result to a vector instead of a list

The regular expression \\b\\w{5}\\b here does the following:

  • \b represents a boundary character. This tells R to look for something to be followed by a space and finished before a space.

  • \w tells R to look for a word-character.

  • {5} tells R to look for a word-character that has a length of exactly 5.

  • \b looks for the second boundary.

Example 2: Finding Words That Start with aeiou

Here we will use a regular expression that looks for words that start with specific letters.

Note: The words dataset is specifically lowercase*, otherwise we would be using both upper and lower case in our expression.

vowel_words <- 
 str_match_all(words,"\\b^[aeiou].*$") |> 
  unlist()

sample(vowel_words,5)
[1] "again"     "achieve"   "unite"     "otherwise" "another"  

Great!

The regular expression does the following:

  • \b - Looks for boundary

  • ^ - Designates the start of a string.

  • [aeiou] - Matches the start of the string that is either a,e,i,o,or u.

  • . - Looks for any character that follows the first match.

  • * - Looks for an unlimited number of matches until it is told to stop.

  • $ - Tells R to look for the end of a string.

Example 2b. Finding words that DON’T start with vowels

We can use the same regular expression we created earlier and at a not qualifier to essentially reverse our search.

str_match_all(words,"\\b[^aeiou].*$") |> 
  unlist() |> 
  sample(5)
[1] "case"     "hospital" "special"  "sing"     "cook"    

Note that by moving the beginning of string qualifier ^ to the inside of the bracket resulted in the opposite of what we were looking for!

Most Common Start Letter Used in stringr::words

word_tbl <- 
  words |>
  data.frame() |>
  mutate(
    StartsWith = str_match(words,"^.") |> unlist()
  ) |> 
  group_by(StartsWith) |>
  count(sort = TRUE)
  
word_tbl |> 
  head() |> 
  hux() |>
  theme_article()
1
words: This is the input dataset (assumed to be a vector or list of words) that will be processed.
2
data.frame(): Converts the words object into a data frame to facilitate data manipulation.
3
mutate() and str_match(): Adds a new column StartsWith, extracting the first letter from each word using a regular expression. unlist() flattens the result into a vector.
4
group_by() and count(): Groups the data by the StartsWith column and counts the number of occurrences for each letter, sorting the counts in descending order.
5
hux(): Converts the resulting grouped and counted data into a huxtable object, which formats the data into a table.
6
theme_article(): Applies the “article” theme to style the table for presentation.
StartsWithn
s119
c83
p72
a65
t65
b58

Taking a look at the table we can see that there are two words that start with a capital C. This doesn’t halt the process, but it is worth it to see who the culprits are.

word_tbl %>% 
  filter(StartsWith == "C")
Warning: Using one column matrices in `filter()` or `filter_out()` was deprecated in
dplyr 1.1.0.
ℹ Please use one dimensional logical vectors instead.
# A tibble: 1 × 2
# Groups:   StartsWith [1]
  StartsWith[,1]     n
  <chr>          <int>
1 C                  2

For our purposes, it is okay to change these entries to be lowercase. Conveniently, the stringr package really does have it all!

words <- 
  str_to_lower(stringr::words)

word_tbl <- 
  words |> 
  data.frame() |> 
  mutate(sw= str_match_all(words,"^.") |> 
           unlist()) %>% 
  group_by(sw) %>% 
  count(sort = TRUE)

word_tbl |> 
  head() |> 
  hux() |> 
  theme_article()
swn
s119
c85
p72
a65
t65
b58

We could look at the table and make some observations, but it would be better to just graph everything!

Keep in mind that this list of words is only 980 observations long so there are plenty of missing words. With that being said, what letter is represented the most in the stringr::words vector?

word_tbl %>% 
  ggplot(aes(fct_reorder(sw,n),n,fill=n,label = n)) + 
    geom_bar(stat="identity",
             aes(fill = ifelse(n == max(n),"darkred","grey"))) +
    coord_flip() +
  labs(x ="",
       y ="",
       title ="Starting Letter Word Frequency",
       subtitle = "The words dataset favors 's'and 'c'",
       caption = "Data from stringr::words") +
    theme_minimal() +
    theme(
      axis.ticks = element_blank(),
      legend.position = "none",
      axix.x.text = element_blank(),
      plot.title.position = "plot",
      plot.title = element_text(size = 20,
                              face = "bold"),
      plot.subtitle = element_text(face = "italic")
  ) + 
  scale_fill_identity() 
Warning in plot_theme(plot): The `axix.x.text` theme element is not defined in
the element hierarchy.

Most Frequent Word Length in stringr::words

To get a words length, we can use str_length()

# Take a sample of 10 observations from the words package

set.seed(616)

ww <- sample(words,10)

tibble(
  word = ww,
  wl = str_length(ww)
) 
wordwl
nature6
clothe6
back4
other5
allow5
suggest7
however7
cup3
mile4
just4

Using this same approach we could find out the number of each letter-sized word in the package.

# X-Axis Values for later
xax <- 1:11

words_t <- 
  words |> 
  data.frame() |> 
  mutate(string_length = str_length(words)) %>% 
  group_by(string_length) %>% 
  count() 

words_t
# A tibble: 11 × 2
# Groups:   string_length [11]
   string_length     n
           <int> <int>
 1             1     1
 2             2    18
 3             3   110
 4             4   263
 5             5   200
 6             6   169
 7             7   119
 8             8    57
 9             9    30
10            10     9
11            11     4
words_t %>%
  ggplot(aes(string_length, n, 
             fill = string_length)) +
  geom_bar(stat = "identity",
           aes(fill = ifelse(n == max(n),"darkred","grey"))) +
  coord_flip() +
  scale_x_continuous(breaks = xax) +
  theme_minimal() +
  theme(
    legend.position = "none",
    axis.ticks = element_blank(),
    axis.text.x = element_blank(),
    plot.title = element_text(face = "bold",
                              size = 20),
    plot.title.position = "plot",
    plot.subtitle = element_text(face = "italic")
        ) +
  scale_fill_identity() +
  ylim(0, 300) +
  labs(
    x = "",
    y = "",
    title = "Frequency Distribution of Word Size",
    subtitle = "Keeping it Short and Sweet!",
    caption = "Data from stringr::words"
  ) 

stringr::sentences

stringr also contains a sentences dataset.

tibble(
    line=1:length(sentences),
    sentence=sentences) %>% 
  unnest_tokens(word,sentence) %>% 
  anti_join(stop_words) %>% 
  group_by(word) %>% 
  count(sort=T) %>% 
  ungroup() |> 
  wordcloud2::wordcloud2()
Joining with `by = join_by(word)`

Whoa! There are sure a lot of sentences with ‘red’ in them. Let’s isolate those 11 sentences.

tibble(
    line=1:length(sentences),
    sentence=sentences) |> 
  filter(str_detect(sentences,"\\bred\\b")) |> 
  select(sentence)
sentence
The sofa cushion is red and of light weight.
It is hard to erase blue or red ink.
The box is held by a bright red snapper.
The houses are built of red clay bricks.
The red tape bound the smuggled food.
The lake sparkled in the red hot sun.
Mark the spot with a sign painted red.
The small red neon lamp went out.
The sky in the west is tinged with orange red.
The red paper brightened the dim stage.
The big red apple fell to the ground.