我有一个像这样的矩阵
P A B C
1 2 0 5
2 1 1 3
3 0 4 7
1 1 1 0
3 1 1 0
3 0 2 1
2 3 3 4
我想按P和每个列合并/排序行。因此,每个P值为每列一次,并且每列中每个P的值相加。结果应该是:
P A B C
1 3 0 0
1 0 1 0
1 0 0 5
2 4 0 0
2 0 4 0
2 0 0 7
3 1 0 0
3 0 7 0
3 0 0 8
我已经尝试了aggregate
但它只能帮助我总结所有列的每个P值,以便每个P只有一行。
答案 0 :(得分:4)
一个想法是在P
上拆分数据框并应用自定义函数(fun1
),该函数创建一个0的矩阵,并用列的总和替换对角线。即。
fun1 <- function(x){
m1 <- matrix(0, ncol = ncol(x) - 1, nrow = ncol(x) - 1)
diag(m1) <- sapply(x[-1], sum)
return(m1)
}
l1 <- split(df, df$P)
do.call(rbind, lapply(l1, fun1))
# [,1] [,2] [,3]
# [1,] 3 0 0
# [2,] 0 1 0
# [3,] 0 0 5
# [4,] 4 0 0
# [5,] 0 4 0
# [6,] 0 0 7
# [7,] 1 0 0
# [8,] 0 7 0
# [9,] 0 0 8
或者为了得到你想要的输出,那么
final_df <- as.data.frame(cbind(rep(names(l1), each = ncol(df)-1),
do.call(rbind, lapply(l1, fun1))))
names(final_df) <- names(df)
final_df
# P A B C
#1 1 3 0 0
#2 1 0 1 0
#3 1 0 0 5
#4 2 4 0 0
#5 2 0 4 0
#6 2 0 0 7
#7 3 1 0 0
#8 3 0 7 0
#9 3 0 0 8
答案 1 :(得分:3)
我们从&#39; P&#39;中获得频率计数的最大值。列(&#39; i1&#39;),aggregate
按&#39; P&#39;分组的列获取sum
(&#39; df2&#39;),复制&#39; df2&#39;的行。通过&#39; i1&#39;,split
数据集按&#39; P&#39;并将其他列中的非对角元素更改为0并将其作为data.frame
,order
返回,并将行名称更改为NULL。
i1 <- max(table(df1$P))
df2 <- aggregate(.~P, df1, sum)
df3 <- df2[rep(1:nrow(df2), i1)]
res <- unsplit(lapply(split(df3, df3$P), function(x) {
x[-1] <- diag(3)*x[-1]
x}), df3$P)
res1 <- res[order(res$P),]
row.names(res1) <- NULL
res1
# P A B C
#1 1 3 0 0
#2 1 0 1 0
#3 1 0 0 5
#4 2 4 0 0
#5 2 0 4 0
#6 2 0 0 7
#7 3 1 0 0
#8 3 0 7 0
#9 3 0 0 8
或使用data.table
,转换&#39; data.frame&#39;到&#39; data.table&#39; (setDT(df1)
),遍历Data.table(.SD
)的子集,获取sum
,按&#39; P&#39;分组,复制汇总数据集的行并将非对角元素更改为0(如第一个解决方案中所述)。
library(data.table)
setDT(df1)[, lapply(.SD, sum), by = P
][rep(1:.N, i1)
][, .SD*diag(ncol(df1)-1), by = P]
# P A B C
#1: 1 3 0 0
#2: 1 0 1 0
#3: 1 0 0 5
#4: 2 4 0 0
#5: 2 0 4 0
#6: 2 0 0 7
#7: 3 1 0 0
#8: 3 0 7 0
#9: 3 0 0 8
或使用dplyr
library(dplyr)
library(purrr)
d1 <- as.data.frame(diag(i1))
df2 <- df1 %>%
group_by(P) %>%
summarise_each(funs(sum)) %>%
replicate(i1, ., simplify = FALSE) %>%
bind_rows() %>%
arrange(P)
df2[-1] <- map2(df2[-1], d1, ~.x * .y)
df2
# A tibble: 9 × 4
# P A B C
# <int> <dbl> <dbl> <dbl>
#1 1 3 0 0
#2 1 0 1 0
#3 1 0 0 5
#4 2 4 0 0
#5 2 0 4 0
#6 2 0 0 7
#7 3 1 0 0
#8 3 0 7 0
#9 3 0 0 8
答案 2 :(得分:3)
另一个想法是使用diag
函数本身来创建矩阵。然后你可以将这些矩阵组合在一起。
xx=aggregate(. ~ P, df, sum)
yy=xx[,-1]
yy=as.data.frame(t(yy))
cbind(rep(1:ncol(yy),nrow(yy)),do.call("rbind", lapply(yy, function(xx) diag(xx, nrow = nrow(yy), ncol = nrow(yy)))))
[,1] [,2] [,3] [,4]
[1,] 1 3 0 0
[2,] 2 0 1 0
[3,] 3 0 0 5
[4,] 1 4 0 0
[5,] 2 0 4 0
[6,] 3 0 0 7
[7,] 1 1 0 0
[8,] 2 0 7 0
[9,] 3 0 0 8
答案 3 :(得分:1)
除非我遗漏了某些东西,否则以下内容看起来也是有效的。 首先计算每个“P”的总和:
s = as.matrix(rowsum(dat[-1], dat$P))
创建最终矩阵:
k = s[rep(1:nrow(s), each = ncol(s)), ]
计算索引以替换为“0”:
k[col(k) != (row(k) - 1) %% ncol(k) + 1] = 0
k
# A B C
#1 3 0 0
#1 0 1 0
#1 0 0 5
#2 4 0 0
#2 0 4 0
#2 0 0 7
#3 1 0 0
#3 0 7 0
#3 0 0 8
数据:
dat = structure(list(P = c(1L, 2L, 3L, 1L, 3L, 3L, 2L), A = c(2L, 1L,
0L, 1L, 1L, 0L, 3L), B = c(0L, 1L, 4L, 1L, 1L, 2L, 3L), C = c(5L,
3L, 7L, 0L, 0L, 1L, 4L)), .Names = c("P", "A", "B", "C"), class = "data.frame", row.names = c(NA,
-7L))
计算出s
后,user20650更直接的选择:
matrix(diag(ncol(s)), nrow(s) * ncol(s), ncol(s), byrow = TRUE) * c(t(s))
或者,同样,在同一个想法上搞乱其他有趣的选择:
kronecker(rep_len(1, nrow(s)), diag(ncol(s))) * c(t(s))
diag(ncol(s))[rep(1:ncol(s), nrow(s)), ] * s[rep(1:nrow(s), each = ncol(s)), ]