将字符串拆分为单词列表

时间:2018-01-06 07:51:10

标签: r regex string split

我有一个来自二手资料的数据框,其中一列中有很多关键信息,以空格分隔。我不能简单地使用str_split,因为某些关键信息在名称中有空格,但它们前面是分组变量。这是一个使用食物和食物组的例子:

foo1 <- paste('FRUIT', 'Apple', 'PROTEIN', 'Chicken', 'STARCH', 'Banana Bread', 'FRUIT', 'Strawberry')
foo2 <- paste('PROTEIN', 'Pork', 'FAT', 'Butter', 'FRUIT', 'Banana', 'STARCH', 'Spaghetti')
foo3 <- paste('FRUIT', 'Strawberry', 'PROTEIN', 'Lean Steak', 'FRUIT', 'Strawberry', 'STARCH', 'Potato')

df <- rbind(foo1, foo2, foo3)
df

foo1 "FRUIT Apple PROTEIN Chicken STARCH Banana Bread FRUIT Strawberry"  
foo2 "PROTEIN Pork FAT Butter FRUIT Banana STARCH Spaghetti"             
foo3 "FRUIT Strawberry PROTEIN Lean Steak FRUIT Strawberry Starch Potato"

在这种情况下,我想要抓住的关键部分是实际的食物,但我不能分开空间,因为存在“香蕉面包”之类的东西。因此,我只能分解FRUIT,PROTEIN,STARCH或FAT,但我无法找到一个很好的方法来做到这一点。在我的实际表中,仍然只有4个“分组”,但是超过500个单独的项目,因此尝试使用空格映射特定的项目将是一个巨大的痛苦。以下行不起作用:

str_split(df, c('FRUIT', 'PROTEIN', 'STARCH', 'FAT'))
str_split_fixed(df, c('FRUIT', 'PROTEIN', 'STARCH', 'FAT'), 4)

有什么想法?提前谢谢。

6 个答案:

答案 0 :(得分:4)

您可以使用正则表达式来执行此操作:

str_split(df, c('FRUIT|PROTEIN|STARCH|FAT'))
[[1]]
[1] ""               " Apple "        " Chicken "      " Banana Bread " " Strawberry"   

[[2]]
[1] ""           " Pork "     " Butter "   " Banana "   " Spaghetti"

[[3]]
[1] ""             " Strawberry " " Lean Steak " " Strawberry " " Potato"    

使用粘贴中的折叠arg将vec转换为正则表达式:

paste(c('FRUIT', 'PROTEIN', 'STARCH', 'FAT'), collapse = '|')
[1] "FRUIT|PROTEIN|STARCH|FAT"

最好,

科林

答案 1 :(得分:3)

由于您只需要食物,因此使用tidyverse的跟随方法应该可以解决问题:

library(stringr)
library(tidyverse)

foo1 <- paste('FRUIT', 'Apple', 'PROTEIN', 'Chicken', 'STARCH', 'Banana Bread', 'FRUIT', 'Strawberry')
foo2 <- paste('PROTEIN', 'Pork', 'FAT', 'Butter', 'FRUIT', 'Banana', 'STARCH', 'Spaghetti')
foo3 <- paste('FRUIT', 'Strawberry', 'PROTEIN', 'Lean Steak', 'FRUIT', 'Strawberry', 'STARCH', 'Potato')

df <- rbind(foo1, foo2, foo3) %>%
  as_tibble()

(请注意使用as_tibble()将数据框转换为tibble对象 - 更易于使用)

现在为实际的东西:

df.new <- df %>% 
   mutate(clean.str = str_replace_all(V1, pattern = "(FRUIT|PROTEIN|STARCH|FAT)", replacement = "|") %>%
       str_sub(start = 3)) %>%
   mutate(str.ls = str_split(clean.str, fixed(" | "))) %>%
   unnest() %>% 
   select(str.ls)

这是你想要的结果,一份实际食物清单:

df.new

# A tibble: 12 x 1
     str.ls
      <chr>
  1        Apple
  2      Chicken
  3 Banana Bread
  4   Strawberry
  5         Pork
  6       Butter
  7       Banana
  8    Spaghetti
  9   Strawberry
 10   Lean Steak
 11   Strawberry
 12       Potato

答案 2 :(得分:2)

我会这样做。这看起来非常简短,易于理解。

df%>%
strsplit(split = paste(c('FRUIT', 'PROTEIN', 'STARCH', 'FAT'), collapse = "|"))%>%
unlist()%>%
.[. != ""]

 [1] " Apple "        " Chicken "      " Banana Bread " " Strawberry"    " Pork "         " Butter "       " Banana "       " Spaghetti"    
 [9] " Strawberry "   " Lean Steak "   " Strawberry "   " Potato" 

答案 3 :(得分:2)

stri_split_regex()中使用unnest_tokens(),我们可以提供以下结果。 unnest_tokens()tidytext包中的函数。在这里,我使用stri_split_regex()作为unnest_tokens()中的自定义函数。正则表达式表示,“以行开头或空格开头的模式和重复的大写字母(一次或多次)开始,模式以白色空格结束”。这允许我们按照您在问题中描述的方式拆分字符串。行名称可以帮助我们查看哪些字符串在哪个字符串中。

library(tidytext)
library(stringi)

df <- data.frame(text = c(foo1, foo2, foo3), stringsAsFactors = FALSE)

df %>%
unnest_tokens(input = text, output = word, to_lower = FALSE,
              token = stri_split_regex, 
              pattern = "(\\s|^)[A-Z]+\\s", omit_empty = TRUE)

            word
1          Apple
1.1      Chicken
1.2 Banana Bread
1.3   Strawberry
2           Pork
2.1       Butter
2.2       Banana
2.3    Spaghetti
3     Strawberry
3.1   Lean Steak
3.2   Strawberry
3.3       Potato

答案 4 :(得分:2)

使用基座R使用do.callstrsplit您可以分割并合并结果,使用当前设置,您可以尝试:

do.call("rbind", strsplit(df[,1], "FRUIT|PROTEIN|STARCH|FRUIT|FAT", perl=T))[,2:5]

<强>输出

  #         [,1]           [,2]           [,3]             [,4]         
  #  foo1 " Apple "      " Chicken "    " Banana Bread " " Strawberry"
  #  foo2 " Pork "       " Butter "     " Banana "       " Spaghetti" 
  #  foo3 " Strawberry " " Lean Steak " " Strawberry "   " Potato"  

答案 5 :(得分:2)

首先请注意,问题中的df是矩阵,而不是数据框:

class(df)
## [1] "matrix"

我们可以使用正则表达式strsplit对大写单词和周围空格进行pat分割。请注意,"\\b"与单词边界匹配。 Filter(nzchar, ...)删除零长度字符串,unique删除重复项。没有包使用。

pat <- " *\\b([A-Z]+)\\b *" 
unique(Filter(nzchar, unlist(strsplit(df[, 1], pat))))

,并提供:

[1] "Apple"        "Chicken"      "Banana Bread" "Strawberry"   "Pork"        
[6] "Butter"       "Banana"       "Spaghetti"    "Lean Steak"   "Potato" 

也可以使用像这样的magrittr管道编写:

library(magrittr)

df[, 1] %>%
        strsplit(pat) %>%
        unlist %>%
        Filter(nzchar, .) %>%
        unique
相关问题