最近我偶然发现dplyr
的一种奇怪行为,如果有人提供一些见解,我会很高兴。
假设我有一个com列包含一些数值的数据。在一个简单的场景中,我想计算rowSums
。虽然有很多方法可以做,但这里有两个例子:
df <- data.frame(matrix(rnorm(20), 10, 2),
ids = paste("i", 1:20, sep = ""),
stringsAsFactors = FALSE)
# works
dplyr::select(df, - ids) %>% {rowSums(.)}
# does not work
# Error: invalid argument to unary operator
df %>%
dplyr::mutate(blubb = dplyr::select(df, - ids) %>% {rowSums(.)})
# does not work
# Error: invalid argument to unary operator
df %>%
dplyr::mutate(blubb = dplyr::select(., - ids) %>% {rowSums(.)})
# workaround:
tmp <- dplyr::select(df, - ids) %>% {rowSums(.)}
df %>%
dplyr::mutate(blubb = tmp)
# works
rowSums(dplyr::select(df, - ids))
# does not work
# Error: invalid argument to unary operator
df %>%
dplyr::mutate(blubb = rowSums(dplyr::select(df, - ids)))
# workaround
tmp <- rowSums(dplyr::select(df, - ids))
df %>%
dplyr::mutate(blubb = tmp)
首先,我并不真正理解导致错误的原因,其次我想知道如何以一种整洁的方式实现一些(可行)列的整洁计算。
修改的
问题mutate and rowSums exclude columns虽然相关,但侧重于使用rowSums进行计算。在这里,我渴望了解为什么上面的例子不起作用。它不是关于如何解决(参见解决方法),而是了解应用天真appraoch时会发生什么
答案 0 :(得分:15)
示例不起作用,因为您在select
中嵌套mutate
并使用裸变量名称。在这种情况下,select
正在尝试执行类似
> -df$ids
Error in -df$ids : invalid argument to unary operator
失败,因为你无法否定字符串(即-"i1"
或-"i2"
没有意义)。以下任何一种配方都有效:
df %>% mutate(blubb = rowSums(select_(., "X1", "X2")))
df %>% mutate(blubb = rowSums(select(., -3)))
或
df %>% mutate(blubb = rowSums(select_(., "-ids")))
由@Haboryme建议。
答案 1 :(得分:1)
添加到这个旧线程是因为我搜索了这个问题,然后意识到我在问错误的问题。另外,我在此问题和相关问题中发现了一些对实现此问题的正确方法的渴望。
这里的答案有些不直观,因为他们试图将dplyr话语与非“整洁”的数据一起使用。如果您想以dplyr的方式进行操作,请先使用gather()
使数据整洁,然后再使用summarise()
library(tidyverse)
df <- data.frame(matrix(rnorm(20), 10, 2),
ids = paste("i", 1:20, sep = ""),
stringsAsFactors = FALSE)
df %>% gather(key=Xn,value="value",-ids) %>%
group_by(ids) %>%
summarise(rowsum=sum(value))
#> # A tibble: 20 x 2
#> ids rowsum
#> <chr> <dbl>
#> 1 i1 0.942
#> 2 i10 -0.330
#> 3 i11 0.942
#> 4 i12 -0.721
#> 5 i13 2.50
#> 6 i14 -0.611
#> 7 i15 -0.799
#> 8 i16 1.84
#> 9 i17 -0.629
#> 10 i18 -1.39
#> 11 i19 1.44
#> 12 i2 -0.721
#> 13 i20 -0.330
#> 14 i3 2.50
#> 15 i4 -0.611
#> 16 i5 -0.799
#> 17 i6 1.84
#> 18 i7 -0.629
#> 19 i8 -1.39
#> 20 i9 1.44
如果在使用arrange()
无法对ID进行排序时,如果您关心ID的顺序,请首先将该列作为因素。
df %>%
mutate(ids=as_factor(ids)) %>%
gather(key=Xn,value="value",-ids) %>%
group_by(ids) %>%
summarise(rowsum=sum(value))
答案 2 :(得分:1)
select_
是deprecated。您可以使用:
library(dplyr)
df <- data.frame(matrix(rnorm(20), 10, 2),
ids = paste("i", 1:20, sep = ""),
stringsAsFactors = FALSE)
df %>%
mutate(blubb = rowSums(select(., .dots = c("X1", "X2"))))
# Or more generally:
desired_columns <- c("X1", "X2")
df %>%
mutate(blubb = rowSums(select(., .dots = all_of(desired_columns))))
答案 3 :(得分:0)
为什么要使用管道操作符?只需写一个表达式,如:
rowSums(df[,sapply(df, is.numeric)])
即。计算所有数字列上的rowsums,其优点是不需要指定ids
。
答案 4 :(得分:0)
如果要将结果保存为数据中的列,可以使用data.table语法,如下所示:
dt <- as.data.table(df)
dt[, x3 := rowSums(.SD, na.rm=T), .SDcols = which(sapply(dt, is.numeric))]