【问题标题】:Using lapply to create new columns based on old columns使用 lapply 基于旧列创建新列
【发布时间】:2020-09-12 04:45:25
【问题描述】:

我的数据如下:

DF <- structure(list(No_Adjusted_Gross_Income = c(183454, 241199, 249506
), NoR_from_1_to_5000 = c(1035373, 4272260, 1124098), NoR_from_5000_to_10000 = c(319540, 
4826042, 1959866)), row.names = c(NA, -3L), class = c("data.table", 
"data.frame"))
val <- c(2500.5, 7500)
vn <- c("AGI_from_1_to_5000", "AGI_from_5000_to_10000")

   No_Adjusted_Gross_Income NoR_from_1_to_5000 NoR_from_5000_to_10000
1:                   183454            1035373                 319540
2:                   241199            4272260                4826042
3:                   249506            1124098                1959866

我想创建新列,基于第 2 列和第 3 列,乘以 val 中的值,使用 vn 中的名称。我尝试这样做:

DF[,2:3] <- lapply(DF[,2:3], vn := val*DF[,2:3])

但这不起作用..

期望的输出:

DF <- setDT(DF)[, vn[1]:=val[1]*DF[,2]]
DF <- setDT(DF)[, vn[2]:=val[2]*DF[,3]]

DFout <- structure(list(No_Adjusted_Gross_Income = c(183454, 241199, 249506
), NoR_from_1_to_5000 = c(1035373, 4272260, 1124098), NoR_from_5000_to_10000 = c(319540, 
4826042, 1959866), AGI_from_1_to_5000 = c(2588950186.5, 10682786130, 
2810807049), AGI_from_5000_to_10000 = c(2396550000, 36195315000, 
14698995000)), row.names = c(NA, -3L), class = c("data.table", 
"data.frame"))

   No_Adjusted_Gross_Income NoR_from_1_to_5000 NoR_from_5000_to_10000 AGI_from_1_to_5000 AGI_from_5000_to_10000
1:                   183454            1035373                 319540         2588950187             2396550000
2:                   241199            4272260                4826042        10682786130            36195315000
3:                   249506            1124098                1959866         2810807049            14698995000

【问题讨论】:

  • 你如何计算AGI_from_5000_to_10000 列?对我来说 319540 * 7500 = 2396550000
  • vn 在您的代码中定义在哪里?
  • 两个都是错别字,我很抱歉。现在应该是正确的。

标签: r data.table lapply


【解决方案1】:

这应该可行.. 不需要lapply()

library( data.table )
setDT( DF )
DF[, (var) := as.data.table ( t( t( DF[, 2:3] ) * val ) ) ][]


#    No_Adjusted_Gross_Income NoR_from_1_to_5000 NoR_from_5000_to_10000 AGI_from_1_to_5000 AGI_from_5000_to_10000
# 1:                   183454            1035373                 319540         2588950187             2396550000
# 2:                   241199            4272260                4826042        10682786130            36195315000
# 3:                   249506            1124098                1959866         2810807049            14698995000

【讨论】:

  • 非常感谢您的回答。我想知道,您的解决方案是否也允许分组变量?我正在尝试在不同的环境中应用您的解决方案。在这种情况下,我想作为输出,按组列中的值的总和。我试图做类似DF[, (var) := as.data.table ( t( t( DF[, 2:3] , by="No_Adjusted_Gross_Income") ) ) ][] 的事情,但它随后给出了错误unused argument。如果我将by 放在更远的地方,它不会出错,但不会给出正确的结果。
【解决方案2】:

您可以使用apply 来获取您的值,然后如果您想与您的原始DF 结合使用cbind

t(apply(DF[,2:3],1, function(x) x*val ))

 NoR_from_1_to_5000 NoR_from_5000_to_10000
[1,]         2588950187             2396550000
[2,]        10682786130            36195315000
[3,]         2810807049            14698995000

