【问题标题】:Adding multiple columns in a dplyr mutate call在 dplyr mutate 调用中添加多列
【发布时间】:2014-09-16 03:54:51
【问题描述】:

我有一个带有点分隔字符列的数据框:

> set.seed(310366)
> tst = data.frame(x=1:10,y=paste(sample(c("FOO","BAR","BAZ"),10,TRUE),".",sample(c("foo","bar","baz"),10,TRUE),sep=""))
> tst
    x       y
1   1 BAR.baz
2   2 FOO.foo
3   3 BAZ.baz
4   4 BAZ.foo
5   5 BAZ.bar
6   6 FOO.baz
7   7 BAR.bar
8   8 BAZ.baz

我想将该列拆分为两个新列,其中包含点两侧的部分。 str_split_fixed from package stringr 可以很好地完成这项工作。我所有的价值观绝对是由一个点分隔的两部分,所以我可以这样做:

> require(stringr)
> str_split_fixed(tst$y,"\\.",2)
      [,1]  [,2] 
 [1,] "BAR" "baz"
 [2,] "FOO" "foo"
 [3,] "BAZ" "baz"
 [4,] "BAZ" "foo"
 [5,] "BAZ" "bar"
 [6,] "FOO" "baz"
 [7,] "BAR" "bar"

现在我可以将 cbind 发送到我的数据框,但我想我会弄清楚如何在 dplyr 管道中执行此操作。首先我认为mutate 可以一次性完成:

> tst %.% mutate(parts=str_split_fixed(y,"\\.",2))
Error: wrong result size (20), expected 10 or 1

我可以让mutate 分两次完成:

> tst %.% mutate(part1=str_split_fixed(y,"\\.",2)[,1], part2=str_split_fixed(y,"\\.",2)[,2])
    x       y part1 part2
1   1 BAR.baz   BAR   baz
2   2 FOO.foo   FOO   foo
3   3 BAZ.baz   BAZ   baz
4   4 BAZ.foo   BAZ   foo
5   5 BAZ.bar   BAZ   bar
6   6 FOO.baz   FOO   baz

但那会运行字符串拆分两次。

到目前为止,我能以dplyr 的方式做到的“最好”是这样的(我只是在写这个问题时才发现......):

> tst %.% do(cbind(.,data.frame(parts=str_split_fixed(.$y,"\\.",2))))
    x       y parts.1 parts.2
1   1 BAR.baz     BAR     baz
2   2 FOO.foo     FOO     foo
3   3 BAZ.baz     BAZ     baz
4   4 BAZ.foo     BAZ     foo
5   5 BAZ.bar     BAZ     bar

这还不错,但在 R 中失去了很多管道事物的可读性。有没有我错过的使用 mutate 的简单方法?

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    您可以将tidyr 中的separate()dplyr 结合使用:

    tst %>% separate(y, c("y1", "y2"), sep = "\\.", remove=FALSE)
    
        x       y  y1  y2
    1   1 BAR.baz BAR baz
    2   2 FOO.foo FOO foo
    3   3 BAZ.baz BAZ baz
    4   4 BAZ.foo BAZ foo
    5   5 BAZ.bar BAZ bar
    6   6 FOO.baz FOO baz
    7   7 BAR.bar BAR bar
    8   8 BAZ.baz BAZ baz
    9   9 FOO.bar FOO bar
    10 10 BAR.foo BAR foo
    

    设置 remove=TRUE 将删除 y 列

    【讨论】:

    • 不幸的是,separate 在拆分后的结果列数多于指定列时会出错。从这个意义上说,它更像str_split 而不是str_split_fixed。见this feature request。但仍然是一个非常有用的答案,谢谢。
    • 使用extra = "merge"参数可以控制
    • 这是一个很好的答案!谢谢
    • 请注意,默认情况下,任何非字母数字都将用作分隔符,因此在这种情况下不需要设置sep
    【解决方案2】:

    This answer 也适用于此;以下方法既是 tidyverse-idiomatic 又是 more performant than separate()(截至 2020 年):

    set.seed(310366)
    tst = data.frame(x=1:10,y=paste(sample(c("FOO","BAR","BAZ"),10,TRUE),".",sample(c("foo","bar","baz"),10,TRUE),sep=""))
    
    library(dplyr)
    library(purrr)
    
    tst %>% 
      mutate(tmp_chunks = stringr::str_split(y, fixed("."),  n = 2)) %>%
      mutate(y1 = map_chr(tmp_chunks, 1),
             y2 = map_chr(tmp_chunks, 2)) %>%
      select(-tmp_chunks)
    

    ... 或者如果你不想y在拆分后,你可以把最后一行改成

      select(-tmp_chunks, -y)
    

    【讨论】:

      猜你喜欢
      • 2015-06-19
      • 2017-02-01
      • 1970-01-01
      • 2014-03-12
      • 1970-01-01
      • 2018-08-17
      • 2018-10-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多