R-создать новую переменную, где каждое наблюдение зависит от другой таблицы и других переменных в фрейме данных

у меня есть две следующие таблицы:

df <- data.frame(eth = c("A","B","B","A","C"),ZIP1 = c(1,1,2,3,5))
Inc <- data.frame(ZIP2 = c(1,2,3,4,5,6,7),A = c(56,98,43,4,90,19,59), B = c(49,10,69,30,10,4,95),C = c(69,2,59,8,17,84,30))

eth    ZIP1         ZIP2    A    B    C
A      1            1      56   49   69
B      1            2      98   10   2
B      2            3      43   69   59
A      3            4      4    30   8
C      5            5      90   10   17
                    6      19   4    84
                    7      59   95   39

Я хотел бы создать переменную Inc в фрейме данных df, где для каждого наблюдения значение является пересечением eth и ZIP наблюдения. В моем примере это привело бы к:

   eth    ZIP1   Inc        
    A      1    56
    B      1    49
    B      2    10
    A      3    43
    C      5    17

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

спасибо !

5 ответов


Как насчет этого?

library(reshape2)
merge(df, melt(Inc, id="ZIP2"), by.x = c("ZIP1", "eth"), by.y = c("ZIP2", "variable"))
  ZIP1 eth value
1    1   A    56
2    1   B    49
3    2   B    10
4    3   A    43
5    5   C    17

конечно, это можно сделать в данных.таблица:

library(data.table)
setDT(df)

df[ melt(Inc, id.var="ZIP2", variable.name="eth", value.name="Inc"), 
  Inc := i.Inc
, on=c(ZIP1 = "ZIP2","eth") ]

синтаксис для этой операции "merge-assign" -X[i, Xcol := expression, on=merge_cols].

вы можете запустить i = melt(Inc, id.var="ZIP", variable.name="eth", value.name="Inc") часть сама по себе, чтобы увидеть, как это работает. Внутри слияния столбцы из i можно сослаться на i.* префиксы.


поочередно...

setDT(df)
setDT(Inc)
df[, Inc := Inc[.(ZIP1), eth, on="ZIP2", with=FALSE], by=eth]

это построено на аналогичной идее. виньетки пакет являются хорошим местом для начала для такого рода синтаксис.


можно использовать row/column индексации

df$Inc <- Inc[cbind(match(df$ZIP1, Inc$ZIP2), match(df$eth, colnames(Inc)))]

df
#  eth ZIP1 Inc
#1   A    1  56
#2   B    1  49
#3   B    2  10
#4   A    3  43
#5   C    5  17

другой вариант:

library(dplyr)
library(tidyr)
Inc %>%
  gather(eth, value, -ZIP2) %>%
  left_join(df, ., by = c("eth", "ZIP1" = "ZIP2"))

мое решение (которое, возможно, кажется неудобным)

for (i in 1:length(df$eth)) {
    df$Inc[i] <- Inc[as.character(df$eth[i])][df$ZIP[i],]
}