如何在R中对数据帧进行分组
我有这样一个大数据框: df: 我想很快地把它分成几个小组: df_1: df_2: 我知道有一种方法是这样的:如何在R中对数据帧进行分组,r,large-data,R,Large Data,我有这样一个大数据框: df: 我想很快地把它分成几个小组: df_1: df_2: 我知道有一种方法是这样的: df_1 <- df[df == 1] df_2 <- df[df == 2] 但它并不快。 我该怎么办 感谢提供dplyr和tidyr选项: 欢迎来到SO 我建议看一下dplyr和data.table包,它们专注于快速和内存高效的实现。特别是我要建议的惊人的答案,这将有助于更好地理解这两个包的功能 随着组和重复子集数量的增加,data.table确实会优于dplyr,
df_1 <- df[df == 1]
df_2 <- df[df == 2]
但它并不快。
我该怎么办
感谢提供dplyr和tidyr选项:
欢迎来到SO
我建议看一下dplyr和data.table包,它们专注于快速和内存高效的实现。特别是我要建议的惊人的答案,这将有助于更好地理解这两个包的功能
随着组和重复子集数量的增加,data.table确实会优于dplyr,因为它使用索引和键控子集,但对于大多数情况,它归结为一种偏好。专注于子集,我将提供一个可复制的示例和一些速度比较
可复制示例
dplyr方法
另一种选择是dplyr包。dplyr是语法糖,提供了管道选项,与其他一些包(例如包)没有什么不同,但本文中显示的不同基准表明,该包可以用于提高各个方面的性能。然而,我不是这个软件包的专家,因为我倾向于使用data.table软件包。该软件包提供%>%管道功能和一些实用功能,如可用于子集数据的过滤器
library(dplyr)
df %>% filter(group == "C")
# subsetting two columns
df %>% filter(group == "C", random_binaries == TRUE) #Equivalent to group == "C" & random_binaries == TRUE
数据表方法:
最后一个流行的软件包是软件包。这个包是为性能和内存效率而设计的,就像dplyr一样。语法设计类似于SQL语句,select、from、where、group by,但开始使用语法可能会有点混乱。该包提供了一个新的data.table类,以供使用,而不是data.frame类,后者的子集设置速度非常慢
但是,几乎可以完全忽略包的语法,因为data.table在大多数情况下使用data.frame语法,并且在任何情况下都可以用作data.frame
library(data.table)
#Convert the data.frame to data.table
setDT(df)
data.table有两种标准方法:使用索引和使用键。如果使用与data.frame方法类似的方法,则使用索引:
语法可能会让人困惑,但你可以看看它们的有用之处,或者今天的8968,它们为大多数问题提供了答案
性能比较
我已经检查了下面显示的子集方法的性能。可视化显示了使用所示方法为group==C和group==H&random_二进制文件==TRUE的子集显示的各种方法。x轴以毫秒为单位指示运行时间,y轴显示方法。
斑点的宽度表示范围,而斑点的大小表示范围内的时间密度
从可视化中可以看出,对于一个包含2列的数据集,在1列和2列上都进行子集设置,使用键的data.table方法标记为data.table_u键的速度要快得多,而使用索引的速度略优于其他方法。使用子集的速度比标准方法慢,令人惊讶的是,在本例中,dplyr比base-R慢,但这可能是因为我对该软件包缺乏经验
这里有一种使用BaseR中的Lappy的方法,它可以为您提供所需数据帧的列表-
df <- data.frame(col_1 = 1, col_2 = 2, col_3 = 1)
lapply(unique(unlist(df)), function(x) {
df[, df == x, drop = F]
})
# output
[[1]]
col_1 col_3
1 1 1
[[2]]
col_2
1 2
您的数据中只有一行吗?如果没有,你能再增加几行,并在此基础上显示预期的输出吗?我只有一行@RonakShahI认为t应该类似于df%>%gatherkey,val%>%group_splitval至少在我的机器上仍然没有达到OP的预期输出。@agila修复了我认为的itor。似乎OP更感兴趣的是按val分组,而不是按键分组,第二眼看到的是你们在那个里写的东西,我错过了。更正了,谢谢。
df %>%
tidyr::gather(key,val) %>%
group_split(val) #attributed to @agila for pointing out the unnenecessary call to group_by that I missed initially
[[1]]
# A tibble: 2 x 2
key val
<chr> <int>
1 col_1 1
2 col_3 1
[[2]]
# A tibble: 1 x 2
key val
<chr> <int>
1 col_2 2
attr(,"ptype")
set.seed(1)
df <- data.frame(group = sample(LETTERS, 1e7, TRUE),
random_numbers = rnorm(1e7),
random_binaries = rbinom(1e7, 1, 0.3))
# size = 152.6 MiB
format(object.size(df), units = "MiB")
df[df$group == "C",]
#Equivalent
df[which(df$group == "C"),]
#Equivalent
subset(df, group == "C")
library(dplyr)
df %>% filter(group == "C")
# subsetting two columns
df %>% filter(group == "C", random_binaries == TRUE) #Equivalent to group == "C" & random_binaries == TRUE
library(data.table)
#Convert the data.frame to data.table
setDT(df)
df1 <- df[random_binaries == TRUE]
df2 <- df[group == "C"]
#Set the key using either setkey, or setkeyv (multiple columns)
setkeyv(df, c("group", "random_binaries"))
#Subset on group
df[.("C")]
#subset on random_binaries
df[CJ(group, TRUE, unique = TRUE)]
df[.(unique(group), TRUE)]
# Subset on multiple conditions
df[.(c("C", "H"), c(TRUE, TRUE))]
df <- data.frame(col_1 = 1, col_2 = 2, col_3 = 1)
lapply(unique(unlist(df)), function(x) {
df[, df == x, drop = F]
})
# output
[[1]]
col_1 col_3
1 1 1
[[2]]
col_2
1 2