Re: [问题] 处理资料 效能询问

楼主: celestialgod (天)   2016-07-08 09:44:17
※ 引述《spiderway (spiderway)》之铭言:
: ※ 引述《spiderway (spiderway)》之铭言:
: : - 问题: 当你想要问问题时,请使用这个类别
: : [问题类型]:
: : 效能咨询(我想让R 跑更快)
: : [软件熟悉度]:
: : 入门(写过其他程式,只是对语法不熟悉)
: : [问题叙述]:
: : 大家好,
: : 最近因为需要要处理一些资料,虽然有写出要的东西,但是实在是跑太慢了,感觉要跑个
: : 几年= =,一定是我写法不好,想来这问一下各位大大该怎个改才对,并学习一下
: : 麻烦各位大大给予小鲁指导,感激不尽!!!
: : 程式:
: : 读取了全部CSV(10万多个)存在一个大大的list里面,要做的大概是把每一个list里面的
: : 资料都做同一件事,就是每5笔整理成1笔,然后append在一起,如下
: : 1 2 3 4 5 6 1 2 3 ....
: : 1 6/1 a b 12 1 2 1 6/1 a b 12 1 2 13 1 3 14 1 4 15 1 5 16 1 6
: : 2 6/1 a b 13 1 3
: : 3 6/1 a b 14 1 4 变成1笔>>>
: : 4 6/1 a b 15 1 5
: : 5 6/1 a b 16 1 6
: : [程式范例]:
: : http://pastie.org/10898589
: : [版本]
: : R version 3.3.0 (2016-05-03)
: : Platform: x86_64-pc-linux-gnu (64-bit)
: : Running under: Ubuntu 14.04.4 LTS
: : [关键字]:
: 解说一下我的资料型态
: CSV档10万个,每一个大概有2000~3000多列不等,但一定是5个倍数
: 但是他的资料都是5列一组,所以我才会希望第一篇说得让他5个整理成一列
: 前面会有V1~V3分别是 时间和AB两个属性,前五笔都是一样的,V4~V6是我要处理的。
: 我上次是选C板大的教学使用,但是因为之前都不常用过dply那些,不太会用
: 用到csv_append之后是没问题,但是在data那边是个list我想要的是一个值
: 一行,所以最后的资料希望是像这样,最后存成一个csv,因为我之后还要在处理一个类
: 似的资料,只有后面不一样,再合并在一起。
: V1 V2 V3 V4 ... V18
: 时间1 A1 B1 (整理的那5 rows合并的)1
: 时间2 A2 B2 (整理的那5 rows合并的)2
: .
: .
: .
: 我现在面临的问题,
: 1,do.call(rbind,csv_append)大概下午跑到隔天早上,但至少跑好了XD
: 2,data那边是list我不太理解是不是能够直接转
: 2,我后来有想到办法,我发现我都只会这种处理方法...
: http://pastie.org/10901154
: 是可以把每一个都转成我要的之后在做do.call rbind
: 在请大大帮忙了 谢谢~~~~~~
: 心得:谢谢各位大大的帮忙,虽然我很多function都看不太懂= =
: 而且发现好像apply系列很好用欸,之前都一直觉得用for就好了,真的遇到资料量变大差
: 别真多...,之后应该好好找时间重读一下apply系列和dply那些
我就用三千笔测试就好,下面是三种不同方法:
好读版:http://pastebin.com/GPgR4FSc
library(pipeR)
library(plyr)
library(dplyr)
library(tidyr)
# data generation (csv_files就是你的ldf)
num_csv <- 3e3
num_xlvls <- 30
num_ylvls <- 30
timePoints <- expand.grid(paste0("a", 1:num_xlvls),
paste0("b", 1:num_ylvls),
stringsAsFactors = FALSE)
csv_files <- lapply(1:num_csv, function(i){
dat <- sample(1:nrow(timePoints), sample(400:600, 1)) %>>%
rep(each = 5) %>>% (timePoints[., ]) %>>%
modifyList(setNames(lapply(1:3, function(j){
sample(1:100, nrow(.), TRUE)
}), paste0("Var", 3:5))) %>>% tbl_df
})
# 整并 + 分开
st <- proc.time()
outRes1 <- lapply(csv_files, function(subdf){
nest(subdf, -Var1, -Var2) %>>%
mutate(data = lapply(data, function(x){
as.matrix(x) %>>% t %>>% as.vector %>>% paste(collapse = ";")
})) %>>% unnest(data) %>>% separate(data, paste0("V", 1:15)) %>>%
mutate_each(funs(as.integer(.)), -Var1, -Var2)
}) %>>% bind_rows
proc.time() - st
# user system elapsed
# 263.93 0.02 265.86
st <- proc.time()
outRes2 <- lapply(csv_files, function(subdf){
subdf %>>% gather(vars, values, -Var1, -Var2) %>>%
group_by(Var1, Var2) %>>%
summarise(tmp = paste(values, collapse = ";")) %>>% ungroup %>>%
separate(tmp, paste0("V", 1:15)) %>>%
mutate_each(funs(as.integer(.)), -Var1, -Var2)
}) %>>% bind_rows
proc.time() - st
# user system elapsed
# 70.01 0.00 70.25
library(data.table)
st <- proc.time()
outRes3 <- lapply(csv_files, function(subdf){
subdf %>>% data.table %>>% melt(c("Var1", "Var2")) %>>%
`[`( , list(tmp = paste(value, collapse = ";")), by = c("Var1", "Var2"))%>>%
`[`( , `:=`(paste0("V", 1:15), tstrsplit(tmp, ";"))) %>>%
`[`( , tmp := NULL) %>>%
`[`( , `:=`(paste0("V", 1:15), lapply(.SD, as.integer)), .SDcols = V1:V15)
}) %>>% rbindlist
proc.time() - st
# user system elapsed
# 37.35 1.30 38.16
第一个方法只是把我原本方法做一个修正,但是nest跟unnest实在太花时间
而且没有必要,所以就有了第二个版本直接把资料直接做合并的动作
虽然快了四倍,但是速度还可以更快,所以就有了第三个版本
(测了一下内存使用量已经很低)
我最近开始往回走,虽然dplyr好用,但是data.table在处理资料还是有他的优势
在第三个方法可以看到,硬是比dplyr的解法快了一倍,但是相对写起来就没那么漂亮
这个是code style跟效能的取舍(摊手
另外,我一万个csv就会出问题了... 内存真没那么大...
如果你内存真的有很大在考虑这样做,没那么大可以考虑分段读取
分段写入时,在append就好,不过之后读进来又很麻烦(摊手
以上,敬请参考~~~
OS: 难得的台风假阿~~~ 大家请注意自身安全!!
7/8 11:00补上data.table把V1~V15转成integer

Links booklink

Contact Us: admin [ a t ] ucptt.com