根据命名列表更新 dt 列

Posted

技术标签:

【中文标题】根据命名列表更新 dt 列【英文标题】:Update dt columns based on named list 【发布时间】:2022-01-19 02:15:07 【问题描述】:

假设,我有以下my_dt 数据表:

neutrons spectrum geography
2.30 -1.2 KIEL
2.54 -1.6 KIEL
2.56 -0.9 JUNG
2.31 -0.3 ANT

我还有以下命名列表 (my_list):

> my_list
$particles   
[1] "neutrons"

$station   
[1] NA

$energy      
[1] "spectrum"

$area   
[1] "geography"

$gamma   
[1] NA 

此列表的值对应于我的数据集中的列名称(如果它们存在,如果它们不存在 - NA)。 根据我的数据集和此列表,我需要检查 my_dt 中存在哪些列并重命名它们(基于 my_list 名称),对于 NA 值 - 我需要创建填充有 NAs 的列。

所以,我想获取以下数据集:

>final_dt
particles station energy area gamma
2.30 NA -1.2 KIEL NA
2.54 NA -1.6 KIEL NA
2.56 NA -0.9 JUNG NA
2.31 NA -0.3 ANT NA

我尝试使用 apply 系列函数来实现这一点,但目前我无法获得我想要的。 所以,如果有任何帮助,我将不胜感激!

【问题讨论】:

【参考方案1】:

data.table 使用lapply

library(data.table)

setDT(my_dt)
setDT(my_list)

final_dt <- setnames( my_list[, lapply( .SD, function(x)
  if( x %in% colnames(my_dt)) my_dt[,x,with=F] else NA   ) ],
  names(my_list) )

final_dt
   particles station energy area gamma
1:      2.30      NA   -1.2 KIEL    NA
2:      2.54      NA   -1.6 KIEL    NA
3:      2.56      NA   -0.9 JUNG    NA
4:      2.31      NA   -0.3  ANT    NA

base R 使用sapply

setDF(my_dt)
setDF(my_list)

data.frame( sapply( my_list, function(x) if(!is.na(x)) my_dt[,x] else NA  ) )
  particles station energy area gamma
1      2.30      NA   -1.2 KIEL    NA
2      2.54      NA   -1.6 KIEL    NA
3      2.56      NA   -0.9 JUNG    NA
4      2.31      NA   -0.3  ANT    NA

数据

my_dt <- structure(list(neutrons = c(2.3, 2.54, 2.56, 2.31), spectrum = c(-1.2, 
-1.6, -0.9, -0.3), geography = c("KIEL", "KIEL", "JUNG", "ANT"
)), class = "data.frame", row.names = c(NA, -4L))

my_list <- list(particles = "neutrons", station = NA, energy = "spectrum", 
    area = "geography", gamma = NA)

【讨论】:

谢谢你,安德烈!将此解决方案应用于我的数据并收到错误:Error in [.data.table(xxx, , x) : j (the 2nd argument inside [...]) is a single symbol but column name 'x' is not found. @Hilary 这是base R 解决方案。使用setDF(my_dt)setDF(my_list)。如果你想要一个纯粹的data.table 解决方案,你应该将标签datatable 更改为data.table。小但重要的区别:) 非常感谢,我更改了标签!您对如何将您的解决方案转换为纯data.table 解决方案有任何想法吗? @Hilary 查看编辑。希望这对你有用!【参考方案2】:

这可能无法满足您的需求,但由于我单独提出了这个想法,因此我会分享以防万一。您可以使用setnames 重命名基于my_list 的列。之后,添加缺少的列名,其值为NA。最后,如果需要,您可以使用setcolorder 根据您的列表重新排序。

library(data.table)

my_vec <- unlist(my_list)
setnames(my_dt, names(my_vec[match(names(my_dt), my_vec)]))
my_dt[, (setdiff(names(my_vec), names(my_dt))) := NA]
setcolorder(my_dt, names(my_vec))
my_dt

输出

   particles station energy area gamma
1:      2.30      NA   -1.2 KIEL    NA
2:      2.54      NA   -1.6 KIEL    NA
3:      2.56      NA   -0.9 JUNG    NA
4:      2.31      NA   -0.3  ANT    NA

【讨论】:

【参考方案3】:

我写了一个简单的代码来为你完成这项工作:

l = list(c = 'cc', a = 'aa', b = NA) # replace this with your my_list

dt = data.frame(aa = 1:3, cc = 2:4) # replace this with my_dt 

dtl = data.frame(l)

names(dt) = names(l)[na.omit(match(l, names(dt)))]

m = merge(dt, dtl[!is.element(names(dtl), names(dt))])

【讨论】:

谢谢你,马蒂亚!但我需要纯data.table 解决方案.. @Hilary,您确实应该在问题中指定该约束,以我阅读的方式假设它是不安全的。 我确信有一种方法可以将 data.table 转换为 data.frame(如果需要,还可以返回),例如使用 as.data.frame(my_dt) l = my_list # replace this with your my_listdt = as.data.frame(my_dt) # replace this with my_dt dtl = data.frame(l)names(dt) = names(l)[na.omit(match(l, names(dt)))]m = merge(dt, dtl[!is.element(names(dtl), names(dt))])

以上是关于根据命名列表更新 dt 列的主要内容,如果未能解决你的问题,请参考以下文章

根据可编辑单元格用户输入更新闪亮的 DT

如何根据r中的条件(日期)更新data.table中的值

根据另一个 data.table 中的值更新 data.table

如何根据PostgreSQL中同一行的两个不同列更新具有唯一序列号的列?

R:变异列并放置在特定列之前并根据这些特定列命名它们

根据另一列中的元素重命名特定列元素