使用R

时间:2016-06-02 00:09:54

标签: r dataframe merge lookup r-package

在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中的缺失值。

例如,对于数据框A中的第三行,我可以用数据框B中的平均收入代替精确收入。我不想合并这两个数据框,而是希望使用Age,City和Gender列执行查找操作。

3 个答案:

答案 0 :(得分:1)

所以我认为这适用于收入。如果只有这3列,您可以用以下代码替换其他列的名称:

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

如果其中一个常客有更好的方法阻止你不得不重新输入列的名称,那就不会让我感到惊讶。

答案 1 :(得分:1)

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 / NewYork / M)联系。
  • 两行连接并应导致A中的NA替换为来自B的非NA值(23 / Chicago / M和31 / Chicago / M)。
  • 一行加入但在B中有NA,所以不应该影响A中的NA(62 / NewYork / M)。
  • 一行可以加入,但A中没有NA,所以不应该从B中取值(我假设你会想要这种行为)(51 /芝加哥/ 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 {{将源列就地分配给目标列。 1}}语法。

请注意,在data.table世界:=执行右连接,因此如果您想要左连接,则需要将其反转为{{ 1}}(使用&#34;左&#34;现在引用X[Y],反直觉)。这就是为什么我使用Y[X]代替X(可能更自然的期望)的原因。我们需要Bt[.SD]上的左连接,因为连接索引表达式的结果将就地分配给目标列,因此赋值的RHS必须是与目标列对应的完整向量。

您可以为要替换的每列重复就地分配行。

.SD[Bt]

我想我在这里感觉有点创意,所以对于一个基本的R解决方案,我做了一些可能有点不寻常的事情,而且我以前从未做过。我将一个合成的行索引列列绑定到每个A和B data.frames的键列子集中,然后调用.SD来加入它们(请注意,这是一个内部连接,因为我们在这里不需要任何类型的外连接),并且只提取了连接产生的行索引列。这有效地预先计算了所有后续修改操作的连接行对。

对于修改,我预先计算A中的行满足替换条件的连接对的子集,例如, ## 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 替换的merge()值为NA。然后,我们可以对这些行的连接对表进行子集化,并从B到A进行直接分配以执行替换。

和以前一样,您可以为要替换的每一列重复分配行。

答案 2 :(得分:0)

您可以简单地使用以下内容将城市的平均收入从B更新为A中的收入。

dataFrameA $ Income = dataFrameB $`平均收入`[匹配(dataFrameA $ City,dataFrameB $ City)]

你必须使用&#34;`&#34;如果列名称有空格

这类似于在excel中使用索引和匹配进行查找。我假设你来自excel。如果您使用data.table

,代码将更紧凑