【发布时间】:2011-05-16 19:49:44
【问题描述】:
我有一个数据框,其中一些连续的列具有相同的名称。我需要搜索这些,为每一行添加它们的值,删除一列并用它们的总和替换另一列。 在之前不知道哪些模式重复的情况下,可能不得不将一个列名与以下列名进行比较以查看是否匹配。
有人可以帮忙吗?
提前致谢。
【问题讨论】:
标签: r
我有一个数据框,其中一些连续的列具有相同的名称。我需要搜索这些,为每一行添加它们的值,删除一列并用它们的总和替换另一列。 在之前不知道哪些模式重复的情况下,可能不得不将一个列名与以下列名进行比较以查看是否匹配。
有人可以帮忙吗?
提前致谢。
【问题讨论】:
标签: r
> dfrm <- data.frame(a = 1:10, b= 1:10, cc= 1:10, dd=1:10, ee=1:10)
> names(dfrm) <- c("a", "a", "b", "b", "b")
> sapply(unique(names(dfrm)[duplicated(names(dfrm))]),
function(x) Reduce("+", dfrm[ , grep(x, names(dfrm))]) )
a b
[1,] 2 3
[2,] 4 6
[3,] 6 9
[4,] 8 12
[5,] 10 15
[6,] 12 18
[7,] 14 21
[8,] 16 24
[9,] 18 27
[10,] 20 30
编辑 2:使用 rowSums 可以将第一个 sapply 参数简化为 unique(names(dfrm)),但需要记住在 "[" 中包含 drop=FALSE:
sapply(unique(names(dfrm)),
function(x) rowSums( dfrm[ , grep(x, names(dfrm)), drop=FALSE]) )
处理 NA 的问题:
sapply(unique(names(dfrm)),
function(x) apply(dfrm[grep(x, names(dfrm))], 1,
function(y) if ( all(is.na(y)) ) {NA} else { sum(y, na.rm=TRUE) }
) )
(编辑说明:通过在 names(.)[.] 结构周围加上 unique 来解决 Tommy 的反例。 错误代码是:
sapply(names(dfrm)[unique(duplicated(names(dfrm)))],
function(x) Reduce("+", dfrm[ , grep(x, names(dfrm))]) )
【讨论】:
dfrm=data.frame(a=1:10, b=20:29, a=101:110, b=200:209, a=1001:1010, check.names=F)
这是我的一个班轮
# transpose data frame, sum by group = rowname, transpose back.
t(rowsum(t(dfrm), group = rownames(t(dfrm))))
【讨论】:
as.data.frame()。
rowsum,因此速度很快,并且在示例数据集上运行速度提高了 1.5 倍。我怀疑在更大的数据帧上它会更快。
一些示例数据。
dfr <- data.frame(
foo = rnorm(20),
bar = 1:20,
bar = runif(20),
check.names = FALSE
)
方法:循环遍历唯一的列名;如果只有一个该名称,则选择具有该 NME 的所有列将返回一个向量,但如果有重复,它也将是一个数据框。使用rowSums 对行求和。 (Duh. 编辑:不像以前想象的那么“duh”!) 编辑:lapply 返回一个列表,我们需要将其重新转换为数据框,最后我们修复名称。 sapply 避免了最后一步的需要。
unique_col_names <- unique(colnames(dfr))
new_dfr <- sapply(unique_col_names, function(name)
{
subs <- dfr[, colnames(dfr) == name]
if(is.data.frame(subs))
rowSums(subs)
else
subs
})
【讨论】:
一种方法是使用(惊喜)duplicated 函数来识别重复项,然后遍历它们以计算总和。这是一个例子:
dat.dup <- data.frame(x=1:10, x=1:10, x=1:10, y=1:10, y=1:10, z=1:10, check.names=FALSE)
dups <- unique(names(dat.dup)[duplicated(names(dat.dup))])
for (i in dups) {
dat.dup[[i]] <- rowSums(dat.dup[names(dat.dup) == i])
}
dat <- dat.dup[!duplicated(names(dat.dup))]
【讨论】: