Split string into words and assign to new columns

Viewed 58

I have speaking Turns of different lengths. I want to break the Turns into individual words and assign each word to a new column depending on the word's position in the utterance:

test <- data.frame(
  Speaker = c("PS1G3","PS1G2","PS1G3","PS1G2"),
  N_words = c(2,3,4,1),
  Turn = c("can you","what 's the","are you going up","what"),
  c5 = c("VM0 PNP","DTQ VBZ AT0","VBB PNP VVG AVP","DTQ"))

The output I'm looking for is this:

test
  Speaker N_words             Turn              c5   w1   w2    w3   w4
1   PS1G3       2          can you         VM0 PNP  can  you  <NA> <NA>
2   PS1G2       3      what 's the     DTQ VBZ AT0 what   's   the <NA>
3   PS1G3       4 are you going up VBB PNP VVG AVP  are  you going   up
4   PS1G2       1             what             DTQ what <NA>  <NA> <NA>

I know how to split the Turns into individual words but am stuck there:

lapply(test$Turn, function(x) unlist(strsplit(x, "\\s")))
4 Answers

We can use read.table from base R

cbind(test, read.table(text = test$Turn, 
       header = FALSE, fill = TRUE, quote = "",  na.strings = ""))

-output

#  Speaker N_words             Turn              c5   V1   V2    V3   V4
#1   PS1G3       2          can you         VM0 PNP  can  you  <NA> <NA>
#2   PS1G2       3      what 's the     DTQ VBZ AT0 what   's   the <NA>
#3   PS1G3       4 are you going up VBB PNP VVG AVP  are  you going   up
#4   PS1G2       1             what             DTQ what <NA>  <NA> <NA>

This tidyverse approach may also help

test <- data.frame(
  Speaker = c("PS1G3","PS1G2","PS1G3","PS1G2"),
  N_words = c(2,3,4,1),
  Turn = c("can you","what 's the","are you going up","what"),
  c5 = c("VM0 PNP","DTQ VBZ AT0","VBB PNP VVG AVP","DTQ"))

library(tidyverse)

test %>% separate(Turn, into = paste0('w', seq_len(1 + max(str_count(test$Turn, ' ')))), fill = 'right', remove = F, sep = ' ')
#>   Speaker N_words             Turn   w1   w2    w3   w4              c5
#> 1   PS1G3       2          can you  can  you  <NA> <NA>         VM0 PNP
#> 2   PS1G2       3      what 's the what   's   the <NA>     DTQ VBZ AT0
#> 3   PS1G3       4 are you going up  are  you going   up VBB PNP VVG AVP
#> 4   PS1G2       1             what what <NA>  <NA> <NA>             DTQ

Created on 2021-05-05 by the reprex package (v2.0.0)

There is no need to use lapply to split the string. The splitted string is extended to the longest length using [ in sapply. The result is cbind to test.

tt <- strsplit(test$Turn, "\\s")
cbind(test, t(sapply(tt, "[", seq_len(max(lengths(tt))))))
#  Speaker N_words             Turn              c5    1    2     3    4
#1   PS1G3       2          can you         VM0 PNP  can  you  <NA> <NA>
#2   PS1G2       3      what 's the     DTQ VBZ AT0 what   's   the <NA>
#3   PS1G3       4 are you going up VBB PNP VVG AVP  are  you going   up
#4   PS1G2       1             what             DTQ what <NA>  <NA> <NA>

You can use cSplit from splitstackshape :

splitstackshape::cSplit(test, 'Turn', sep = "\\s", fixed = FALSE, stripWhite = FALSE)

#   Speaker N_words              c5 Turn_1 Turn_2 Turn_3 Turn_4
#1:   PS1G3       2         VM0 PNP    can    you   <NA>   <NA>
#2:   PS1G2       3     DTQ VBZ AT0   what     's    the   <NA>
#3:   PS1G3       4 VBB PNP VVG AVP    are    you  going     up
#4:   PS1G2       1             DTQ   what   <NA>   <NA>   <NA>
Related