作者celestialgod (天)
看板R_Language
标题Re: [问题] 如何更有效率的整理data的问题?
时间Tue Jan 31 17:42:25 2017
※ 引述《phil5566 (5566)》之铭言:
: [问题类型]:
: 效能谘询(我想让R 跑更快)
: [软体熟悉度]:
: 新手(没写过程式,R 是我的第一次)
: [问题叙述]:
: 小弟自己产生一组data叫做"T"的矩阵,
: 想把其中"T"的第5行(T[,5])和第6行(T[,6])的数据,
: 挑出来整理成一个120X3的矩阵,假设叫"G",
: T[,5]的数值有10,16,22,28,34,40,6个可能,
: T[,6]的数值有0.5,1.5,2.5,.........,19.5和inf的可能,
: 整理方法:
: G的第一行(G[,1]):放0.5,1.5,....,19.5(20个数,6个循环,共120个)
: G的第二行(G[,2]):放的东西比较麻烦,即
: T[,5]=10的情况下,对应到T[,6]那些0.5,1.5,.....,19.5,inf的数值
: 计算他们的累积比率,假设T[,5]=10,有100笔data,
: T[,5]=10且T[,6]<=0.5(或者T[,6]<=1)有22笔,
: 则它算出的累积比率为22/100=0.22,依此类推...,
: 算到T[,5]=10且T[,6]<=19.5(或者T[,6]<=20)的累积比率
: 共20个数字放到G[1:20,2],重复以上模式处理T[,5]=16,22,28,34,40的情形
: 分别放到G[21:40,2],G[61:80,2],.....,G[101:120,2]
: G的第三行(G[,3]):G[1:20,3]放10,G[21:40,3]放16,......G[101:120,3]放40
: ________________________________________________________________________
: 小弟之前是用table函数处理,
: 直接table(T[,5],T[,6])得到分类结果
: 再分别计算累积比率,没用到廻圈,
: 但考虑到"假设T[,6]可能没有出现5.5的情况",
: table函数分类後就不会有5.5的这个分类,
: 所以小弟又重新写,用两个廻圈来整理data,
: 第一个廻圈是在处理G[,1]和G[,3],第二个廻圈在处理G[,2]
: 以下附上code范例,
: 想请教版上各位高手,大大有没有更漂亮,快速的处理方法,
: 指教了,谢谢~
: [程式范例]:
: http://pastebin.com/bw0C2YNJ
: [环境叙述]:
: R x64 3.3.1
: [关键字]:
: data整理
# generage T[,5]跟T[,6]
targetMat <- cbind(sample(c(10,16,22,28,34,40), 2e4, TRUE),
sample(c(seq(0.5,19.5,by = 1), Inf), 2e4, TRUE))
# 取unique的T[,5]
g1 <- unique(targetMat[ , 1])
# 取T[,6] min ~ max(除去Inf),间隔1的序列,共20个
g2 <- seq(min(targetMat[ , 2]), max(targetMat[is.finite(targetMat[,2]), 2]),
by = 1)
# 展开g1跟g2,并加一行转成矩阵
outputDF <- expand.grid(g1, g2)
outputMat <- as.matrix(cbind(outputDF[order(outputDF$Var1, outputDF$Var2), ],
0))
# 用tapply计算每一个g1, g2对应的次数,第一个input随意放即可,没用到,我这里放1
resMat <- tapply(rep(1, nrow(targetMat)),
list(targetMat[,1], targetMat[, 2]), length)
# 用cumsum算出累积次数,再用sweep算累积比率
# 最後再把矩阵拉直,变成outputMat的第三行
outputMat[ , 3] <- as.vector(sweep(apply(resMat[ , 1:20], 1, cumsum), 2,
rowSums(resMat), `/`))
最後一行可能要花时间消化一下,先从
apply(resMat[ , 1:20], 1, cumsum) 看起
然後去看sweep用法
看一下 rowSums(resMat) 代表的意义
组合起来就是你要的累积比率
另外要注意我有先对outputMat排序,才能直接放进去
再写的时候要注意顺序错了,塞进去的结果就会不对了
--
R资料整理套件系列文:
magrittr #1LhSWhpH (R_Language) https://goo.gl/72l1m9
data.table #1LhW7Tvj (R_Language) https://goo.gl/PZa6Ue
dplyr(上.下) #1LhpJCfB,#1Lhw8b-s (R_Language) https://goo.gl/I5xX9b
tidyr #1Liqls1R (R_Language) https://goo.gl/i7yzAz
pipeR #1NXESRm5 (R_Language) https://goo.gl/zRUISx
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 118.170.46.59
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/R_Language/M.1485855748.A.626.html
1F:推 phil5566: 谢谢C大回答~这个方法蛮厉害的,完全没用到廻圈 01/31 22:21
2F:→ phil5566: 但还是有几点疑问?您说的outputMat排序是指 01/31 22:23
3F:→ phil5566: order(outputDF$Var1, outputDF$Var2)吧?order(X,Y)排序 01/31 22:24
4F:→ phil5566: 原则是否先比X再比Y,比完後越小的放越前面? 01/31 22:26
对,相比X再比Y,预设是increasing or ascending排序
5F:推 phil5566: 最後一行我还可以理解,只是tapply那一行就看不太懂? 01/31 22:29
6F:→ phil5566: google"tapply"的用法还是有看没有懂,能否麻烦C大解说一 01/31 22:30
tapply(x, y, fun):
x是目标向量
y可以是向量或是list,向量长度要和x长度相同
若是list,每个元素的长度都要和x长度相同
fun是每一组要做的动作
举例:
tapply(1:6, rep(1:2, 3), mean)
x y
1 1
2 2
3 1 就是y=1的对应的x取mean跟 1 2 (这个是group)
4 2 y=2的对应的y取mean => 3 4 (这个是value)
5 1
6 2
如果第二个是list
tapply(1:6, list(rep(1:2,3), rep(1:3, each=2)), mean)
x y1 y2
1 1 1
2 2 1
3 1 2
4 2 2
5 1 3
6 2 3
这样就是 y1=1, y2=1的一组,y1=2, y2=1的一组, ... 分别取mean
这些其实在?tapply都可以找到,不需要google
我觉得看R程式范例去学习也是很重要的,要自己想办法学习阿~~
我的程式码应该就简单懂了,根据g1跟g2的分组计算每组的length
7F:推 phil5566: 下?最後就是假设产生sample的那个步骤如果只有产生10个 01/31 22:34
8F:→ phil5566: 那您做g2那个动作,取min还会取到0.5吗?谢谢 01/31 22:35
9F:→ phil5566: 可能是我没说清楚,我指的是不论今天sample产生出来是什 01/31 22:38
10F:→ phil5566: 都一定要有0.5,1.5,......,19.5这20个数的存在 01/31 22:40
对不起,我考虑的不够周到,那你只能写死了
g2 <- seq(0.5, 19.5, by = 1)
11F:推 phil5566: 赞赞赞~ 02/01 01:13
最後顺便回答你前一篇的问题
benchmark是评比的意思
你可以把程式分段去看执行时间
或是 直接使用profvis这个套件
可以比较容易抓出程式瓶颈的部分
再根据瓶颈部份去改善
柏拉图法则:80%的速度瓶颈来自20%的程式码
※ 编辑: celestialgod (118.170.46.59), 02/01/2017 02:05:39
12F:推 phil5566: 马上来试试 02/01 18:34