我有一个来自二手资料的数据框,其中一列中有很多关键信息,以空格分隔。我不能简单地使用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)
有什么想法?提前谢谢。
答案 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.call
和strsplit
您可以分割并合并结果,使用当前设置,您可以尝试:
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