Subtract/find 2个不同列数的数据框的区别
Subtract/find the difference between 2 data frames with different numbers of columns
我对 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))
会将2个数据帧加在一起产生
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
我试过用 diff
替换函数中的 sum
但没有用
有什么想法可以解决这个问题吗?
编辑 - 我意识到该函数包括对我保存这些数据框的列表的引用并对其进行了更改。
跟进:处理 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 值,但了解答案是否有调整会很有用可以解决这个问题。
这是一个使用 data,table
连接的选项。获取两个数据集中共有的列名称 (intersect
) 并删除比较不需要的名称 (setdiff
)
library(data.table)
nm1 <- setdiff(intersect(names(df1), names(df2)), c("Measure", "Filename"))
然后做一个连接 on
the 'Measure', 'Filename', 从 'df1' 和相应的列中获取列 ('nm1') 的值在 'df2'。在这里,它将是 i.
,因为 'df2' 位于第 i
个位置(data.table 遵循相同的格式 [i, j, by]
。通过使用 mget
,它 returns 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相比的任意值returns 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
如果您将 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
我对 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))
会将2个数据帧加在一起产生
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
我试过用 diff
替换函数中的 sum
但没有用
有什么想法可以解决这个问题吗?
编辑 - 我意识到该函数包括对我保存这些数据框的列表的引用并对其进行了更改。
跟进:处理 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 值,但了解答案是否有调整会很有用可以解决这个问题。
这是一个使用 data,table
连接的选项。获取两个数据集中共有的列名称 (intersect
) 并删除比较不需要的名称 (setdiff
)
library(data.table)
nm1 <- setdiff(intersect(names(df1), names(df2)), c("Measure", "Filename"))
然后做一个连接 on
the 'Measure', 'Filename', 从 'df1' 和相应的列中获取列 ('nm1') 的值在 'df2'。在这里,它将是 i.
,因为 'df2' 位于第 i
个位置(data.table 遵循相同的格式 [i, j, by]
。通过使用 mget
,它 returns 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相比的任意值returns 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
如果您将 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
它们在减去
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