Программный вызов объекта на основе "имен", хранящихся в переменных - PullRequest
0 голосов
/ 07 августа 2020

У меня есть вопрос о ссылках на объекты путем получения имени объекта из переменной.

SETUP

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

Теперь у меня есть набор имен флагов (которые соответствуют фактическим именам столбцов) для первого объекта в моей исходной таблице данных, и я хочу присвоить этим флагам новые значения (ИСТИНА). Я хочу вызвать значение из 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

И мой единственный флаг теперь ИСТИНА, поэтому мы знаем, что object :: one - это "isGreen" :: ИСТИНА. Конечно, с помощью цикла я могу установить все необходимые флаги для всех объектов. Я видел много конкретных c решений, но все они следуют основной идее c; превратите переменную в строку, объедините эту строку с другими строками, необходимыми для построения вашего выражения, а затем оцените всю строку как выражение.

ВОПРОС

Есть ли лучший способ, чем, "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] (как выражение, которое необходимо оценить)
Красиво и аккуратно, без суеты, без многоуровневых функций.

ПРИМЕЧАНИЕ: Я понимаю, что могу создать свою собственную функцию для этого, но то, что я спрашиваю, это «он уже существует, а я просто не нашел его?». Я просто пытаюсь понять, знает ли кто-нибудь то, чего я не знаю, что могло бы облегчить мою жизнь. СПАСИБО.

1 Ответ

1 голос
/ 09 августа 2020

Вот одна альтернатива:

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)]
...