dplyr在每列的突变分别带有几个参数的自定义函数

时间:2018-07-28 08:34:36

标签: r dplyr mutate

我想将以下功能应用于数据框的列:

ff <- function(w, epsi, df) {
  res <- w*(max(df, na.rm = T) - min(df, na.rm=T)+2*epsi)+min(df, na.rm = T) - epsi
  return(res)
}

应使用参数wepsi将函数应用于df的每一列。该函数必须取w的每个值,然后乘以df对应列的最大值减去df对应列的最小值,依此类推。

例如:

> w
# A tibble: 5 x 2
    A       B
  <dbl>   <dbl>
1 0.290  0.928  
2 0.917  0.929  
3 0.910  0.919  
4 0.243  0.908  
5 0.936  0.901  

df是:

> df
# A tibble: 10 x 2
   A     B
  <dbl> <dbl>
1 0.977 1.03 
2 1.04  1.15 
3 0.929 0.875
4 1.12  1.15 
5 0.913 1.05 
6 1.00  1.09 
7 0.972 1.03 
8 0.919 1.04 
9 0.935 0.973
10 1.08  1.17 

因此对于w的第一个元素0.290,该函数将0.290乘以df列中的A的最大值(1.12),依此类推。

如何将dplyr应用于w

我尝试过:

w_new = w %>%  mutate_each(ff(w,0.001, df))

但它不是一次只接受一列,而是尝试一次对所有列进行操作。

2 个答案:

答案 0 :(得分:2)

OP表示希望使用基于dplyr的解决方案来解决此问题,因此我想使用dplyr提供一个答案。

在这种情况下,我们需要在另一个表中查找对应的列(名称),那么最好不要依赖列的顺序,而要使用特定的列名称。使用quo_namequo函数可以访问dplyr::mutate_all函数范围内的列名。

使用dplyr::mutate_all的解决方案可以是:

# Re-wirte fucntion to accept the column name for df
ff <- function(x, epsi, colName) {
  res <- x*(max(df[,colName], na.rm = TRUE) - min(df[,colName], na.rm=TRUE) +
         2*epsi)+min(df[,colName], na.rm = TRUE) - epsi
  return(res)
}

library(dplyr)

# The corresponding column names is passed to ff using quo_name(quo(.))
w %>% mutate_all(funs(ff(., 0.001, quo_name(quo(.)) )))
#          A        B
# 1 0.972610 1.149616
# 2 1.103653 1.149913
# 3 1.102190 1.146943
# 4 0.962787 1.143676
# 5 1.107624 1.141597

数据:

w <- read.table(text = 
"A       B
1 0.290  0.928  
2 0.917  0.929  
3 0.910  0.919  
4 0.243  0.908  
5 0.936  0.901",
header = TRUE)


df <- read.table(text = 
"A     B
1 0.977 1.03 
2 1.04  1.15 
3 0.929 0.875
4 1.12  1.15 
5 0.913 1.05 
6 1.00  1.09 
7 0.972 1.03 
8 0.919 1.04 
9 0.935 0.973
10 1.08  1.17",
header = TRUE)

答案 1 :(得分:1)

这是使用mapply

的基本R解决方案
mapply(
    function(x, y, epsi = 0.001)
        x * (max(y, na.rm = T) - min(y, na.rm = T) + 2 * epsi) + min(y, na.rm = T) - epsi,
    w, df)
#            A        B
#[1,] 0.972610 1.149616
#[2,] 1.103653 1.149913
#[3,] 1.102190 1.146943
#[4,] 0.962787 1.143676
#[5,] 1.107624 1.141597

说明:mapply逐列将功能应用于wdf,并将结果简化为5x2 matrix

稍微重新定义ff,这可以写得更简洁

ff <- function(x, y, epsi = 0.001)
    x * (max(y, na.rm = T) - min(y, na.rm = T) + 2 * epsi) + min(y, na.rm = T) - epsi
mapply(ff, w, df)

或使用purrr::map2_df作为

w %>% map2_df(df, ff)
## A tibble: 5 x 2
#      A     B
#  <dbl> <dbl>
#1 0.973  1.15
#2 1.10   1.15
#3 1.10   1.15
#4 0.963  1.14
#5 1.11   1.14

更新

microbenchmarkmutate_all方法进行非常快速,肮脏的map2分析的结果看起来像这样:

res <- microbenchmark(
    map2 = {
        ff <- function(x, y, epsi = 0.001)
            x * (max(y, na.rm = T) - min(y, na.rm = T) + 2 * epsi) + min(y, na.rm = T) - epsi
        w %>% map2_df(df, ff)
    },
    mutate_all = {
        ff <- function(x, epsi, colName) {
            res <- x*(max(df[,colName], na.rm = TRUE) - min(df[,colName], na.rm=TRUE) +
         2*epsi)+min(df[,colName], na.rm = TRUE) - epsi
            return(res)
        }
        w %>% mutate_all(funs(ff(., 0.001, quo_name(quo(.)) )))
    }
)
res
#Unit: microseconds
#       expr      min        lq      mean    median        uq       max neval
#       map2  320.537  371.1365  495.7786  397.6755  449.4445  8599.661   100
# mutate_all 1916.788 1998.2105 2312.5878 2059.7650 2290.1415 11169.320   100

library(ggplot2)
autoplot(res)

enter image description here