我是R的新手,却找不到能够回答该查询的地方。
我有2个数据框,它们具有相同的行数但具有不同的列数。我想减去匹配列中的值以标识2个数据帧之间的差异。
例如,这两个数据框类似于我正在使用的数据框:
df1<-data.frame(Measure=rep("test",3),Filename=c("filename1","filename2","filename3"),Op1=c(79,72,95),Op2=c(NA,NA,5),Op3=c(75,64,66),Op4=c(86,71,58))
Filename Op1 Op2 Op3 Op4
1 filename1 79 NA 75 86
2 filename2 72 NA 64 71
3 filename3 95 5 66 58
df2<-data.frame(Measure=rep("test",3),Filename=c("filename1","filename2","filename3"),Op1=c(9,NA,5),Op4=c(80,70,50))
Filename Op1 Op4
1 filename1 9 80
2 filename2 NA 70
3 filename3 5 50
当前,我有一个函数可以融合2个数据帧,并对看起来像这样的数据求和:
CalcFunSum<-function(MeasureName,BoxNumbers){
temp<-data.frame()
for (i in BoxNumbers){
data<-melt(BoxNumbers[i])
temp<-temp %>% bind_rows(data)
}
temp<-cbind(Measure = MeasureName,dcast(temp,Filename~variable,sum,fill = 0))
temp
}
所以CalcFunSum(test,c(df1,df2))
将把这两个数据帧相加并产生
Measure Filename Op1 Op2 Op3 Op4
1 test filename1 88 NA 75 166
2 test filename2 72 NA 64 141
3 test filename3 100 5 66 108
我想要执行类似于df1-df2的计算以获得以下内容:
Measure Filename Op1 Op2 Op3 Op4
1 test filename1 70 NA 75 6
2 test filename2 72 NA 64 1
3 test filename3 90 5 66 8
我尝试用sum
替换函数中的diff
,但这没用
有什么想法可以解决这个问题吗?
编辑-我意识到该功能包括对列表的引用,我将这些数据帧保存在其中并进行了更改。
跟进:处理NA值
到目前为止,答案一直有效,但是在测试我的实际数据时,我注意到在df2具有NA但df1具有值的情况下,结果输出包含NA而不是df1中的值。我将df2中的值之一更改为NA以反映这一点。
在@akrun和@IceCreamToucan的当前答案中,输出将为
Measure Filename Op1 Op2 Op3 Op4
1 test filename1 70 NA 75 6
2 test filename2 NA NA 64 1
3 test filename3 90 5 66 8
我认为这是代码中某个地方的NA.rm = T,或者我需要在处理过程的早期处理NA值,但是知道对这些答案的调整是否会有所帮助将很有用
答案 0 :(得分:2)
这是使用data,table
进行联接的一个选项。获取两个数据集中的公用列名(intersect
)并删除比较不需要的名称(setdiff
)
library(data.table)
nm1 <- setdiff(intersect(names(df1), names(df2)), c("Measure", "Filename"))
然后进行on
'度量','文件名'的联接,从'df1'和'df2'中的对应列获取列(nm1')的值。在这里,它将是i.
,因为'df2'在第i
位置(data.table遵循相同的格式[i, j, by]
。通过使用mget
,它返回list
中的列,我们用-
得到两组列的差(Map
),并通过分配(:=
)反映原始值的值来更新数据集('df1')
setDT(df1)[df2, (nm1) := Map(`-`, mget(nm1),
mget(paste0("i.", nm1))), on = .(Measure, Filename)]
df1
# Measure Filename Op1 Op2 Op3 Op4
#1: test filename1 70 NA 75 6
#2: test filename2 70 NA 64 1
#3: test filename3 90 5 66 8
任何与NA相比的值都将返回NA,同样,
72-NA
#[1] NA
为避免此问题,我们可以将replace
与NA
设为0,然后进行求和
setDT(df1)[df2, (nm1) := Map(function(x, y) replace(x, is.na(x), 0) -
replace(y, is.na(y), 0),
mget(nm1),mget(paste0("i.", nm1))), on = .(Measure, Filename)]
df1
# Measure Filename Op1 Op2 Op3 Op4
#1: test filename1 70 NA 75 6
#2: test filename2 72 NA 64 1
#3: test filename3 90 5 66 8
答案 1 :(得分:1)
如果您要比较df1
中的一行与df2
中的同一行,即匹配索引而不检查某些连接列是否相等,则可以从中减去df2[common_columns]
df1[common_columns]
,然后将结果分配回df1
(或副本)。
common <- intersect(names(df1), names(df2))[-(1:2)]
new <- df1 # or copy(df1) if df1 is a data.table
new[common] <- df1[common] - df2[common]
new
# Measure Filename Op1 Op2 Op3 Op4
# 1 test filename1 70 NA 75 6
# 2 test filename2 70 NA 64 1
# 3 test filename3 90 5 66 8
编辑:
如果df2
中的某些值为NA
,则可以在减去之前将replace
设为0。
common <- intersect(names(df1), names(df2))[-(1:2)]
new <- df1
new[common] <- new[common] - replace(df2[common], is.na(df2[common]), 0)
new
# Measure Filename Op1 Op2 Op3 Op4
# 1 test filename1 70 NA 75 6
# 2 test filename2 72 NA 64 1
# 3 test filename3 90 5 66 8