我有一个像
这样的data.framemydata
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
信息(对应于不同列的参数值)集成到该过程中。有什么方法可以tidyverse
或data.table
的方式进行?
谢谢。
已更新:
@IceCreamToucan @akrun,谢谢你们。
我已经测试了gather
/ cast
和map2_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
....
答案 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_join
,transmute
根据该函数创建一个'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