将唯一值(在多列中)传播到不同的列并粘贴聚合值
Posted
技术标签:
【中文标题】将唯一值(在多列中)传播到不同的列并粘贴聚合值【英文标题】:Spread unique values (in multiple columns) to different columns and paste aggregated values 【发布时间】:2020-03-12 09:15:24 【问题描述】:我有一个如下的数据框:
structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L,
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L,
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1",
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA,
-4L))
我想使用 data.table 将每列中的唯一值传播到不同的列,并在每列下粘贴总和值(来自“值”列) 例如:列 col1 有 2 个唯一值 A1 和 A2。 A1 之和为 3,A2 为 7 同样,列 col2 有 2 个唯一值 B1 和 B2。 B1之和为5,B2之和为5
此操作将针对 col1、col2 和 col3 中的每一列执行。
预期输出如下
structure(list(A1 = 3, A2 = 7, B1 = 5, B2 = 5, C1 = 1, C2 = 2,
C3 = 3, C4 = 4), class = "data.frame", row.names = c(NA,
-1L))
如何在 R 中实现这一点?
【问题讨论】:
***.com/help/someone-answers 【参考方案1】:data.table
@Sotos 的答案是:
library(data.table)
dcast(melt(setDT(df), 'Value')[, .(Total = sum(Value)), value],
rowid(value)~value, value.var = 'Total')
# value A1 A2 B1 B2 C1 C2 C3 C4
#1: 1 3 7 5 5 1 2 3 4
您可能不需要 value
列,因此您可以通过添加 [, value := NULL][]
来删除它
【讨论】:
heh...我刚刚在DT中完成了但比这更麻烦所以我不会费心添加 也许还有一个更简洁的版本:P 但我也使用更多的tidyverse
而不是 data.table
。
我认为他们将dcast/melt
合二为一,但我可能会将其与reshape2
混淆...不确定
fun.aggregate
中有 fun.aggregate
参数,但我猜它不能按组求和。【参考方案2】:
我不太适应data.table
,但tidyverse
的解决方案可以,
library(dplyr)
library(tidyr)
df %>%
pivot_longer(starts_with('col')) %>%
group_by(value) %>%
summarise(res = sum(Value)) %>%
pivot_wider(names_from = value, values_from = res)
给出,
# A tibble: 1 x 8 A1 A2 B1 B2 C1 C2 C3 C4 <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 3 7 5 5 1 2 3 4
【讨论】:
【参考方案3】:Base R 版本(另一个 data.table 想要的):
t(unstack(
with(reshape(df, direction="long",
varying=grep("^col", names(df), value=TRUE), sep=""),
aggregate(formula=Value~col, FUN=sum)),
form=Value~col))
A1 A2 B1 B2 C1 C2 C3 C4
res 3 7 5 5 1 2 3 4
【讨论】:
【参考方案4】:这是另一种基本的 R 解决方案
dfout <- t(do.call(rbind,
lapply(seq_along(df)[-1],
function(k) unstack(rev(aggregate(Value~.,df[c(1,k)],sum))))))
这样
> dfout
A1 A2 B1 B2 C1 C2 C3 C4
res 3 7 5 5 1 2 3 4
数据
df <- structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L,
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L,
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1",
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA,
-4L))
【讨论】:
我喜欢这个解决方案,但是如果有第 4 列col4
,或者通常更多列怎么办?你会如何修改这个?
@Edward 好问题!那么对于一般情况,您可以使用seq_along(df)[-1]
而不是2:4
。查看我的更新【参考方案5】:
这是另一种选择:
library(data.table)
x <- rbindlist(lapply(paste0("col", 1:3), function(b) df[, sum(Value), b]),
use.names=FALSE)
setDT(setNames(as.list(x$V1), x$col1))[]
数据:
df <- structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L,
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L,
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1",
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA,
-4L))
【讨论】:
【参考方案6】:你也可以这样解决:
library(data.table)
melt(setDT(df), "Value")[, .(TOT = sum(Value)), value][, setNames(as.list(TOT), value)]
# A1 A2 B1 B2 C1 C2 C3 C4
# 1: 3 7 5 5 1 2 3 4
【讨论】:
以上是关于将唯一值(在多列中)传播到不同的列并粘贴聚合值的主要内容,如果未能解决你的问题,请参考以下文章