【讨论】:

  • 谢谢你的回答,在这种情况下变量名vn会去哪里?
  • 如果您将上述代码分配为名为@9​​87654325@ 的对象,您可以在使用cbind 之前使用colnames(NewCols) &lt;- vn
【解决方案3】:

OP 已在 comment 中要求分组变量。

虽然接受的答案显然符合 OP 最初的要求,但我想提出一种完全不同的方法,以整齐(长)格式存储和处理数据。恕我直言,以长格式处理数据更加直接和灵活(包括聚合和分组)。

为此,数据集从宽的 Excel 样式格式重塑为长的 SQL 样式格式

library(data.table)
col <- "NoR"
long <- melt(DF, measure.vars = patterns(col), value.name = col, variable.name = "range")
long[, range := stringr::str_remove(range, paste0(col, "_"))]
long
   No_Adjusted_Gross_Income              range     NoR
1:                   183454     from_1_to_5000 1035373
2:                   241199     from_1_to_5000 4272260
3:                   249506     from_1_to_5000 1124098
4:                   183454 from_5000_to_10000  319540
5:                   241199 from_5000_to_10000 4826042
6:                   249506 from_5000_to_10000 1959866

在整洁(长)格式中,每个观察值一行,每个变量一列(请参阅Chapter 12.2 of Hadley Wickham's book R for Data Science

乘数向量val也需要从宽格式改成长格式:

valDF <- long[, .(range = unique(range), val)]
valDF
                range    val
1:     from_1_to_5000 2500.5
2: from_5000_to_10000 7500.0

现在,valDF 的格式也很整洁,因为每个 range 都有一行。

最后,我们可以通过 update join 将新列 AGI 添加到 DF

long[valDF, on = "range", AGI := val * NoR][]
   No_Adjusted_Gross_Income              range     NoR         AGI
1:                   183454     from_1_to_5000 1035373  2588950187
2:                   241199     from_1_to_5000 4272260 10682786130
3:                   249506     from_1_to_5000 1124098  2810807049
4:                   183454 from_5000_to_10000  319540  2396550000
5:                   241199 from_5000_to_10000 4826042 36195315000
6:                   249506 from_5000_to_10000 1959866 14698995000

如果需要演示,可以将数据集从长格式重新调整为宽格式:

dcast(long, No_Adjusted_Gross_Income ~ range, value.var = c("NoR", "AGI"))
   No_Adjusted_Gross_Income NoR_from_1_to_5000 NoR_from_5000_to_10000 AGI_from_1_to_5000 AGI_from_5000_to_10000
1:                   183454            1035373                 319540         2588950187             2396550000
2:                   241199            4272260                4826042        10682786130            36195315000
3:                   249506            1124098                1959866         2810807049            14698995000

再现了 OP 的预期结果。请注意,变量名称vn 是自动创建的。


可以在整形的同时进行聚合和分组

dcast(long, No_Adjusted_Gross_Income ~ range, sum, value.var = c("NoR", "AGI"))
   No_Adjusted_Gross_Income NoR_from_1_to_5000 NoR_from_5000_to_10000 AGI_from_1_to_5000 AGI_from_5000_to_10000
1:                   183454            1035373                 319540         2588950187             2396550000
2:                   241199            4272260                4826042        10682786130            36195315000
3:                   249506            1124098                1959866         2810807049            14698995000

dcast(long, No_Adjusted_Gross_Income ~ ., sum, value.var = c("NoR", "AGI"))
   No_Adjusted_Gross_Income     NoR         AGI
1:                   183454 1354913  4985500187
2:                   241199 9098302 46878101130
3:                   249506 3083964 17509802049

或者,可以以长格式执行聚合和分组:

long[, lapply(.SD, sum), .SDcols = c("NoR", "AGI"), by = No_Adjusted_Gross_Income]
   No_Adjusted_Gross_Income     NoR         AGI
1:                   183454 1354913  4985500187
2:                   241199 9098302 46878101130
3:                   249506 3083964 17509802049

【讨论】:

  • 非常感谢!早上第一件事就试试这个!
猜你喜欢
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 2018-04-03
  • 2020-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多