【问题标题】:Programmatically calling Object based on "names" stored in variables基于存储在变量中的“名称”以编程方式调用 Object
【发布时间】:2020-08-06 22:52:42
【问题描述】:

我有一个关于通过从变量中检索对象名称来引用对象的问题。

设置

library(data.table)
object <- c("one", "two", "three")
attributes <- c("green, blue, red", "red", "blue, orange")
DT <- data.table(object,attributes) ; DT

   object       attributes
1:    one green, blue, red
2:    two              red
3:  three     blue, orange

这是我的基本设置(简化数据)。我有带有名称的对象,每个对象都分配了属性。属性在原始数据集中以逗号分隔的字符串形式出现在表格的单个单元格中。这些属性来自一个有限的、可知的属性列表。在这个例子中,我使用颜色。 我需要能够按属性查找对象。因此,将所有以“红色”作为属性的对象进行子集化。 (在现实世界的例子中,有 20k 个对象和 ~200 个属性) 在收到原始数据并创建 data.table 后,我想要的是为所有可能的属性创建标志列,以方便搜索/子设置。所以这个……

DT[, isRed := FALSE]
DT[, isGreen := FALSE]
DT[, isBlue := FALSE]
DT[, isOrange := FALSE]
DT
   object       attributes isRed isGreen isBlue isOrange
1:    one green, blue, red FALSE   FALSE  FALSE    FALSE
2:    two              red FALSE   FALSE  FALSE    FALSE
3:  three     blue, orange FALSE   FALSE  FALSE    FALSE

这将创建我的基线 data.table,所有标志列都已到位并在处理之前设置为 FALSE。

处理是获取属性字符串,解析出各个属性,并相应地设置标志。这就是我正在做的……

# take the first object, parse the attributes into a data.table
split.attributes <- 
  str_split(DT[object == "one", attributes], ",", n = Inf) %>% 
  transpose() %>% 
  data.table() 
split.attributes
       .
1: green
2:  blue
3:   red

# format the attributes with initial Uppercase, and update the data.table
# ignore the extraneous string manipulates (like "\\s") in the real world example 
# the attributes are sometimes two word strings that are then a 
# single flag name, i.e., "blue green" -> "BlueGreen"
split.attributes <- split.attributes[,.] %>% 
  str_to_title() %>% 
  str_remove("\\s") %>% 
  as.list() %>% 
  data.table()
split.attributes

       .
1: Green
2:  Blue
3:   Red

我已经有了“is”形式的所有标志列名,即“isRed”,所以转换data.table…

# paste "is" in front of the attribute and change the column name to avoid referring to "." later
split.attributes[, col.names := paste0("is",.)] 
split.attributes
       . col.names
1: Green   isGreen
2:  Blue    isBlue
3:   Red     isRed
# then remove the extraneous column
split.attributes[, . := NULL]
split.attributes
   col.names
1:   isGreen
2:    isBlue
3:     isRed

我现在有一组用于原始数据表中第一个对象的标志名称(与实际列名称匹配),我想为这些标志分配新值 (TRUE)。 我想要做的是调用 split.attributes[1] 中的值并将其用作 DT 中列的名称。我知道一种方法……

eval(parse( text = (paste0("DT[1, ", eval(split.attributes[i]), " := TRUE]"))))
DT
   object       attributes isRed isGreen isBlue isOrange
1:    one green, blue, red FALSE    TRUE  FALSE    FALSE
2:    two              red FALSE   FALSE  FALSE    FALSE
3:  three     blue, orange FALSE   FALSE  FALSE    FALSE

我的 one 标志现在是 TRUE,所以我们知道 object::one 是 "isGreen"::TRUE。当然,通过循环,我可以为所有对象设置所有必要的标志。我见过很多具体的解决方案,但都遵循以下基本思想;将变量转换为字符串,将该字符串与构建表达式所需的其他字符串连接起来,然后将完整的字符串作为表达式求值。

问题

有没有比“eval(parse( text = (paste0("DT[1, ", eval(split.attributes[i]), " := TRUE]"))))" 更好的方法? 在我看来,这是一个常见问题(或者我的个人项目在这方面可能是独一无二的),所以我觉得你应该能够做类似的事情;
DT[1, ", get_the_variable_value_and_add_as_part_of_a_function ( split.attributes[i] ), " := TRUE]
然后将创建您想要的基础体验以及发送到 R 的内容;
DT[1, isGreen := TRUE](作为要评估的表达式)
漂亮整洁,没有大惊小怪,没有分层功能。

注意:我意识到我可以为此创建自己的功能,但我要问的是“是否已经存在但我还没有找到它?”。我只是想看看是否有人知道我不知道的事情,这会让我的生活更轻松。谢谢。

【问题讨论】:

  • 谢谢@Henrik。出于概念上的原因,我不想要具有属性 = 绿色等的列/行,我希望该列是“isGreen”,因为它是更大应用程序的一部分(并且真实数据不是“绿色”,而是更像“可变”,所以在最后的演示中,我们希望用户被询问“所有可变的项目”,因此标记为“isMutable”的二进制标志列在概念上比属性更容易链接到应用程序的性质==可变的,如果这有意义的话。它也有帮助,因为用户的逻辑要求不可变的项目,所以查询“isMutable”== 0。只是我的想法。

标签: r object data.table


【解决方案1】:

这是另一种选择:

DT[, attributes := strsplit(attributes, ", ")] # Convert to a list column
all_attr <- unique(unlist(DT$attributes))
DT[, 
   paste0("is_", all_attr) := lapply(all_attr, `%chin%`, attributes[[1]]), 
   by = object]

   object     attributes is_green is_blue is_red is_orange
1:    one green,blue,red     TRUE    TRUE   TRUE     FALSE
2:    two            red    FALSE   FALSE   TRUE     FALSE
3:  three    blue,orange    FALSE    TRUE  FALSE      TRUE

另一种选择:

DT[, lapply(.SD, function(x) strsplit(x, ", ")[[1]]), by = object
   ][, x := TRUE
     ][, dcast(.SD, object ~ paste0("is_", attributes), value.var = "x", fill = FALSE)]

【讨论】:

  • 谢谢@sindri_baldur。这很好用,但这并不是我想要的。让它工作不是问题,如果我忽略了一种直接方法,例如“创建一个表达式,在表达式中包含一个变量值,指定该值是一个对象名称,评估”,我会更好奇.这是一件奇怪的事情,如果没有意义,非常抱歉。这对我来说似乎很明显,所以我很难接受它不是那样工作的。
猜你喜欢
  • 2018-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 2013-12-06
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多