拆分数据帧值并放入R中的组?

时间:2019-07-11 14:19:59

标签: r dataframe dplyr tidyverse

给出一个数据框的列,例如:

df <- structure(list(ingredients = structure(c("en:xylitol", "en:water,en:sugar,en:glucose-fructose-syrup,en:fructose,en:glucose,fr:dioxyde-de-carbone,en:acid,en:citric-acid,en:natural-flavouring,en:flavouring,fr:arome-quinine,fr:quinine", 
"en:sugar,en:corn-syrup,fr:sirop-de-mais-a-teneur-elevee-en-fructose,en:citric-acid,en:natural-and-artificial-flavouring,en:artificial-flavouring,en:natural-flavouring,en:flavouring,en:colour,fr:rouge-40,fr:bleu-1", 
"pt:semoule-de-ble-dur,pt:pesto,pt:basilic,pt:fromage-en-poudre,pt:ail-et-epinars,pt:basilic-contient-du-gluten-et-des-derives-de-lait", 
"pt:pimenta-branca", "en:water,es:pasta-de-almendras-tostadas,en:sugar", 
"en:water,es:zumo-de-chufas,en:sugar,en:dextrose,en:glucose,es:estabilizantes,es:412,es:carragenanos,es:e-407,es:carboximetil-celulosa,es:e-466,es:monodigliceridos-de-acidos-grasos,en:mono-and-diglycerides-of-fatty-acids,en:emulsifier,en:flavouring,en:guar-gum,es:e", 
"es:aceitunas-cacerena,en:water,en:salt,en:stabiliser,es:579,es:categoria,es:i,es:calibre,es:gluconato-ferroso,es:e,es:240,es:260", 
"en:carbonated-water,en:water,en:sugar,en:colour,fr:caramel-e150d,en:natural-flavouring,en:flavouring,en:acid,en:phosphoric-acid,fr:extrait-de-genepi,fr:cafeine", 
"en:pear,en:fruit,es:variedad,es:70-mm,es:conferencia,es:categoria-i,es:calibre,es:65"
), .Dim = c(10L, 1L))), row.names = c(NA, -10L), class = c("tbl_df", 
"tbl", "data.frame"))

我想用“,”分隔符分隔每一行,并将分隔的输出分组。

例如:

en:water,es:pasta-de-almendras-tostadas,en:sugar 

将变成

group ingredient
1     en:water
1     es:pasta-de-almendras-tostadas
1     en:sugar

下一步是删除XX:的前缀

请告知如何执行此操作?

5 个答案:

答案 0 :(得分:3)

添加序列列后,我们可以使用separate_rows中的tidyr

library(tidyr)
library(dplyr)
df %>% 
    mutate(group = row_number()) %>%
    separate_rows(ingredients, sep=",")

答案 1 :(得分:2)

您可以使用strsplit并根据列表编号添加一个组列,最后rbind

l <- strsplit(df$ingredients, ",")

res <- data.frame(do.call(rbind, sapply(seq(l), function(x) 
  cbind(group=x, ingredient=l[[x]]))))
head(res)
#   group                ingredient
# 1     1                en:xylitol
# 2     2                  en:water
# 3     2                  en:sugar
# 4     2 en:glucose-fructose-syrup
# 5     2               en:fructose
# 6     2                en:glucose

答案 2 :(得分:2)

以下是答案,包括删除前缀:

library(tidyverse)

df %>% 
    mutate(ingredients = str_split(ingredients, ","),
           row_num = row_number()) %>% 
    unnest() %>% 
    mutate(ingredients = str_remove(ingredients, "^[^:]+(:)"))

#> # A tibble: 82 x 2
#>    row_num ingredients           
#>      <int> <chr>                 
#>  1       1 xylitol               
#>  2       2 water                 
#>  3       2 sugar                 
#>  4       2 glucose-fructose-syrup
#>  5       2 fructose              
#>  6       2 glucose               
#>  7       2 dioxyde-de-carbone    
#>  8       2 acid                  
#>  9       2 citric-acid           
#> 10       2 natural-flavouring    
#> # … with 72 more rows

答案 3 :(得分:2)

我们可以使用data.table

require(data.table)
setDT(df)[, lapply(.SD, function(x){
                        unlist(tstrsplit(x, ",", fixed=TRUE))}), 
          by = seq.int(nrow(df))]

或仅使用base

stack(setNames(strsplit(df$ingredients,','), seq.int(nrow(df))))

或使用splitstackshape软件包:

require(splitstackshape)

cSplit(cbind(seq.int(nrow(df)), df), "ingredients", ",", "long")

#>    seq.int(nrow(df))               ingredients
#> 1:                 1                en:xylitol
#> 2:                 2                  en:water
#> 3:                 2                  en:sugar
#> 4:                 2 en:glucose-fructose-syrup
#> 5:                 2               en:fructose
#> 6:                 2                en:glucose
#...# … with 76 more rows (manually trimmed the output)

答案 4 :(得分:1)

使用@akrun建议的split_rows函数,我将以下代码与正则表达式^[a-z]{2}:一起使用,这意味着我想在每个值的开头过滤前两个字符a-z和一列(:

df %>% 
  dplyr::mutate(group = row_number()) %>% 
  tidyr::separate_rows(ingredients, sep = ",", convert = TRUE) %>%
  dplyr::mutate(ingredients = str_remove(ingredients, pattern = "^[a-z]{2}:")) %>%
  dplyr::distinct(ingredients, .keep_all = TRUE)