[英]Performing simple lookup using 2 data frames in R
在R中,我有兩個數據幀A和B,如下所示:
Name Age City Gender Income Company ...
JXX 21 Chicago M 20K XYZ ...
CXX 25 NewYork M 30K PQR ...
CXX 26 Chicago M NA ZZZ ...
Age City Gender Avg Income Avg Height Avg Weight ...
21 Chicago M 30K ... ... ...
25 NewYork M 40K ... ... ...
26 Chicago M 50K ... ... ...
我想填充數據框B中數據框A中的缺失值。
例如,對於數據框AI中的第三行,AI可以代替數據框B的平均收入,而不是確切收入。 我不想合並這兩個數據框,而是想使用“年齡”,“城市”和“性別”列執行類似操作的查找。
所以我認為這對收入有效。 如果只有這三列,則可以在以下位置替換其他列的名稱:
df1<-read.table(header = T, stringsAsFactors = F, text = "
Name Age City Gender Income Company
JXX 21 Chicago M 20K XYZ
CXX 25 NewYork M 30K PQR
CXX 26 Chicago M NA ZZZ")
df2<-read.table(header = T, stringsAsFactors = F, text = "
Age City Gender Avg_Income
21 Chicago M 30K
25 NewYork M 40K
26 Chicago M 50K ")
df1[is.na(df1$Income),]$Income<-df2[is.na(df1$Income),]$Avg_Income
如果其中一位常規者擁有更好的方法來防止您不得不重新鍵入列名,這也不會令我感到驚訝。
library(data.table);
## generate data
set.seed(5L);
NK <- 6L; pA <- 0.8; pB <- 0.2;
keydf <- unique(data.frame(Age=sample(18:65,NK,T),City=sample(c('Chicago','NewYork'),NK,T),Gender=sample(c('M','F'),NK,T),stringsAsFactors=F));
NO <- nrow(keydf)-1L;
Af <- cbind(keydf[-1L,],Name=sample(paste0(LETTERS,LETTERS,LETTERS),NO,T),Income=sample(c(NA,paste0(seq(20L,90L,10L),'K')),NO,T,c(pA,rep((1-pA)/8,8L))),stringsAsFactors=F)[sample(seq_len(NO)),];
Bf <- cbind(keydf[-2L,],`Avg Income`=sample(c(NA,paste0(seq(20L,90L,10L),'K')),NO,T,c(pB,rep((1-pB)/8,8L))),stringsAsFactors=F)[sample(seq_len(NO)),];
At <- as.data.table(Af);
Bt <- as.data.table(Bf);
At;
## Age City Gender Name Income
## 1: 50 NewYork F OOO NA
## 2: 23 Chicago M SSS NA
## 3: 62 NewYork M VVV NA
## 4: 51 Chicago F FFF 90K
## 5: 31 Chicago M XXX NA
Bt;
## Age City Gender Avg Income
## 1: 62 NewYork M NA
## 2: 51 Chicago F 60K
## 3: 31 Chicago M 50K
## 4: 27 NewYork M NA
## 5: 23 Chicago M 60K
我出於演示目的生成了一些隨機測試數據。 我對種子5的結果感到非常滿意,它涵蓋了許多情況:
而且,我故意加擾了A和B的行,以確保無論輸入的行順序如何,我們都可以正確地連接它們。
## data.table solution
keys <- c('Age','City','Gender');
At[is.na(Income),Income:=Bt[.SD,on=keys,`Avg Income`]];
## Age City Gender Name Income
## 1: 50 NewYork F OOO NA
## 2: 23 Chicago M SSS 60K
## 3: 62 NewYork M VVV NA
## 4: 51 Chicago F FFF 90K
## 5: 31 Chicago M XXX 50K
在上面的代碼中,我首先過濾了A中的NA值,然后在鍵列的j
參數中進行了連接,然后使用data.table :=
語法將源列適當地分配給目標列。
請注意,在data.table世界中, X[Y]
進行右連接 ,因此,如果要左連接 ,則需要將其反轉為Y[X]
(“ left”現在直指X
)。 這就是為什么我使用Bt[.SD]
而不是.SD[Bt]
(可能更自然的期望)的.SD[Bt]
。 我們需要在.SD
上進行左連接,因為連接索引表達式的結果將就地分配給目標列,因此分配的RHS必須是與目標列對應的完整向量。
您可以為要替換的每一列重復就地分配行。
## base R solution
keys <- c('Age','City','Gender');
m <- merge(cbind(Af[keys],Ai=seq_len(nrow(Af))),cbind(Bf[keys],Bi=seq_len(nrow(Bf))))[c('Ai','Bi')];
m;
## Ai Bi
## 1 2 5
## 2 5 3
## 3 4 2
## 4 3 1
mi <- which(is.na(Af$Income[m$Ai])); Af$Income[m$Ai[mi]] <- Bf$`Avg Income`[m$Bi[mi]];
Af;
## Age City Gender Name Income
## 2 50 NewYork F OOO <NA>
## 5 23 Chicago M SSS 60K
## 3 62 NewYork M VVV <NA>
## 6 51 Chicago F FFF 90K
## 4 31 Chicago M XXX 50K
我想我在這里感覺有點創意,因此對於基本的R解決方案,我做了一些可能不尋常的事情,而我以前從未做過。 我將一個合成的行索引列綁定到A和B data.frames的每個鍵列子集中,然后調用merge()
將它們連接起來(請注意,這是一個內部連接 ,因為我們不需要任何連接)一種外部聯接),並僅提取聯接產生的行索引列。 這可以有效地為所有后續修改操作預先計算連接的行對。
對於修改,我預先計算了A中的行滿足替換條件的聯接對的子集,例如,對於Income
替換,其Income
值為NA。 然后,我們可以為這些行的聯接對表子集,並從B到A進行直接分配以進行替換。
和以前一樣,您可以為要替換的每一列重復分配行。
您只需使用以下內容即可將城市的平均收入從B更新為A中的收入。
dataFrameA $ Income = dataFrameB $`平均收入`[match(dataFrameA $ City,dataFrameB $ City)]
如果列名帶有空格,則必須使用“`”
這類似於在Excel中使用索引和匹配進行查找。 我假設您來自Excel。 如果使用data.table,代碼將更加緊湊。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.