在具有多个参数的data.frame(data.table)中使用多个列的功能

时间:2019-07-18 16:15:13

标签: r dplyr data.table

我有一个像

这样的data.frame mydata
index     x     y     z
<int> <int> <int> <int>
    1     1     2     3
    2     3     4     5
    3     3     4     9
    ....

我想做的是在(x,y,z)列上应用相同的函数fun(input, par1, par2, par3),将其修改为新值(替换原始列)

问题在于,对于任一列,它都有自己的参数集,即par1, par2, par3,该参数是在另一个表mypar中设置的

 name  par1  par2  par3
<chr> <dbl> <dbl> <dbl>
    x   0.1   0.2   0.1 
    y   0.5   0.1   0.7
    z   0.3   0.9   0.5

如果x, y, z的所有列的参数都相同,例如[0.1, 0.2, 0.3],则可以使用dplyr mutate_at或data.table .SDcol

 names = c("x", "y", "z")
 mydata %>%  mutate_at(names, ~fun(., 0.1, 0.2, 0.3))

 mydata.dt[, (names) := lapply(.SD, fun, 0.1, 0.2, 0.3), .SDcol = names]

不是,我想将mypar信息(对应于不同列的参数值)集成到该过程中。有什么方法可以tidyversedata.table的方式进行?

谢谢。

已更新:

@IceCreamToucan @akrun,谢谢你们。

我已经测试了gather / castmap2_df方法。

我发现了一些有趣的东西。

在我的情况下,fun()接受一个长度为N的向量,并返回一个长度为N的向量,它是一个window函数。

例如,如果我将答案中的函数更改为fun1 <- function(x, p1, p2, p3) x/cumsum(x) + p1/p2 -p3,则只有map2_df给出正确的结果。

更复杂的是,通过使用map2_df,我想在最终结果中保留x, y, z旁边的其他列,并且可能还需要对组进行处理。如原始数据为: (最终结果将包含所有列,但更新后的x, y, z

index  group      x     y     z  others
<int>  <fct>  <int> <int> <int>   <dbl>
    1      a      1     2     3     1.2
    2      a      3     4     5     3.4
    3      a      3     4     9     4.5
    1      b      5     2     1     5.5
    2      b      4     3     9     3.9
    3      b      2     9     1     2.9
    .... 

3 个答案:

答案 0 :(得分:3)

如果将mydata转换为长格式,则可以与mypar合并以将参数添加为列。然后,您可以Map在结果数据表的列上,因为现在将参数作为列。之后,您可以使用dcast将数据放回宽格式。

library(data.table)
setDT(mypar)
setDT(mydata)
setnames(mypar, 'name', 'variable')

long_out <- 
  merge(melt(mydata, 1), mypar, by = 'variable')[,
    fun_out := Map(fun, value, par1, par2, par3)]

dcast(long_out, index ~ variable, value.var = 'fun_out')
#    index   x   y        z
# 1:     1 1.4 6.3 2.833333
# 2:     2 3.4 8.3 4.833333
# 3:     3 3.4 8.3 8.833333

使用的数据

fun <- function(x, p1, p2, p3) x + p1/p2 -p3

mypar <- fread('
 name  par1  par2  par3
    x   0.1   0.2   0.1 
    y   0.5   0.1   0.7
    z   0.3   0.9   0.5
')

mydata <- fread('
index     x     y     z
    1     1     2     3
    2     3     4     5
    3     3     4     9
')

答案 1 :(得分:2)

我们将gather的原始数据集转换为'long'格式,然后对'mypar'进行left_jointransmute根据该函数创建一个'newcol',然后{ {1}}转换为“宽”格式

spread

或使用f1 <- function(x, p1, p2, p3) x + p1/p2 - p3 library(tidyverse) gather(mydata, name, val, -index) %>% left_join(mypar) %>% transmute(index, name, newcol = f1(x = val, p1 = par1, p2 = par2, p3 = par3)) %>% spread(name, newcol) # index x y z #1 1 1.4 6.3 2.833333 #2 2 3.4 8.3 4.833333 #3 3 3.4 8.3 8.833333

map

数据

map2_df(mydata %>%
            select(mypar$name),
       map(mypar$name, ~  mypar %>%
            slice(match(.x, name)) %>% 
            select(-name)), ~ f1(.x, .y[[1]], .y[[2]], .y[[3]]))

答案 2 :(得分:1)

如何根据需要检索参数?

setkey(mypar, name)
cols <- c('x','y','z')
mydata[, paste0(cols, "_new") := lapply(cols, 
        function(x) fun1(.SD[[x]], mypar[x]$par1, mypar[x]$par2, mypar[x]$par3)), 
    .SDcols=cols]

输出:

   index x y z     x_new    y_new     z_new
1:     1 1 2 3 1.4000000 5.300000 0.8333333
2:     2 3 4 5 1.1500000 4.966667 0.4583333
3:     3 3 4 9 0.8285714 4.700000 0.3627451

数据:

library(data.table)
mypar <- fread("name  par1  par2  par3
x   0.1   0.2   0.1 
y   0.5   0.1   0.7
z   0.3   0.9   0.5")

mydata <- fread("index     x     y     z
1     1     2     3
2     3     4     5
3     3     4     9")

fun1 <- function(x, p1, p2, p3) x/cumsum(x) + p1/p2 -p3