添加(不合并!)两个不等行和列

时间:2016-02-02 20:16:09

标签: r dataframe

我想有效地对两个数据帧的条目求和,尽管不保证数据帧具有相同的维度或列名称。合并并不是我在这之后的真实情况。相反,我想创建一个输出对象,其中包含属于任一添加数据帧的所有行和列名称。在该输出的每个位置,我想对计算值使用以下逻辑:

  • 如果行/列配对属于两个输入数据帧,我希望输出包含它们的总和
  • 如果行/列配对只属于一个输入数据框,我想在输出中包含该值
  • 如果行/列配对不属于任何输入矩阵,我希望输出中的该位置为0。

例如,请考虑以下输入数据框:

df1 = data.frame(x = c(1,2,3), y = c(4,5,6))
rownames(df1) = c("a", "b", "c")
df2 = data.frame(x = c(7,8), z = c(9,10), w = c(2, 3))
rownames(df2) = c("a", "d")
> df1
  x y
a 1 4
b 2 5
c 3 6
> df2
  x  z  w 
a 7  9  2
d 8 10  3

我希望最终结果是

> df2
   x  y   z  w
a  8  4   9  2
b  2  5   0  0
c  3  6   0  0
d  8  0  10  3

到目前为止我做了什么 -

dplyr中的

bind_rows / bind_cols可以抛出以下内容:  “错误:行数不兼容(3,期望2)”

我有重复的列名,所以'merge'也不能用于我的目的 - 由于某种原因返回一个空的df。

5 个答案:

答案 0 :(得分:4)

好像你可以在rownames上合并,然后将NA的总和和转换为零,并进行一些额外的修改:

library(dplyr)

df.new = df1 %>% add_rownames %>%
  full_join(df2 %>% add_rownames, by="rowname") %>%
  mutate_each(funs(replace(., which(is.na(.)), 0))) %>%
  mutate(x = x.x + x.y) %>%
  select(rowname,x,y,z,w)

或者,@ DavidArenburg提供了更加优雅和可扩展的解决方案:

df.new = df1 %>% add_rownames %>% 
  full_join(df2 %>% add_rownames) %>% 
  group_by(rowname) %>% 
  summarise_each(funs(sum(., na.rm = TRUE)))

df.new

  rowname     x     y     z     w
1       a     8     4     9     2
2       b     2     5     0     0
3       c     3     6     0     0
4       d     8     0    10     3

答案 1 :(得分:3)

这看起来像普通列名(+行名)上的某种类型的简单合并然后是一个简单的聚合,这就是我要解决的问题

library(data.table)
merge(setDT(df1, keep.rownames = TRUE), # Convert to data.table + keep rows
      setDT(df2, keep.rownames = TRUE), # Convert to data.table + keep rows
      by = intersect(names(df1), names(df2)), # merge on common column names
      all = TRUE)[, lapply(.SD, sum, na.rm = TRUE), by = rn] # Sum all columns by group                   
#    rn x y  z w
# 1:  a 8 4  9 2
# 2:  b 2 5  0 0
# 3:  c 3 6  0 0
# 4:  d 8 0 10 3

是一个非常直接的基础R解决方案

df1$rn <- row.names(df1)
df2$rn <- row.names(df2)
res <- merge(df1, df2, all = TRUE)
rowsum(res[setdiff(names(res), "rn")], res[, "rn"], na.rm = TRUE)
#   x y  z w
# a 8 4  9 2
# b 2 5  0 0
# c 3 6  0 0
# d 8 0 10 3

答案 2 :(得分:2)

首先,我会获取新实体的所有行和列的名称:

(all.rows <- unique(c(row.names(df1), row.names(df2))))
# [1] "a" "b" "c" "d"
(all.cols <- unique(c(names(df1), names(df2))))
# [1] "x" "y" "z" "w"

然后我将构造一个包含行和列名称的输出矩阵(矩阵数据初始化为全0),将df1df2添加到该矩阵的相关部分。

out <- matrix(0, nrow=length(all.rows), ncol=length(all.cols))
rownames(out) <- all.rows
colnames(out) <- all.cols
out[row.names(df1),names(df1)] <- unlist(df1)
out[row.names(df2),names(df2)] <- out[row.names(df2),names(df2)] + unlist(df2)
out
#   x y  z w
# a 8 4  9 2
# b 2 5  0 0
# c 3 6  0 0
# d 8 0 10 3

答案 3 :(得分:1)

在融合/堆叠数据框上使用xtabs

out <- rbind(cbind(rn=rownames(df1),stack(df1)), cbind(rn=rownames(df2),stack(df2)))
as.data.frame.matrix(xtabs(values ~ rn + ind, data=out))

#  x y w  z
#a 8 4 2  9
#b 2 5 0  0
#c 3 6 0  0
#d 8 0 3 10

答案 4 :(得分:0)

我不相信接受(或替代合并)方法是最好的。如果你有共同的行,它会得到不正确的结果,它们会加入而不是求和。

这可以通过将df2更改为:

来琐碎地显示
df2 = data.frame(x = c(1,2), y = c(4,5), z = c(9,10), w = c(2, 3))
rownames(df2) = c("a", "d")

预期结果:

   rn x y  z w
1:  a 2 8  9 2
2:  b 2 5  0 0
3:  c 3 6  0 0
4:  d 2 5 10 3

实际结果

merge(setDT(df1, keep.rownames = TRUE), 
  setDT(df2, keep.rownames = TRUE), 
  by = intersect(names(df1), names(df2)), 
  all = TRUE)[, lapply(.SD, sum, na.rm = TRUE), by = rn]

   rn x y  z w
1:  a 1 4  9 2
2:  b 2 5  0 0
3:  c 3 6  0 0
4:  d 2 5 10 3

您需要将外部联接与内部联接(或左/右联接,合并all = T / all = F)组合在一起。或者使用plyr的rbind.fill:

基础R解决方案

res <- rbind.fill(df1,df2)
rowsum(res[setdiff(names(res), "rn")], res[, "rn"], na.rm = TRUE)

数据表解决方案

as.data.table(rbind.fill(
  setDT(df1, keep.rownames = TRUE),
  setDT(df2, keep.rownames = TRUE)
))[, lapply(.SD, sum, na.rm = TRUE), by = rn]

我更喜欢rbind.fill方法,因为你可以“合并”&gt;使用相同语法的2个数据帧。