重复data.frame的行[重复]
Posted
技术标签:
【中文标题】重复data.frame的行[重复]【英文标题】:Repeat rows of a data.frame [duplicate] 【发布时间】:2012-06-22 16:44:31 【问题描述】:我想重复 data.frame 的行,每个 N
次。结果应该是一个新的data.frame
(带有nrow(new.df) == nrow(old.df) * N
),保留了列的数据类型。
N = 2 的示例:
A B C
A B C 1 j i 100
1 j i 100 --> 2 j i 100
2 K P 101 3 K P 101
4 K P 101
因此,每行重复 2 次,字符仍然是字符,因子仍然是因子,数字仍然是数字,...
我第一次尝试使用 apply:apply(old.df, 2, function(co) rep(co, each = N))
,但这一次将我的值转换为字符,我得到:
A B C
[1,] "j" "i" "100"
[2,] "j" "i" "100"
[3,] "K" "P" "101"
[4,] "K" "P" "101"
【问题讨论】:
【参考方案1】:df <- data.frame(a = 1:2, b = letters[1:2])
df[rep(seq_len(nrow(df)), each = 2), ]
【讨论】:
如果你想改变每行重复的次数,你可以使用n.times <- c(2,4) ; df[rep(seq_len(nrow(df)), n.times),]
。【参考方案2】:
一个干净的dplyr
解决方案,取自here
library(dplyr)
df <- tibble(x = 1:2, y = c("a", "b"))
df %>% slice(rep(1:n(), each = 2))
【讨论】:
这是 imo 的首选解决方案,因为它可以在管道中干净地工作。【参考方案3】:有一个可爱的矢量化解决方案,每行仅重复某些行 n 次,例如可以通过在数据框中添加 ntimes
列:
A B C ntimes
1 j i 100 2
2 K P 101 4
3 Z Z 102 1
方法:
df <- data.frame(A=c("j","K","Z"), B=c("i","P","Z"), C=c(100,101,102), ntimes=c(2,4,1))
df <- as.data.frame(lapply(df, rep, df$ntimes))
结果:
A B C ntimes
1 Z Z 102 1
2 j i 100 2
3 j i 100 2
4 K P 101 4
5 K P 101 4
6 K P 101 4
7 K P 101 4
这与 Josh O'Brien 和 Mark Miller 的方法非常相似:
df[rep(seq_len(nrow(df)), df$ntimes),]
但是,这种方法看起来有点慢:
df <- data.frame(A=c("j","K","Z"), B=c("i","P","Z"), C=c(100,101,102), ntimes=c(2000,3000,4000))
microbenchmark::microbenchmark(
df[rep(seq_len(nrow(df)), df$ntimes),],
as.data.frame(lapply(df, rep, df$ntimes)),
times = 10
)
结果:
Unit: microseconds
expr min lq mean median uq max neval
df[rep(seq_len(nrow(df)), df$ntimes), ] 3563.113 3586.873 3683.7790 3613.702 3657.063 4326.757 10
as.data.frame(lapply(df, rep, df$ntimes)) 625.552 654.638 676.4067 668.094 681.929 799.893 10
【讨论】:
我认为这是最通用的解决方案,因为它允许您为每行分配不同数量的复制!我很好奇,有没有办法在 tidyverse 中做到这一点?【参考方案4】:如果您可以重复整个事情,或者先将其子集然后重复,那么this similar question 可能会有所帮助。再次:
library(mefa)
rep(mtcars,10)
或者干脆
mefa:::rep.data.frame(mtcars)
【讨论】:
啊哈!另一个出色的 R 函数隐藏在一个名称完全不相关的不起眼的专家包中。我喜欢这种语言!【参考方案5】:除了@dardisco 提到的mefa::rep.data.frame()
之外,它非常灵活。
您可以将每一行重复 N 次:
rep(df, each=N)
或将整个数据帧重复 N 次(想一想:就像回收矢量化参数时一样)
rep(df, times=N)
为mefa
点赞!直到现在我才听说过它,我不得不编写手动代码来做到这一点。
【讨论】:
【参考方案6】:作为参考和添加引用 mefa 的答案,如果您不想包含整个包,可能值得看看 mefa::rep.data.frame()
的实现:
> data <- data.frame(a=letters[1:3], b=letters[4:6])
> data
a b
1 a d
2 b e
3 c f
> as.data.frame(lapply(data, rep, 2))
a b
1 a d
2 b e
3 c f
4 a d
5 b e
6 c f
【讨论】:
【参考方案7】:rep.row 函数似乎有时会为列创建列表,这会导致内存崩溃。我写了以下似乎效果很好:
library(plyr)
rep.row <- function(r, n)
colwise(function(x) rep(x, n))(r)
【讨论】:
【参考方案8】:我的解决方案类似于mefa:::rep.data.frame
,但速度更快,并且关心行名:
rep.data.frame <- function(x, times)
rnames <- attr(x, "row.names")
x <- lapply(x, rep.int, times = times)
class(x) <- "data.frame"
if (!is.numeric(rnames))
attr(x, "row.names") <- make.unique(rep.int(rnames, times))
else
attr(x, "row.names") <- .set_row_names(length(rnames) * times)
x
比较解决方案:
library(Lahman)
library(microbenchmark)
microbenchmark(
mefa:::rep.data.frame(Batting, 10),
rep.data.frame(Batting, 10),
Batting[rep.int(seq_len(nrow(Batting)), 10), ],
times = 10
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval cld
#> mefa:::rep.data.frame(Batting, 10) 127.77786 135.3480 198.0240 148.1749 278.1066 356.3210 10 a
#> rep.data.frame(Batting, 10) 79.70335 82.8165 134.0974 87.2587 191.1713 307.4567 10 a
#> Batting[rep.int(seq_len(nrow(Batting)), 10), ] 895.73750 922.7059 981.8891 956.3463 1018.2411 1127.3927 10 b
【讨论】:
【参考方案9】:尝试使用例如
N=2
rep(1:4, each = N)
作为索引
【讨论】:
【参考方案10】:另一种方法是首先获取行索引,附加 df 的额外副本,然后按索引排序:
df$index = 1:nrow(df)
df = rbind(df,df)
df = df[order(df$index),][,-ncol(df)]
虽然其他解决方案可能更短,但这种方法在某些情况下可能更有利。
【讨论】:
以上是关于重复data.frame的行[重复]的主要内容,如果未能解决你的问题,请参考以下文章