在 R 中有效地设置非常大的数据帧

Posted

技术标签:

【中文标题】在 R 中有效地设置非常大的数据帧【英文标题】:Sub setting very large data frames in R efficiently 【发布时间】:2015-04-30 08:07:29 【问题描述】:

所以我有一个 16 列和约 1700 万行的数据框。

我想先对数据框做一些ddply,然后看看不同列之间的相关性。实现这一目标的最佳和最有效的方法是什么?我目前的方法耗时太长:

数据框为all_df,列名称为ABC、...、NOP

avB <- ddply(all_df, c(“A”), summarise, NB_av=mean(B), NB_sd=sd(B))
avC <- ddply(all_df, c(“A”), summarise, NC_av=mean(C), NC_sd=sd(C))
avD <- ddply(all_df, c(“A”), summarise, ND_av=mean(D), ND_sd=sd(D))
avE <- ddply(all_df, c(“A”), summarise, NE_av=mean(E), NE_sd=sd(E))
avF <- ddply(all_df, c(“A”), summarise, NF_av=mean(F), NF_sd=sd(F))
avG <- ddply(all_df, c(“A”), summarise, NG_av=mean(G), NG_sd=sd(G))

summary_df <- avB
summary_df <- merge(summary_df, avC, by=c(“A”))
summary_df <- merge(summary_df, avD, by=c(“A”))
summary_df <- merge(summary_df, avE, by=c(“A”))
summary_df <- merge(summary_df, avF, by=c(“A”))
summary_df <- merge(summary_df, avG, by=c(“A”))

#quick look at the correlation
plot((summary_df[,c(2,4,6,8,10,12)]), gap=0) 

所以,事实上,我决定在 mysql 中做很多这些,平均值,标准偏差等,然后在 R 中进行最终的关联分析。但是,我觉得这不是很优雅。

为什么我使用数据框而不是数据表?因为我正在读取一个 MySQL 表到 R 中,语法 dbGetQuery(con,"select * from mysql_table") 返回一个数据框。

【问题讨论】:

然后把data.frame转成data.table? 您想要除 1 之外的所有列的均值和标准差吗? 你可以试试dplyr 即。 library(dplyr); all_df%&gt;% group_by(A) %&gt;% summarise_each(funs(mean, sd), B:G) @akrun 如果你可以添加这个作为答案,可能有一些基准测试,我会 +1 :)。 【参考方案1】:

你可以试试

library(dplyr)
 all_df %>% 
       group_by(A) %>% 
       summarise_each(funs(mean, sd), B:G)

或者另一个选项是data.table

library(data.table)
setDT(all_df)[, lapply(.SD, function(x) c(mean(x), sd(x))), by = A,
              .SDcols=LETTERS[2:6]][,var:= c('mean', 'sd')][]

注意:第一种形式的结果是宽格式,而在第二种形式中,我们得到 'mean'、'sd' 作为替代行。

基准测试

 all_df1 <- all_df[rep(1:nrow(all_df), 1e5),]
 system.time(all_df1%>% group_by(A) %>% summarise_each(funs(mean, sd), B:G))
 #  user  system elapsed 
 # 0.189   0.000   0.189 

 DT1 <- as.data.table(all_df1)
 system.time(DT1[,lapply(.SD, function(x) c(mean(x), sd(x))),
              A, .SDcols=LETTERS[2:6]][,var:= c('mean', 'sd')][])
 #  user  system elapsed 
 #0.232   0.002   0.235 

数据

set.seed(25)
m1 <- matrix(sample(1:20, 15*20, replace=TRUE), ncol=15)
set.seed(353)
all_df <- data.frame(sample(letters[1:3], 20, replace=TRUE), m1)
colnames(d1) <- LETTERS[1:ncol(d1)]    

【讨论】:

【参考方案2】:

非常感谢阿克伦!

我根据您的答案编写了一个完整的示例,该示例也借鉴了 http://www.carlboettiger.info/2012/02/12/elegant-fast-data-manipulation-with-data-table.html 它还显示了如何调用由 lapply 生成的对象的特定元素。

#create a super large data frame:
grpsize = ceiling(1e7/26^2)

all_df1 <- data.frame(
            x=rep(LETTERS,each=26*grpsize),
            y=rep(letters,each=grpsize),
            v=runif(grpsize*26^2),
            v2=runif(grpsize*26^2),
            stringsAsFactors=FALSE)

#to group by x and y andget length, mean from data frame
sumalldf <- ddply(all_df1, c("x","y"), summarise, ntotalldf = length(x), nmeanalldf = mean(v))

#convert to data.table
#more efficient way:
DT1 <- data.table(all_df1)

##less efficient way:   
DT2 <- as.data.table(all_df1)

#set keys on x,y columns
setkey(DT1,x,y) # for x only, use: setkey(DT,x)

#setting the key as above allows calling by column value : DT1["A"]
#if you don't setkey and attempt the above, you'll get an error warning you to set key

#take a look at DT1
print(head(DT1))
print(tail(DT1))

#now group data table by x,y and get mean and standard deviation for all other columns
sumalldt <- DT1[,lapply(.SD, function(x) c(mean(x), sd(x))), by= list(x,y)][,var:= c('mean', 'sd')][]
#.SD stands for subset of data, in lay words it applies function (mean, sd) to all columns
#except the by columns

#take a look at this new object that holds the
#mean and standard deviation for all other columns
#after grouping by x,y
print(head(sumalldt))
print(tail(sumalldt)) 

#the keys for sumalldt get set by the 'by' components in lapply
print("some key, attributes etc for sumalldt")
print(key(sumalldt))
print(haskey(sumalldt))

#to get all values for x=B
#sumalldt["B"]

#to get all values for y=r
#sumalldt[list(unique(x),'r')]
#or
#sumalldt[y=="r"] # the former is more efficient

#say then you want to get the values only of x=B, y=r
print(paste("values for x=B, y=r"))
print(sumalldt[list('B','r')])

print("only the mean")
print(subset(sumalldt[list('B','r')],sumalldt[list('B','r')]$var=='mean')$v)
print(subset(sumalldt[list('B','r')],sumalldt[list('B','r')]$var=='mean')$v2)

【讨论】:

以上是关于在 R 中有效地设置非常大的数据帧的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地计算数据帧的行数? [复制]

如何在 hdf5 中有效地保存 python pandas 数据帧并将其作为 R 中的数据帧打开?

非常大的数据帧的有效映射

通过多列中的值有效地在R中闪烁过滤数据帧

更有效地显示非常大的数据集

如何有效地展平Spark数据框中的特征?