dplyr :: mutate,其中包含从列名

时间:2018-04-23 09:08:23

标签: r dplyr mutate

我提到thisthis,这两个对我都不起作用,因为它们都是基于调用mutate的函数而这些函数可能是在循环中调用的,这就是我做不到。

我有df(可以通过以下代码复制:) [[注意:巧合的是,此处的所有"Y_****"列恰好具有相同的值,但请忽略它。主数据帧实际上很长,我这里只放了6行。 ]]

mainY <- structure(list(PolygonId = 0:5, Area = c(3.018892, 1.995702, 
2.277057, 1.176975, 1.983469, 4.533144), Perimeter = c(10.6415, 
8.6314, 9.2226, 6.1484, 10.2277, 12.0012), X0 = c(0.59, 0.654, 
0.51, 0.6, 0.622, 0.431), Y0 = c(1.4, 1.4, 1.4, 1.4, 1.4, 1.4
), phi = c(0.3, 0.3, 0.3, 0.3, 0.5, 0.3), J0 = c(0.49199, 0.33466, 
0.55057, 0.5076, 0.46434, 0.6574), h0 = c(1669.494, 1656.977, 
1683.435, 1660.62, 1670.445, 1707.416), mat0 = c(0.58, 0.74, 
0.39, 0.67, 0.47, 0.24), tc0 = c(0.4, 0.42, 0.37, 0.41, 0.38, 
0.35), z0 = c(0.8272, 0.8044, 0.744, 0.8505, 1.0288, 0.6703), 
    W0 = c(4764.9472, 3147.8891, 2859.4418, 1974.6163, 4127.504, 
    4670.4702), Y_a02 = c(1.4, 1.4, 1.4, 1.4, 1.4, 1.4), Y_a03 = c(1.4, 
    1.4, 1.4, 1.4, 1.4, 1.4), Y_a04 = c(1.4, 1.4, 1.4, 1.4, 1.4, 
    1.4), Y_b05 = c(1.4, 1.4, 1.4, 1.4, 1.4, 1.4), Y_b06 = c(1.4, 
    1.4, 1.4, 1.4, 1.4, 1.4)), .Names = c("PolygonId", "Area", 
"Perimeter", "X0", "Y0", "phi", "J0", "h0", "mat0", "tc0", "z0", 
"W0", "Y_a02", "Y_a03", "Y_a04", "Y_b05", "Y_b06"), row.names = c(NA, 
6L), class = "data.frame")

这就是它的样子:

enter image description here

Y_**** columns的实际数量超过20.当我决定增加更多数据时,它会增加。

我的代码如下:(解释在代码下面)

calc.z <- function(x, y, phi, j){
  round(x * y * (phi + sqrt(j)),4)
}
calc.W <- function(tc, h, z, area){
  round(tc * h * pi * sqrt(z^3) * area, 4)
}

我需要为每一行计算zW。上述函数显示了zW的公式。

通常我要做的是:

newdf<- dplyr::mutate(mainY,
       z_Y_a02  = calc.z(X0, Y_a02 , phi, J0), W_Y_a02  = calc.W(tc0, h0, z_Y_a02,  Area),
       z_Y_a03  = calc.z(X0, Y_a03 , phi, J0), W_Y_a03  = calc.W(tc0, h0, z_Y_a03,  Area))
# and so on 
# note here, for calculating all z_****, X0, phi, J0 are always used the same
# same for calculating W

但这很乏味,重复20多列等等。

对于我上面提到的例子,我编写了如下代码::

newdf<- dplyr::mutate_at(mainY,
                      .vars = c("Y_a02","Y_a03","Y_a04","Y_b05","Y_b06"),
                      .funs = calc.z("X0",.vars,"phi","J0")
                      )
# This did not work. I again changed like this:

newdf<- dplyr::mutate_at(mainY,
                         .vars = c("Y_a02","Y_a03","Y_a04","Y_b05","Y_b06"),
                         .funs = calc.z("X0",.vars,"phi","J0")
                          )
# This does not work as well.

以下是我期望的结果格式。 ((##代表一些数字。))

> newdf
  PolygonId     Area Perimeter    X0  Y0 phi      J0       h0 mat0  tc0     z0       W0 Y_a02 Y_a03 Y_a04 Y_b05 Y_b06   z_Y_a02   W_Y_a02   z_Y_a03   W_Y_a03   z_Y_a04   W_Y_a04   z_Y_b05   W_Y_b05   z_Y_b06   W_Y_b06
1         0 3.018892   10.6415 0.590 1.4 0.3 0.49199 1669.494 0.58 0.40 0.8272 4764.947   1.4   1.4   1.4   1.4   1.4      ##        ##         ##        ##       ##       ##        ##        ##         ##        ##
2         1 1.995702    8.6314 0.654 1.4 0.3 0.33466 1656.977 0.74 0.42 0.8044 3147.889   1.4   1.4   1.4   1.4   1.4      ##        ##         ##        ##       ##       ##        ##        ##         ##        ##
3         2 2.277057    9.2226 0.510 1.4 0.3 0.55057 1683.435 0.39 0.37 0.7440 2859.442   1.4   1.4   1.4   1.4   1.4      ##        ##         ##        ##       ##       ##        ##        ##         ##        ##
4         3 1.176975    6.1484 0.600 1.4 0.3 0.50760 1660.620 0.67 0.41 0.8505 1974.616   1.4   1.4   1.4   1.4   1.4      ##        ##         ##        ##       ##       ##        ##        ##         ##        ##
5         4 1.983469   10.2277 0.622 1.4 0.5 0.46434 1670.445 0.47 0.38 1.0288 4127.504   1.4   1.4   1.4   1.4   1.4      ##        ##         ##        ##       ##       ##        ##        ##         ##        ##
6         5 4.533144   12.0012 0.431 1.4 0.3 0.65740 1707.416 0.24 0.35 0.6703 4670.470   1.4   1.4   1.4   1.4   1.4      ##        ##         ##        ##       ##       ##        ##        ##         ##        ##

1 个答案:

答案 0 :(得分:2)

这应该有效:

library(tidyverse)
mainY %>%
  mutate_at(.vars = vars(Y_a02, Y_a03, Y_a04, Y_b05, Y_b06),
            .funs = funs(calc.z = calc.z(X0,.,phi,J0)))
#output

**  PolygonId     Area Perimeter    X0  Y0 phi      J0       h0 mat0  tc0     z0       W0 Y_a02 Y_a03 Y_a04
1         0 3.018892   10.6415 0.590 1.4 0.3 0.49199 1669.494 0.58 0.40 0.8272 4764.947   1.4   1.4   1.4
2         1 1.995702    8.6314 0.654 1.4 0.3 0.33466 1656.977 0.74 0.42 0.8044 3147.889   1.4   1.4   1.4
3         2 2.277057    9.2226 0.510 1.4 0.3 0.55057 1683.435 0.39 0.37 0.7440 2859.442   1.4   1.4   1.4
4         3 1.176975    6.1484 0.600 1.4 0.3 0.50760 1660.620 0.67 0.41 0.8505 1974.616   1.4   1.4   1.4
5         4 1.983469   10.2277 0.622 1.4 0.5 0.46434 1670.445 0.47 0.38 1.0288 4127.504   1.4   1.4   1.4
6         5 4.533144   12.0012 0.431 1.4 0.3 0.65740 1707.416 0.24 0.35 0.6703 4670.470   1.4   1.4   1.4
  Y_b05 Y_b06 Y_a02_calc.z Y_a03_calc.z Y_a04_calc.z Y_b05_calc.z Y_b06_calc.z
1   1.4   1.4       0.8272       0.8272       0.8272       0.8272       0.8272
2   1.4   1.4       0.8044       0.8044       0.8044       0.8044       0.8044
3   1.4   1.4       0.7440       0.7440       0.7440       0.7440       0.7440
4   1.4   1.4       0.8505       0.8505       0.8505       0.8505       0.8505
5   1.4   1.4       1.0288       1.0288       1.0288       1.0288       1.0288
6   1.4   1.4       0.6703       0.6703       0.6703       0.6703       0.6703

如果您只想将Y_b**列替换为结果:

mainY %>%
      mutate_at(.vars = vars(Y_a02, Y_a03, Y_a04, Y_b05, Y_b06),
                .funs = funs(calc.z(X0, ., phi, J0)))

而不是键入.vars中的所有列,您也可以执行以下操作:

colnames(mainY)[grep("Y_.\\d{2}$", colnames(mainY))]
如果非其他列以"^Y_"开头,则

"Y_"作为模式。

其中"Y_.\\d{2}$"依赖于相关示例,但可能需要更改您的真实表:

mainY %>%
  mutate_at(.vars = colnames(.)[grep("Y_.\\d{2}$", colnames(.))],
            .funs = funs(calc.z = calc.z(X0, ., phi, J0)))

编辑回答评论中的问题:

将计算出的calc.z值传递给calc.W的方法。所有列都将保留:

 mainY %>%
      mutate_at(.vars = colnames(.)[grep("Y_.\\d{2}$", colnames(.))],
                .funs = funs(calc.z = calc.z(X0, ., phi, J0))) %>%
      mutate_at(.vars = colnames(.)[grep("_calc.z$", colnames(.))],
                .funs = funs(calc.W = calc.z(tc0, h0, ., Area))

)