簡體   English   中英

使用R中的2個數據幀執行簡單查找

[英]Performing simple lookup using 2 data frames in R

在R中,我有兩個數據幀A和B,如下所示:

數據框A:

Name      Age    City       Gender   Income    Company   ...
JXX       21     Chicago    M        20K       XYZ       ...
CXX       25     NewYork    M        30K       PQR       ...
CXX       26     Chicago    M        NA        ZZZ       ...

數據框B:

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相連的一行(50 / NewYork / F)。
  • B中不與A連接的一行(27 / New York / M)。
  • 兩行連接,應導致A中的NA被B中的非NA值替換(23 / Chicago / M和31 / Chicago / M)。
  • 一行連接但在B中具有NA,因此不應影響A中的NA(62 / Nework / M)。
  • 可以連接但在A中具有非NA的一行,因此不應從B中獲取值(我假設您會想要這種行為)(51 / Chicago / F)。 A(90K)中的值不同於B(60K)中的值,因此我們可以驗證此行為。

而且,我故意加擾了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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM