Как рассчитать новый столбец на основе других столбцов, используя подход поиска в R? - PullRequest
1 голос
/ 23 апреля 2019

Я пытаюсь вычислить другой столбец в кадре данных на основе других столбцов и таблицы поиска. У меня есть простой пример, который показывает только несколько данных (мой реальный набор данных содержит миллионы строк).

У меня есть следующие наборы данных:

  lookup<- data.frame("class"=c(1, 2, 1, 2), "type"=c("A", "B", "B", "A"), 
           "condition1"=c(50, 60, 55, 53), "condition2"=c(80, 85, 86, 83))

  lookup
  class type condition1 condition2
      1    A         50         80
      2    B         60         85
      1    B         55         86
      2    A         53         83

Мой фрейм данных имеет такую ​​форму:

  data<- data.frame("class"=c(1, 2, 2, 1, 2, 1), 
         "type"=c("A","B", "A", "A", "B", "B"), 
         "percentage_condition1"=c(0.3, 0.6, 0.1, 0.2, 0.4, 0.5), 
         "percentage_condition2"=c(0.7, 0.4, 0.9, 0.8, 0.6, 0.5))


  data
  class type percentage_condition1 percentage_condition2
    1    A                   0.3                   0.7
    2    B                   0.6                   0.4
    2    A                   0.1                   0.9
    1    A                   0.2                   0.8
    2    B                   0.4                   0.6
    1    B                   0.5                   0.5

Я хотел бы создать новый столбец в моем фрейме данных с именем data, который будет использовать таблицу поиска, такую ​​как:

в моих данных, где мой класс совпадает с моими столбцами type , он может вычислять новый столбец в данных моего кадра данных, например (не реальный код):

d $ new <- поиск $ условие1 * данные $ процентное_условие1 + поиск $ условие2 * данные $ процентное_условие2 </p>

Я знаю, как сделать это с помощью оператора if else, но я пытаюсь сделать это более эффективно, так как работаю с большим количеством данных. Я знаю, что сделать это с одним столбцом в таблице поиска, но у меня не получается с несколькими столбцами (столбец класса и типа).

Спасибо за любую помощь и предложения!

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019

Один из вариантов: merge data и lookup, а затем выполнить расчет

df1 <- merge(data, lookup) #This merges by class and type columns

df1$new <- with(df1, (condition1 * percentage_condition1) + 
                     (condition2 * percentage_condition2))


df1
#  class type percentage_condition1 percentage_condition2 condition1 condition2  new
#1     1    A                   0.3                   0.7         50         80 71.0
#2     1    A                   0.2                   0.8         50         80 74.0
#3     1    B                   0.5                   0.5         55         86 70.5
#4     2    A                   0.1                   0.9         53         83 80.0
#5     2    B                   0.6                   0.4         60         85 70.0
#6     2    B                   0.4                   0.6         60         85 75.0
2 голосов
/ 23 апреля 2019

Мы можем использовать match, чтобы получить индекс столбцов «тип» для «данных» и «тип», использовать этот индекс, чтобы получить соответствующие строки столбцов «условие1», «условие2», умножить на процентные столбцы «данных» и получите rowSums

data$new <- rowSums(lookup[match(paste(data$class, data$type), 
                  paste(lookup$class, lookup$type)), 
               c("condition1", "condition2")] * data[3:4])

data
#  class type percentage_condition1 percentage_condition2  new
#1     1    A                   0.3                   0.7 71.0
#2     2    B                   0.6                   0.4 70.0
#3     2    A                   0.1                   0.9 80.0
#4     1    A                   0.2                   0.8 74.0
#5     2    B                   0.4                   0.6 75.0
#6     1    B                   0.5                   0.5 70.5

ПРИМЕЧАНИЕ: С match мы можем сделать это намного проще


или используя data.table

library(data.table)
setDT(data)[lookup, new := condition1 * percentage_condition1 + 
       condition2 * percentage_condition2, on = .(class, type)]
data
#   class type percentage_condition1 percentage_condition2  new
#1:     1    A                   0.3                   0.7 71.0
#2:     2    B                   0.6                   0.4 70.0
#3:     2    A                   0.1                   0.9 80.0
#4:     1    A                   0.2                   0.8 74.0
#5:     2    B                   0.4                   0.6 75.0
#6:     1    B                   0.5                   0.5 70.5

Или используя tidyverse

library(tidyverse)
data %>% 
     left_join(lookup, by = c("class", "type")) %>%
     mutate(new = condition1 * percentage_condition1 + 
       condition2 * percentage_condition2) %>%
     select(names(data), new)
#   class type percentage_condition1 percentage_condition2  new
#1     1    A                   0.3                   0.7 71.0
#2     2    B                   0.6                   0.4 70.0
#3     2    A                   0.1                   0.9 80.0
#4     1    A                   0.2                   0.8 74.0
#5     2    B                   0.4                   0.6 75.0
#6     1    B                   0.5                   0.5 70.5

Или используйте решение на основе SQL с sqldf

library(sqldf)
str1 <- "SELECT data.class, data.type, data.percentage_condition1, 
  data.percentage_condition2, (data.percentage_condition1 * lookup.condition1 + 
   data.percentage_condition2 * lookup.condition2) as new
   FROM data 
   LEFT JOIN lookup on data.class = lookup.class AND 
   data.type = lookup.type"
sqldf(str1)

Или, как упомянул в комментариях @ G.Grothendieck, с идентификаторами псевдонимов, sqldf решение можно сделать более компактным

sqldf("select D.*, L.condition1 * D.[percentage_condition1] + 
       L.condition2 * D.[percentage_condition2] as new 
       from data as D 
       left join lookup as L 
       using(class, type)")

ПРИМЕЧАНИЕ. Все решения поддерживают первоначальный порядок набора данных

...