【问题标题】:Create multiple variables based on difference and ratios of existing variables in R根据R中现有变量的差异和比率创建多个变量
【发布时间】:2021-08-29 17:47:38
【问题描述】:

我想在我的数据集中一次创建现有变量的多个差异和比率(在这种特殊情况下,但这可能是任何东西)。这个想法是创建我想要使用的变量列表(分别是根,因为它简化了很多任务),并使用它进一步使用 data.table 方法在一行中创建所有内容。

这是一个带有两个根的简单示例,以显示我正在寻找的内容。我们的想法是执行以下操作

setDT(dataset)[ , root1.xy_diff := root1.x - root1.y]
setDT(dataset)[ , root1.xy_ratio := root1.x / root1.y]

setDT(dataset)[ , root2.xy_diff := root2.x - root2.y]
setDT(dataset)[ , root2.xy_ratio := root2.x / root2.y]

我想做得很好,使用一行,而不是每次使用新根复制粘贴相同的行。我可以为 10 个变量做到这一点,但不是数千个。这不是很聪明。

如上所示,我以这样一种方式准备了数据集,即我想要计算差异/比率的变量始终具有相同的根。根据我在网上可以找到的内容,我正在考虑执行以下操作(使用相同的根 - 差异是值 x 和值 y 之间的差异,比率是 x 和 y 之间的比率):

roots <- c("root1","root2")
roots.x <- paste0(roots,".x")
roots.y <- paste0(roots,".y")
names <- c(paste0(roots,".xy_diff"), paste0(roots,".xy_ratio"))

dataset[ , (names) := list(difference(), ratio())]

or

dataset[ , c(paste0(roots,".xy_diff"), paste0(roots,".xy_ratio")) := lapply(.SD, list_of_functions), .SDcols=roots]

问题是,无论我尝试什么,都没有效果……我真的不知道应该怎么写。

如有必要,我可以添加一些数据。谢谢

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    可能有更优雅的解决方案,但这可行:

    library("data.table")
    dataset <- data.table(root1.x = 1:3, root1.y = 4:2, root2.x = 5:7, root2.y = 9:7)
    difference <- function(root) lapply(root, function(z) paste0("get('", z, ".x') - get('", z, ".y')"))
    ratio <- function(root) lapply(root, function(z) paste0("get('", z, ".x') / get('", z, ".y')"))
    roots <- c("root1","root2")
    
    dataset[ , c(paste0(roots,".xy_diff"), paste0(roots,".xy_ratio")) := 
               lapply(c(difference(roots), ratio(roots)), function(x) eval(parse(text = x)))]
    

    这给出了:

    dataset[]
       root1.x root1.y root2.x root2.y root1.xy_diff root2.xy_diff root1.xy_ratio root2.xy_ratio
    1:       1       4       5       9            -3            -4      0.2500000      0.5555556
    2:       2       3       6       8            -1            -2      0.6666667      0.7500000
    3:       3       2       7       7             1             0      1.5000000      1.0000000
    

    【讨论】:

    • 谢谢,这行得通。我仍然有一个问题,因为我想为大约 5000 个变量而不是 2 个变量运行它。我收到以下警告:警告消息:在 [.data.table(setDT(Final), , :=(c( paste0(vars, ".xy_diff"), : truelength (30854) is greater than 10,000 items over-allocated (length = 10854). 查看 ?truelength。如果您没有将 datatable.alloccol 选项设置得很大,请报告给data.table 问题跟踪器,包括 sessionInfo() 的结果。有什么线索吗?
    【解决方案2】:

    您可以使数据变长,按组执行计算,然后再次使数据变宽:

    library("data.table")
    dataset <- data.table(id = 1:3, root1.x = 1:3, root1.y = 4:2, root2.x = 5:7, root2.y = 9:7)
    dtlong = melt(dataset,id.vars = "id",  measure.vars = patterns("root"), value.name = "root", variable.name = "variable")
    dtlong[, c("varname", "ind"):=tstrsplit(variable, "\\.")]
    dtlong[, `:=`(diff = root[ind=="x"] - root[ind=="y"],
                  ratio = root[ind=="x"]/root[ind=="y"])
           , by = .(varname, id)]
    dt_wide = dcast(dtlong, id~varname + ind, value.var = c("root", "diff", "ratio"))
    

    给出:

       id root_root1_x root_root1_y root_root2_x root_root2_y diff_root1_x diff_root1_y diff_root2_x diff_root2_y ratio_root1_x ratio_root1_y ratio_root2_x ratio_root2_y
    1:  1            1            4            5            9           -3           -3           -4           -4     0.2500000     0.2500000     0.5555556     0.5555556
    2:  2            2            3            6            8           -1           -1           -2           -2     0.6666667     0.6666667     0.7500000     0.7500000
    3:  3            3            2            7            7            1            1            0            0     1.5000000     1.5000000     1.0000000     1.0000000
    

    【讨论】:

    • 感谢您的解决方案。最后,我选择将数据拆分到多个表中,进行计算并返回。我认为这比转置两次并不得不考虑 id 和度量值更容易。
    猜你喜欢
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-07
    • 2018-07-31
    • 1970-01-01
    • 2015-03-12
    相关资源
    最近更新 更多