如何按多列的值重复行并重新划分

How to repeat rows by their value by multiple columns and divide back

假设我有这个数据框:

> df <- data.frame(A=1:5, B=c(0, 0, 3, 0, 0), C=c(1, 0, 0, 1, 0), D=c(0, 2, 0, 0, 1))
> df
  A B C D
1 1 0 1 0
2 2 0 0 2
3 3 3 0 0
4 4 0 1 0
5 5 0 0 1

我如何将其转换为:

  A B C D
1 1 0 1 0
2 2 0 0 1
3 2 0 0 1
4 3 1 0 0
5 3 1 0 0
6 3 1 0 0
7 4 0 1 0
8 5 0 0 1

如您所见,有值 23,我想按该长度重复它们并将值改回 1。我该怎么做?

如您所见,我还想复制 A 列。

我试过了:

replace(df[rep(rownames(df), select(df, -A)),], 2, 1)

但是它给我一个错误。

一个选项是使用 pmaxBCD 列中获取最大值,使用 uncount 重复这些行。使用pmin将大于1的值替换为1.

library(dplyr)
library(tidyr)

df %>%
  mutate(repeat_row = pmax(B, C, D)) %>%
  uncount(repeat_row) %>%
  mutate(across(-A, pmin, 1))

#  A B C D
#1 1 0 1 0
#2 2 0 0 1
#3 2 0 0 1
#4 3 1 0 0
#5 3 1 0 0
#6 3 1 0 0
#7 4 0 1 0
#8 5 0 0 1

只是稍微修改一下 Ronak Shah 的回答,我意识到你可以只用 dplyr:

library(dplyr)

df[rep(rownames(df), apply(select(df, -A), 1, max)),] %>%
  as.data.frame(row.names=1:nrow(.)) %>%
  mutate(across(-A, pmin, 1))

输出:

  A B C D
1 1 0 1 0
2 2 0 0 1
3 2 0 0 1
4 3 1 0 0
5 3 1 0 0
6 3 1 0 0
7 4 0 1 0
8 5 0 0 1

rowSums:

library(dplyr)

df[rep(rownames(df), rowSums(select(df, -A)),] %>%
  as.data.frame(row.names=1:nrow(.)) %>%
  mutate(across(-A, pmin, 1))

显然,B 到 D 列中只有一个值 > 0,因此我们可以利用部分 rowSums 对使用 > 0 二值化的 B 到 D 列进行 replicate 调用.为了我们可以在 Map 中使用它,我们 transpose 两次。休息是化妆品。

t(do.call(cbind, Map(replicate,
                     rowSums(df[-1]), 
                     as.data.frame(t(cbind(df[1], df[-1] > 0)))))) |>
  as.data.frame() |>
  setNames(names(df))
#   A B C D
# 1 1 0 1 0
# 2 2 0 0 1
# 3 2 0 0 1
# 4 3 1 0 0
# 5 3 1 0 0
# 6 3 1 0 0
# 7 4 0 1 0
# 8 5 0 0 1

注: R>=4.1 used.