作者celestialgod (天)
看板R_Language
标题Re: [问题] data.frame资料处理
时间Tue Sep 15 21:59:29 2015
原问题:
想进一步请问
在一个data.frame中
No1消费者 有A B C D四种消费时间点
A1代表No1 在第一次消费时点的消费金额
A2 A3 A4 A5代表No1第一次消费时点的其他状态(停留时间、点击商品数量..等˙)
B1 代表No1 在第二次消费时点的消费金额
B2 B3 B4 B5代表No2第二次消费时点的其他状态
欲拿掉消费金额<5的群组
(即判断每个群组的第一位是否<5,若<5,则将其消费伴随的状态也移除)
剩余的往左靠齐
No A1 A2 A3 A4 A5 | B1 B2 B3 B4 B5 | C1 C2 C3 C4 C5 | D1 D2 D3 D4 D5
1 5 6 3 2 1 | 10 11 12 13 14 | 1 1 2 3 4 | 5 5 5 5 9
2 1 2 3 4 5 | 1 1 1 1 1 | 5 8 7 6 5 | 5 3 2 1 0
第一位消费者的A1 B1 D1 >=5 则留下ABD三个群组
第二位消费者的C1 D1 >=5 则留下CD 两个群组
靠右平移 成为以下table
| | |
No A1 A2 A3 A4 A5 | B1 B2 B3 B4 B5 | C1 C2 C3 C4 C5 | D1 D2 D3 D4 D5
1 5 6 3 2 1 | 10 11 12 13 14 | 5 5 5 5 9 |
2 5 8 7 6 5 | 5 3 2 1 0 | |
我不清楚你原始的column name是否这麽regular...
我定义一个block就是相同名称开头的名称,
例如: A1~A5这样称做一个block,B1~B5亦是一个block
我的目标就是根据block的第一个元素去把该block设定为0或是不是0
block设定成0之後就回到你原本的左移案子了~~
但是要执行这个基本上就是只能用eval了...
因为有太多column不可能,手动去处理这些column
因此,我给了两个eval方式
一个是用mutate_,另一个是单纯的eval
我个人是觉得单纯的eval难写满多的
但是mutate_要需要相对多的东西才能累积出来...
所以我无法肯定哪一个方法比较好
我自己本身对於mutate_这函数跟lazyeval这个套件都没有很熟悉
下面的程式提供参考
好读的程式码:
http://pastebin.com/NCAvfmfP
library(data.table)
library(dplyr)
library(magrittr)
N = 10
T = 5
nItem = 4
m = matrix(rbinom(N*T*nItem, 15, 0.4), N)
dat = data.table(id = 1:nrow(m), m) %>%
setnames(paste0("V",1:20), paste0(rep(LETTERS[1:nItem],,, T),
rep(1:T, nItem)))
varChecking = names(dat)[grepl("[A-Z]1", names(dat))]
f = function(x) ifelse(x < 5, 0, x)
dat_out = mutate_each_(dat, funs(f), varChecking)
namesWorking = gsub("([A-Z])1", "\\1", varChecking)
varsWorking = paste0(rep(namesWorking,,,T-1), rep(2:T,nItem))
## method 1
cmd = paste0('ifelse(', rep(namesWorking,,,T-1), '1<5,0,', varsWorking, ')')
mutate_(dat_out, .dots= setNames(lapply(cmd, lazyeval:::interp), varsWorking))
## method 2
eval(parse(text = paste0('dat_out=mutate(dat_out,',
paste0(varsWorking, '=ifelse(', rep(namesWorking,,,T-1), '1<5,0,',
varsWorking, ')', collapse = ","), ')')))
最後提供一个简单的方法,但是我怕记忆会爆掉XD
varWorking = gsub('([A-Z])\\d', '\\1', names(dat)) %>%
unique %>% setdiff('id')
llply(varWorking, function(x){
tmp_dat = dat %>% select(starts_with(x))
tmp_dat %<>% setnames(paste0("V", 1:ncol(tmp_dat)))
f = function(x) ifelse(tmp_dat$V1 > 5, x, 0)
tmp_dat %<>% mutate_each(funs(f)) %>%
setnames(paste0(x, 1:ncol(tmp_dat)))
tmp_dat
}) %>% bind_cols %>% tbl_dt %>% mutate(id = dat$id)
最後补一个执行时间
N = 20000; T = 10; nItem = 1000
method 1: 68.03
method 2: 66.75
method 3: 53.87
测试程式码:
http://pastebin.com/HbVzPh6D
基本上,method 1跟method 2差不多,method 3用空间换时间
所以看你的data.frame大小跟你的记忆体来选适合你的方法吧
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 123.205.27.107
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/R_Language/M.1442325572.A.8B0.html
1F:推 thephone: 谢谢C大 内容对我来讲有深度 要好好研究一下09/16 00:22
对我来说,也不简单,我自己不知道有没有方法更快。
※ 编辑: celestialgod (123.205.27.107), 09/16/2015 00:30:29