在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中的缺失值。
例如,对于数据框A中的第三行,我可以用数据框B中的平均收入代替精确收入。我不想合并这两个数据框,而是希望使用Age,City和Gender列执行查找操作。
答案 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的行以确保我们正确加入它们,无论传入的行顺序如何。
## 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
,代码将更紧凑