在R中的多个配对变量上应用具有多个参数的函数

时间:2017-01-06 05:09:07

标签: r function lapply data-cleaning mapply

我有一个这样的函数,我用来清理数据并正常工作。

my_fun <- function (x, y){
    y <- ifelse(str_detect(x, "-*\\d+\\.*\\d*"), 
        as.numeric(str_extract(x, "-*\\d+\\.*\\d*")),
        as.numeric(y))
}

它需要在错误的列中输入的数字并将它们重新分配到正确的列。它用于清理y变量:

df$y <- my_fun(x, y)

我有很多列/变量(超过10个),它们以相同的格式配对,就像这样

x_vars <- c("x_1", "x_2", "x_3", "x_4", "x_5", "x_6")
y_vars <- c("y_1", "y_2", "y_3", "y_4", "y_5", "y_6")

我的问题是。有没有办法在我的数据集中需要以相同方式清理的所有变量中应用此函数?我可以在其他情况下轻松地执行此操作,其中我的数据清理功能只有一个参数使用lapply但在这种情况下我正在努力。

我已经尝试mapply但是无法让它工作,这可能是因为我在R中仍然是一个新手。任何建议都会非常感激。

2 个答案:

答案 0 :(得分:2)

B / c我一直认为知道如何在基地R中做这些事情很好,我已经有了如何使用mapply()lapply()的例子。

## first generate some data
df <- data.frame(replicate(12, rnorm(5)))
my_fun <- function (x, y){
    ifelse(stringr::str_detect(x, "-*\\d+\\.*\\d*"),
        as.numeric(stringr::str_extract(x, "-*\\d+\\.*\\d*")),
        as.numeric(y))
}
df <- data.frame(replicate(12, rnorm(3)))
df[, sample(1:6, 3)] <- letters[1:3]
## not function of interest, but good mapply() example
names(df) <- c(
               mapply(paste0, rep("x_", 6), 1:6),
               mapply(paste0, rep("y_", 6), 1:6))

## print data with problem variables (cols with letters)
#df
#         x_1 x_2 x_3 x_4        x_5        x_6       y_1
#1 -0.2184993   a   a   a -0.1587070 0.37795630 0.6162796
#2  0.8511775   b   b   b  0.5743287 0.15291219 1.0594502
#3  0.8183208   c   c   c  1.8923812 0.07156925 0.8613535
#         y_2        y_3        y_4       y_5        y_6
#1  0.3240393 -1.1084067  0.5233168 0.3712705 -0.3911407
#2  0.3044824 -0.2286032 -1.0019870 1.2156441  0.4010163
#3 -1.0920677  1.3408504  1.3339865 0.3270800 -0.8416253



## if you wrote a for loop, it'd look like this maybe
out <- vector("list", 6)
for (i in seq_len(6)) {
    out[[i]] <- my_fun(df[, i], df[, i + 6])
}

## same construction can be used with lapply
dfy <- lapply(seq_len(6), function(i)
    my_fun(df[, 1:6][[i]],
           df[, 7:12][[i]]))
matrix(unlist(dfy), 5, 6)
#           [,1]       [,2]       [,3]        [,4]       [,5]
#[1,] -0.2184993 -1.0920677 -1.0019870  0.37795630  0.8183208
#[2,]  0.8511775 -1.1084067  1.3339865  0.15291219  0.3240393
#[3,]  0.8183208 -0.2286032 -0.1587070  0.07156925  0.3044824
#[4,]  0.3240393  1.3408504  0.5743287 -0.21849928 -1.0920677
#[5,]  0.3044824  0.5233168  1.8923812  0.85117750 -1.1084067
#           [,6]
#[1,] -0.2286032
#[2,]  1.3408504
#[3,]  0.5233168
#[4,] -1.0019870
#[5,]  1.3339865
  

警告讯息:       在矩阵中(unlist(dfy),5,6):         数据长度[18]不是行数的子数倍或倍数[5]

## and mapply makes this even easier
mapply(my_fun, df[, 1:6], df[, 7:12])
#            x_1        x_2        x_3        x_4        x_5
#[1,] -0.2184993  0.3240393 -1.1084067  0.5233168 -0.1587070
#[2,]  0.8511775  0.3044824 -0.2286032 -1.0019870  0.5743287
#[3,]  0.8183208 -1.0920677  1.3408504  1.3339865  1.8923812
#            x_6
#[1,] 0.37795630
#[2,] 0.15291219
#[3,] 0.07156925

答案 1 :(得分:0)

我们可以使用mapply/Map。我们需要通过传递&#39; x_vars&#39;&#39; y_vars&#39;来提取基于列名称的列。作为Map的参数,在提取的my_fun上应用vector,并将其分配回&#39; y_vars&#39;在原始数据集中

df[y_vars] <- Map(function(x,y) my_fun(df[,x], df[,y]), x_vars, y_vars)

或者这也可以写成

df[y_vars] <- Map(my_fun, df[x_vars], df[y_vars])

注意:在这里,我们假设&#39; x_vars&#39;中的所有元素都是和&#39; y_vars&#39;是原始数据集中的列。我们还要声明,使用Map比将其重新整形为长时间更快更有效率,然后进行一些转换。

要提供不同的方法,我们可以使用melt

中的data.table
library(data.table)
dM <- melt(setDT(df), measure = list(x_vars, y_vars))[,
               value3 := my_fun(value1, value2), variable]

然后,再一次,我们需要dcast它回到广泛的&#39;格式。所以,这需要更多的步骤,而且不是那么容易

setnames(dcast(dM, rowid(variable)~variable, 
  value.var = c("value1", "value3"))[,variable := NULL][], c(x_vars, y_vars))[]

数据

set.seed(24)
df <- as.data.frame(matrix(sample(c(1:5, "something 10.5",
   "this -4.5", "what -5.2 value?"),
          12*10, replace=TRUE), ncol=12, dimnames = 
     list(NULL, c(x_vars, y_vars))), stringsAsFactors=FALSE)