I added another row to your example to have a bit more variation. This should be pretty efficient:
library(tibble)
library(purrr)
library(dplyr)
library(stringr)
q_data <- tibble(number = 1:2, string = c("COUNTTHESECHARACTERS", "countthesecharacters"))
tmp_data <- map_df(q_data$string, function(s) {
tmp <- t(str_count(s, fixed(LETTERS, ignore_case = TRUE)))
tmp <- as_tibble(tmp, .name_repair = "minimal")
colnames(tmp) <- LETTERS
tmp
}) %>%
bind_rows()
q_data_new <- cbind(q_data, tmp_data)
q_data_new
#> number string A B C D E F G H I J K L M N O P Q R S T U V
#> 1 1 COUNTTHESECHARACTERS 2 0 3 0 3 0 0 2 0 0 0 0 0 1 1 0 0 2 2 3 1 0
#> 2 2 countthesecharacters 2 0 3 0 3 0 0 2 0 0 0 0 0 1 1 0 0 2 2 3 1 0
#> W X Y Z
#> 1 0 0 0 0
#> 2 0 0 0 0
Created on 2019-10-18 by the reprex package (v0.3.0)
If you look up ?str_count
from stringr
you can see a couple more options that might be useful in your case.
Update
I realised only from the other answer that what you are trying to do is count all elements of a string, not just letters. In this case you are basically looking for a docuemnt feature matrix:
library(quanteda)
tmp <- q_data$string %>%
tokens("character", remove_separators = FALSE) %>%
dfm() %>%
convert("data.frame") %>%
select(-document) %>%
select(noquote(order(colnames(.)))) %>% # this is just for ordering alpabetically
as_tibble() # just for better comparison to other results
q_data_new <- cbind(q_data, tmp)
q_data_new
This is even a lot faster than the two options already given in the answers. Benchmarking:
q_data <- tibble(number = 1:2000, string = stringi::stri_rand_strings(2000, 20))
stringr <- function(q_data, pattern = c(0:9, letters)) {
tmp_data <- map_df(q_data$string, function(s) {
tmp <- t(str_count(s, fixed(pattern, ignore_case = TRUE)))
tmp <- as_tibble(tmp, .name_repair = "minimal")
colnames(tmp) <- pattern
tmp
}) %>%
bind_rows() %>%
mutate_if(is.integer, as.numeric)
q_data_new <- bind_cols(q_data, tmp_data)
q_data_new
}
tidytext <- function(q_data) {
q_data %>%
group_by(number, string) %>%
unnest_tokens(character, string, token = "characters", drop = FALSE) %>%
count(number, character) %>%
complete(character = letters) %>%
spread(character, n, fill = 0) %>%
ungroup()
}
quanteda <- function(q_data) {
tmp <- q_data$string %>%
tokens("character", remove_separators = FALSE) %>%
dfm() %>%
convert("data.frame") %>%
select(-document) %>%
select(noquote(order(colnames(.)))) %>%
as_tibble()
q_data_new <- cbind(q_data, tmp)
q_data_new
}
results
res <- bench::mark(
stringr = stringr(q_data),
tidytext = tidytext(q_data),
quanteda = quanteda(q_data)
)
res
#> # A tibble: 3 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 stringr 1.82s 1.82s 0.549 17.05MB 3.84
#> 2 tidytext 6.06s 6.06s 0.165 35.17MB 2.31
#> 3 quanteda 56.4ms 70.74ms 13.9 8.75MB 5.95