如何使用 pipe/dplyr 为数据框的算术运算编写可读代码?
How to write a readable code for arithmetic operations on data frame using pipe/dplyr?
我想从我的整个数据集中减去一个值,同时从该操作中排除第一列。虽然有很多方法可以做到这一点,但我正在寻找一个非常易读的代码。
我从 magrittr
包中遇到 subtract()
,但我无法以合理的方式将其合并到管道中。
我的数据
set.seed(12)
df <- data.frame(replicate(10,sample(1:100,10,rep=TRUE)))
df[1] <- 1:10
colnames(df) <- c("ID", "A", "B", "C", "D", "E", "F", "G", "H", "I")
> df
# ID A B C D E F G H I
# 1 1 91 57 26 91 83 73 14 75 16
# 2 2 82 72 32 37 18 52 80 22 59
# 3 3 82 43 84 87 85 56 74 67 38
# 4 4 38 46 20 48 55 53 66 12 18
# 5 5 90 30 64 71 58 39 12 5 66
# 6 6 48 37 19 27 88 28 42 76 83
# 7 7 13 34 84 77 13 40 40 67 10
# 8 8 56 39 4 84 32 59 37 5 50
# 9 9 68 78 13 91 40 15 80 86 79
# 10 10 24 71 77 5 88 7 5 42 6
尝试从整个数据集中减去 5,第一列除外
library(magrittr)
library(dplyr)
## first attempt
df %>%
mutate_at(vars(-ID), funs(subtract(5)))
# ID A B C D E F G H I ## while first column remains intact,
# 1 1 -5 -5 -5 -5 -5 -5 -5 -5 -5 ## the rest just gets assigned with -5.
# 2 2 -5 -5 -5 -5 -5 -5 -5 -5 -5 ## not good.
# 3 3 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 4 4 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 5 5 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 6 6 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 7 7 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 8 8 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 9 9 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 10 10 -5 -5 -5 -5 -5 -5 -5 -5 -5
## second attempt
df %>%
subtract(5)
# ID A B C D E F G H I ## subtracts correctly, simple and sweet.
# 1 -4 86 52 21 86 78 68 9 70 11 ## however, there's no specification to
# 2 -3 77 67 27 32 13 47 75 17 54 ## skip the first column.
# 3 -2 77 38 79 82 80 51 69 62 33
# 4 -1 33 41 15 43 50 48 61 7 13
# 5 0 85 25 59 66 53 34 7 0 61
# 6 1 43 32 14 22 83 23 37 71 78
# 7 2 8 29 79 72 8 35 35 62 5
# 8 3 51 34 -1 79 27 54 32 0 45
# 9 4 63 73 8 86 35 10 75 81 74
# 10 5 19 66 72 0 83 2 0 37 1
## third attempt
b2i_minus_five <- df[, -1] -5
cbind(df[1], b2i_minus_five)
# ID A B C D E F G H I ## gets the job done, but ugly code,
# 1 1 86 52 21 86 78 68 9 70 11 ## at least in my opinion.
# 2 2 77 67 27 32 13 47 75 17 54
# 3 3 77 38 79 82 80 51 69 62 33
# 4 4 33 41 15 43 50 48 61 7 13
# 5 5 85 25 59 66 53 34 7 0 61
# 6 6 43 32 14 22 83 23 37 71 78
# 7 7 8 29 79 72 8 35 35 62 5
# 8 8 51 34 -1 79 27 54 32 0 45
# 9 9 63 73 8 86 35 10 75 81 74
# 10 10 19 66 72 0 83 2 0 37 1
有没有办法本着第二次尝试的精神完成这项工作,希望只是增加一点点接触?
同样,这里的动机是写一个简单明了的代码,这也是我坚持使用subtract()
而不是-5
的原因。
谢谢!
我认为问题在于您调用 subtract() 的方式。无论如何,最新版本的 dplyr
0.8.0 有一种处理这些调用的新方法,用 list()
而不是 funs()
。使用新版本,您将获得您想要获得的东西:
set.seed(12)
df <- data.frame(replicate(10,sample(1:100,10,rep=TRUE)))
df[1] <- 1:10
colnames(df) <- c("ID", "A", "B", "C", "D", "E", "F", "G", "H", "I")
library(magrittr)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
packageVersion("dplyr")
#> [1] '0.8.3'
## first attempt
df %>%
mutate_at(vars(-ID), list(~subtract(., 5)))
#> ID A B C D E F G H I
#> 1 1 86 52 21 86 78 68 9 70 11
#> 2 2 77 67 27 32 13 47 75 17 54
#> 3 3 77 38 79 82 80 51 69 62 33
#> 4 4 33 41 15 43 50 48 61 7 13
#> 5 5 85 25 59 66 53 34 7 0 61
#> 6 6 43 32 14 22 83 23 37 71 78
#> 7 7 8 29 79 72 8 35 35 62 5
#> 8 8 51 34 -1 79 27 54 32 0 45
#> 9 9 63 73 8 86 35 10 75 81 74
#> 10 10 19 66 72 0 83 2 0 37 1
我想从我的整个数据集中减去一个值,同时从该操作中排除第一列。虽然有很多方法可以做到这一点,但我正在寻找一个非常易读的代码。
我从 magrittr
包中遇到 subtract()
,但我无法以合理的方式将其合并到管道中。
我的数据
set.seed(12)
df <- data.frame(replicate(10,sample(1:100,10,rep=TRUE)))
df[1] <- 1:10
colnames(df) <- c("ID", "A", "B", "C", "D", "E", "F", "G", "H", "I")
> df
# ID A B C D E F G H I
# 1 1 91 57 26 91 83 73 14 75 16
# 2 2 82 72 32 37 18 52 80 22 59
# 3 3 82 43 84 87 85 56 74 67 38
# 4 4 38 46 20 48 55 53 66 12 18
# 5 5 90 30 64 71 58 39 12 5 66
# 6 6 48 37 19 27 88 28 42 76 83
# 7 7 13 34 84 77 13 40 40 67 10
# 8 8 56 39 4 84 32 59 37 5 50
# 9 9 68 78 13 91 40 15 80 86 79
# 10 10 24 71 77 5 88 7 5 42 6
尝试从整个数据集中减去 5,第一列除外
library(magrittr)
library(dplyr)
## first attempt
df %>%
mutate_at(vars(-ID), funs(subtract(5)))
# ID A B C D E F G H I ## while first column remains intact,
# 1 1 -5 -5 -5 -5 -5 -5 -5 -5 -5 ## the rest just gets assigned with -5.
# 2 2 -5 -5 -5 -5 -5 -5 -5 -5 -5 ## not good.
# 3 3 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 4 4 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 5 5 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 6 6 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 7 7 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 8 8 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 9 9 -5 -5 -5 -5 -5 -5 -5 -5 -5
# 10 10 -5 -5 -5 -5 -5 -5 -5 -5 -5
## second attempt
df %>%
subtract(5)
# ID A B C D E F G H I ## subtracts correctly, simple and sweet.
# 1 -4 86 52 21 86 78 68 9 70 11 ## however, there's no specification to
# 2 -3 77 67 27 32 13 47 75 17 54 ## skip the first column.
# 3 -2 77 38 79 82 80 51 69 62 33
# 4 -1 33 41 15 43 50 48 61 7 13
# 5 0 85 25 59 66 53 34 7 0 61
# 6 1 43 32 14 22 83 23 37 71 78
# 7 2 8 29 79 72 8 35 35 62 5
# 8 3 51 34 -1 79 27 54 32 0 45
# 9 4 63 73 8 86 35 10 75 81 74
# 10 5 19 66 72 0 83 2 0 37 1
## third attempt
b2i_minus_five <- df[, -1] -5
cbind(df[1], b2i_minus_five)
# ID A B C D E F G H I ## gets the job done, but ugly code,
# 1 1 86 52 21 86 78 68 9 70 11 ## at least in my opinion.
# 2 2 77 67 27 32 13 47 75 17 54
# 3 3 77 38 79 82 80 51 69 62 33
# 4 4 33 41 15 43 50 48 61 7 13
# 5 5 85 25 59 66 53 34 7 0 61
# 6 6 43 32 14 22 83 23 37 71 78
# 7 7 8 29 79 72 8 35 35 62 5
# 8 8 51 34 -1 79 27 54 32 0 45
# 9 9 63 73 8 86 35 10 75 81 74
# 10 10 19 66 72 0 83 2 0 37 1
有没有办法本着第二次尝试的精神完成这项工作,希望只是增加一点点接触?
同样,这里的动机是写一个简单明了的代码,这也是我坚持使用subtract()
而不是-5
的原因。
谢谢!
我认为问题在于您调用 subtract() 的方式。无论如何,最新版本的 dplyr
0.8.0 有一种处理这些调用的新方法,用 list()
而不是 funs()
。使用新版本,您将获得您想要获得的东西:
set.seed(12)
df <- data.frame(replicate(10,sample(1:100,10,rep=TRUE)))
df[1] <- 1:10
colnames(df) <- c("ID", "A", "B", "C", "D", "E", "F", "G", "H", "I")
library(magrittr)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
packageVersion("dplyr")
#> [1] '0.8.3'
## first attempt
df %>%
mutate_at(vars(-ID), list(~subtract(., 5)))
#> ID A B C D E F G H I
#> 1 1 86 52 21 86 78 68 9 70 11
#> 2 2 77 67 27 32 13 47 75 17 54
#> 3 3 77 38 79 82 80 51 69 62 33
#> 4 4 33 41 15 43 50 48 61 7 13
#> 5 5 85 25 59 66 53 34 7 0 61
#> 6 6 43 32 14 22 83 23 37 71 78
#> 7 7 8 29 79 72 8 35 35 62 5
#> 8 8 51 34 -1 79 27 54 32 0 45
#> 9 9 63 73 8 86 35 10 75 81 74
#> 10 10 19 66 72 0 83 2 0 37 1