R中的条件数据框突变与magrittr和dplyr

Posted

技术标签:

【中文标题】R中的条件数据框突变与magrittr和dplyr【英文标题】:Conditional dataframe mutations in R with magrittr and dplyr 【发布时间】:2016-03-13 15:52:10 【问题描述】:

我想使用 magrittr 和 dplyr 的简洁性来根据其他列中的值在列子集中的行之间复制单个值。这是一个简单的例子;我想将这个想法应用到具有多个条件的大型数据集的许多列中。

取数据框df <- data.frame(a = 1:5, b = 6:10, x = 11:15, y = 16:20):

a   b   x   y

1   6   11  16
2   7   12  17
3   8   13  18
4   9   14  19
5   10  15  20

对于a = 5所在的行,我想将xy的值替换为b = 7所在行的值,给出:

a   b   x   y

1   6   11  16
2   7   12  17
3   8   13  18
4   9   14  19
5   10  12  17

此尝试失败:

foo <- function(x)ifelse(df$a == 5, df[df$b == 7, .(df$x)], x)
df %<>%  mutate_each(funs(foo), x, y)

我能得到的最接近的是:

bar <- function(x)ifelse(df$a == 5, df[df$b == 7, "x"], x)
df %<>%  mutate_each(funs(bar), x, y)

但这是不正确的,因为它将两个值都替换为来自x 的值,而不是分别替换为xy

感谢您的建议。

【问题讨论】:

%&lt;&gt;%%&gt;% 之间的区别是什么? x %&lt;&gt;% f 来自magrittr 包,相当于普通模式x &lt;- x %&gt;% f %&gt;% 也来自magrittr 包... @DavidArenburg %&gt;% 将仅在加载 dplyr 的情况下工作,而目前使用 CRAN 版本,使用 %&lt;&gt;% 需要加载 magrittr。没错,%&gt;% 来自 magrittrdplyr,但对于最终用户来说,知道要加载哪些包更相关! @antoine-sac 好吧,这就是你的意见,伙计。 【参考方案1】:

您可以使用mutate_eachreplace 来做到这一点:

df %>% mutate_each(funs(replace(., a==5, nth(., which(b==7)))), x, y)

输出:

  a  b  x  y
1 1  6 11 16
2 2  7 12 17
3 3  8 13 18
4 4  9 14 19
5 5 10 12 17

或者根据@docendodiscimus 的评论,它可以进一步缩短为(并且可能[ 也比which 更好):

df %>% mutate_each(funs(replace(., a==5, .[b==7])), x, y)

【讨论】:

谢谢,但我想将此方法应用于可能在其他地方定义的大量列,因此这将很快变得笨拙。 @PatrickHogan 我没有在你的问题中注意到这一点。我也许可以调整上面的代码。 更新了答案。现在我认为这应该符合您的需求。 不错的一个!可以缩短为df %&gt;% mutate_each(funs(replace(., a==5, .[b==7])), x, y) 啊,很好的改进@docendodiscimus 谢谢。我也加一下。【参考方案2】:

仅提及data.table 解决方案是:

require(data.table)
setDT(df)[a == 5, c("x", "y") := df[b == 7, .SD, .SDcols = c("x", "y")]]

> df
   a  b  x  y
1: 1  6 11 16
2: 2  7 12 17
3: 3  8 13 18
4: 4  9 14 19
5: 5 10 12 17

或者,您也可以使用:

cols <- c("x", "y")
setDT(df)[a == 5, (cols) := df[b == 7, .SD, .SDcols = cols]]
# or 
cols <- c("x", "y")
setDT(df)[a == 5, (cols) := df[b == 7, cols, with = FALSE]]

【讨论】:

DT &lt;- setDT(df) 几乎没有意义。因为df 现在也是一个 data.table 并且已通过引用更新。 @Arun:我完全同意。当我开始使用data.table 时,通过引用更新 的概念对我来说非常陌生。当问题要求dplyr 解决方案时,我认为我的答案更容易理解。 我明白了.. 那么最好使用 as.data.table 。还使用with=FALSE.SD + .SDcols 将有助于表明它很容易扩展到许多列。 @Arun:看看我的编辑。我不明白您使用with=FALSE 是什么意思。随意编辑。 我冒昧地改进了您的答案。希望你不要介意。【参考方案3】:

如果您的主要要求是在更长的 dplyr 管道中应用该函数,您可以执行以下示例:

foo <- function(df, cols = c("x", "y")) 
  df[df$a == 5, cols] <- df[df$b == 7, cols]
  df


df %>% ... %>% foo(c("x", "y")) %>% ... 
#  a  b  x  y
#1 1  6 11 16
#2 2  7 12 17
#3 3  8 13 18
#4 4  9 14 19
#5 5 10 12 17

【讨论】:

以上是关于R中的条件数据框突变与magrittr和dplyr的主要内容,如果未能解决你的问题,请参考以下文章

在 R dplyr 中过滤具有多个条件名称匹配的数据框

R:在自编写的包中使用magrittr管道运算符

R:dplyr 有条件地汇总并重新编码列中的值

R中的标准评估和非标准评估

%.% (dplyr) 和 %>% (magrittr) 之间的差异

R:在自写包中使用 magrittr 管道运算符