【问题标题】:Is there a way to assign a value to data.table columns selected programmatically by row? [duplicate]有没有办法为按行以编程方式选择的 data.table 列分配值? [复制]
【发布时间】:2020-01-29 18:08:13
【问题描述】:

我正在处理一个包含大约 500 列和数千行的数据表,每列代表一个可能会或可能不会出现在字符串中的项目。例如,我的数据看起来像这样

   String                Item 1 Item 2  Item 3 Item 4
1  "Item 1Item 2Item 4"    0     0        0     0
2  "Item 1Item 2"          0     0        0     0      
3  "Item 3"                0     0        0     0      

我已将字符串解析为项目编号,结果项目位于列表中(因此,对于上面的第一个观察,列表项目 1 将包含元素“项目 1”、“项目 2”和“项目 4”。

我试图以编程方式更改每列的值,方法是将列表中的每一项用作行的列名,然后将 1 分配给这些列。例如,我可以构建一个简单的 for 循环来执行我正在寻找的操作:

for (i in 1:nrow(data)){
   data[i, eval(unlist(listofitems[[i]])) := 1]
}

返回

  String                Item 1 Item 2  Item 3 Item 4
1  "Item 1Item 2Item 4"    1     1        0     1
2  "Item 1Item 2"          1     1        0     0      
3  "Item 3"                0     0        1     0           

但是,考虑到数据的大小以及出现类似情况的频率(有时我希望能够对数据表对通过引用分配的列进行逐行操作),我希望可能会有一种更“data.table-y”的方式来获得最终答案。

【问题讨论】:

  • 项目和数字之间的空格是故意的还是错字?
  • 间距和分隔符不一致。但是,它们已经被解析到我在问题中提到的列表中。我已经编辑了问题,使其与实际数据的格式更加一致。
  • 您能否在解析后dput 数据集?
  • 从 dput-ing 列表中获取的数据样本将是 "c("Item 7.01", "Item 9.01"), c("Item 7.01", "Item 9.01"), c( "Item 2.02", "Item 9.01"), "Item 1.01", c("Item 2.02", "Item 9.01") 其中每个向量都是列表中的一个元素。
  • 我猜你改变了输入数据格式

标签: r data.table


【解决方案1】:

我们可以使用cSplit_e

library(splitstackshape)
out <- cSplit_e(data[1], 'String', type = 'character', sep=":", fill = 0)
names(out)[-1] <- sub("String_", "", names(out)[-1])
out
#              String Item 1 Item 3 Item2 Item4
#1 Item 1:Item2:Item4      1      0     1     1
#2       Item 1:Item2      1      0     1     0
#3             Item 3      0      1     0     0

数据

data <- structure(list(String = c("Item 1:Item2:Item4", "Item 1:Item2", 
"Item 3"), Item1 = c(0L, 0L, 0L), Item2 = c(0L, 0L, 0L), Item3 = c(0L, 
0L, 0L), Item4 = c(0L, 0L, 0L)), class = "data.frame", row.names = c("1", 
"2", "3"))

【讨论】:

  • 谢谢!字符串的格式不是很干净,但我可以看到,如果我只是做一些工作来清理字符串,这将使整个练习变得非常简单。
  • @JerryMathis 更改列名非常容易out &lt;- cSplit_e(data[1], 'String', type = 'character', sep=":", fill = 0); names(out)[-1] &lt;- sub("String_", "", names(out)[-1])
  • 问题是字符串在整个数据中并不统一。其中很多是手工编码的,另一部分是由机器生成的,等等。所以很难说分隔符是一个特定的字符或模式。这就是为什么我使用已经解析的列名列表进行操作的原因。我意识到这与原始帖子并没有真正区别 - 我很抱歉!
【解决方案2】:

一个选项是使用矩阵数字索引进行分配:

cols <- setdiff(names(DT), c("String", "ParsedString"))
DT[, (cols) := {
    m <- cbind(rep(1L:.N, lengths(ParsedString)), 
        match(unlist(ParsedString), names(.SD)))
    ans <- as.matrix(.SD)
    ans[m] <- 1L
    as.data.table(ans)
}, .SDcols=cols]

数据:

library(data.table)
DT <- fread('String,Item 1,Item 2,Item 3,Item 4
"Item 1:Item 2:Item 4",0,0,0,0
"Item 1:Item 2",0,0,0,0      
"Item 3",0,0,0,0')
DT[, ParsedString := strsplit(String, split=":")]

【讨论】:

  • 这是一个非常有用的解决方案(很好地概括了我遇到的其他问题)并且在我的数据上运行得非常快。感谢您的帮助!
猜你喜欢
  • 2012-03-16
  • 2013-04-02
  • 2014-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-02
相关资源
最近更新 更多