输入数据:
> head(iris[c(48:50, 98:100), 3:5])
Petal.Length Petal.Width Species
48 1.4 0.2 setosa
49 1.5 0.2 setosa
50 1.4 0.2 setosa
98 4.3 1.3 versicolor
99 3.0 1.1 versicolor
100 4.1 1.3 versicolor
输出数据:
setosa.Petal.Length versicolor.Petal.Length setosa.Petal.Width versicolor.Petal.Width
1.4 4.3 0.2 1.3
1.5 3.0 0.2 1.1
1.4 4.1 0.2 1.3
使用例如:
spread(
iris%>%mutate(n=row_number()),
key=Species,
value=Petal.Length:Petal.Width)
#or c("Petal.Length", "Petal.Width")`
不起作用
答案 0 :(得分:2)
碰到了这一点,并对“大型数据集”的提及感到好奇。作为Tidyverse所有东西的狂热粉丝,我在不断地使用大型套装时,我是实际的基准性能。对于这个例子,这就是我想出的,这有点令人担忧的是使用基本包函数而不是使用tidyverse调用的管道。
复制虹膜数据集以伪造更大的数据集。
iris_1000 <- plyr::ldply(1:1000, function(i){
iris
})
尺寸为150,000行乘5列:
dim(iris_1000)
[1] 150000 5
因此,这将代表一个大小为的数据集:
sprintf("%s MB", object.size(iris_1000) * 0.001^2)
[1] "5.401688 MB"
在函数调用中包装提供的anser以进行测试但是更改以便它适用于所有列,而不仅仅是那些包含'Petal'并且还删除索引列并作为数据框返回的列
tidy_fn <- function(){
iris_1000 %>%
gather(key, value, -Species) %>%
unite(tmp, Species, key, sep=".") %>%
group_by(tmp) %>%
mutate(indx = row_number()) %>%
spread(tmp, value) %>%
select(-indx) %>% data.frame
}
功能主要使用基础包提供的功能并进行输入 数据框作为'df'变量和数据的列名 汇总,或者在我们的案例中分开
baseish_fn <- function(df, col_split){
df_split <- split(df, df[[col_split]])
df_loop <- lapply(names(df_split), function(i){
iter_df <- df_split[[i]][-which(colnames(df_split[[i]]) == col_split)]
new_names <- sprintf("%s.%s", i, colnames(iter_df))
colnames(iter_df) <- new_names
iter_df
})
names(df_loop) <- NULL
as.data.frame(df_loop)
}
现在速度比较令人惊讶...... 需要注意的是,baseish函数中的列名将被安排为 匹配tudy函数的返回col排列以供稍后比较 值如此运行一次才能得到
tidy_val_test <- tidy_fn()
microbenchmark::microbenchmark(
tidyverse = tidy_fn(),
`base-ish` = baseish_fn(iris_1000, "Species")[colnames(tidy_val_test)],times = 100L
)
Unit: milliseconds
expr min lq mean median uq max neval
tidyverse 378.46753 419.93116 447.8020 438.5375 466.78367 718.9666 100
base-ish 76.57918 83.21915 92.8109 87.8329 94.58085 342.2290 100
确保他们产生相同的产出:
all(mapply(function(i){
identical(tidyverse[[i]], `base-ish`[[i]])
},colnames(tidyverse)))
[1] TRUE
head(`base-ish`[1:4,1:5])
setosa.Sepal.Length setosa.Sepal.Width setosa.Petal.Length setosa.Petal.Width
1 5.1 3.5 1.4 0.2
2 4.9 3.0 1.4 0.2
3 4.7 3.2 1.3 0.2
4 4.6 3.1 1.5 0.2
versicolor.Sepal.Length
1 7.0
2 6.4
3 6.9
4 5.5
答案 1 :(得分:0)
我正在写我的答案,直到我看到David Arenburg出色的评论,然后我用他的答案调整了答案。
我明白了:
df <- iris %>%
select(c(starts_with("Petal"), Species)) %>%
gather(key, value, -Species) %>%
unite(tmp, Species, key, sep=".") %>%
group_by(tmp) %>%
mutate(indx = row_number()) %>%
spread(tmp, value)
我不知道unite()
功能,这是主要区别。
Obs:由于我不能发表评论,我需要发帖作为答案,如果你觉得我在偷你的答案,我可以删除它。