楼主: gulongzhou
7042 34

[问答] 实测R的vector和list结构比python对应的list和dict慢近千倍,怎么破? [推广有奖]

11
cheetahfly 在职认证  发表于 2016-1-5 16:07:43
gulongzhou 发表于 2016-1-5 15:36
@cheetahfly 给你点120个赞!!!
我本人确实算半个C/Python程序员(之所以说半个是因为coding ...
多交流,共同进步

12
cheetahfly 在职认证  发表于 2016-1-6 09:50:26
gulongzhou 发表于 2016-1-5 15:36
@cheetahfly 给你点120个赞!!!
我本人确实算半个C/Python程序员(之所以说半个是因为coding ...
昨天没有考虑周全,其实最后收尾阶段的那6行代码不是最简化的,应该可以一行代码,一个函数就搞定收尾
  1. lstResult <- split(xu[,2],xu[,1])
复制代码

最终,应该三行代码可以全部搞定:
  1. x <- matrix(c(k,v), ncol = 2)    #  矩阵化
  2. xu <- unique.matrix(x)            #  去除重复冗余数据
  3. lstResult <- split(xu[,2],xu[,1])  # 切割向量v
复制代码
执行效率上未必有明显的进一步提升,但胜在代码较简化,逻辑更清晰,且较符合向量化的思想。


13
gulongzhou 发表于 2016-1-6 13:38:26
cheetahfly 发表于 2016-1-6 09:50
昨天没有考虑周全,其实最后收尾阶段的那6行代码不是最简化的,应该可以一行代码,一个函数就搞定收尾
最 ...
感谢!实测效率比原来的6行代码效率还有10倍以上的提升!
但也带来了个问题:split函数返回的list对象的长度是固定的!!!
比如你这里的lstResult <- split(xu[,2],xu[,1])
我原来的程序里面,对lstResult还有修改,就是将lstResult中的元素再增加一个属性。
例如原来的lstResult[[1]]$c1,我计算后又增加了lstResult[[1]]$c2
现在问题出来了:c1和c2的长度必须相同才行,否则报错!
但按照原来的方法没有问题。

14
cheetahfly 在职认证  发表于 2016-1-6 14:55:59
看了你的描述,猜测问题出在c1和c2封装在一起的形式,matrix和dataframe要求c1和c2必须长度相同(会自动补齐,请检查清楚),list则不用。
一个可能的解决问题的方案是:
另外算出由另一个属性c2组成的list,我们暂时将它的名称定为lstResult2,注意,lstResult和lstResult2中的元素应该是一一对应的。然后再将两个list按c1、c2组装成一个子列表的形式组装在一起,比如:
  1. for (i in 1:length(lstResult)) {
  2.     lstResult[[i]] <- list(lstResult[[i]],lstResult2[[i]])
  3. }   
复制代码
你可以试试看。
多问一句,目前的耗时是多少?

15
gulongzhou 发表于 2016-1-6 15:04:11
cheetahfly 发表于 2016-1-6 14:55
看了你的描述,猜测问题出在c1和c2封装在一起的形式,matrix和dataframe要求c1和c2必须长度相同(会自动补齐 ...
哈哈,我也是用这种方法绕过这个坑的。
在我的服务器上处理50万条流量数据,用我最初逐条处理需要约4个小时,向量化后用for循环的方法需要240秒,用split方法不到3秒,见证奇迹的时刻啊!

16
gulongzhou 发表于 2016-1-6 15:06:58
cheetahfly 发表于 2016-1-6 14:55
看了你的描述,猜测问题出在c1和c2封装在一起的形式,matrix和dataframe要求c1和c2必须长度相同(会自动补齐 ...
再多说一句,python真是各种场景通吃,不用考虑优化,耗时稳定在2分钟以内。

17
cheetahfly 在职认证  发表于 2016-1-6 16:11:51
gulongzhou 发表于 2016-1-6 15:04
哈哈,我也是用这种方法绕过这个坑的。
在我的服务器上处理50万条流量数据,用我最初逐条处理需要约4个小 ...
我听着都很高兴

18
suimong 发表于 2016-1-6 18:37:41
cheetahfly 发表于 2016-1-5 14:30
我不知道理解的对不对,如果不对请见谅:

我用以下两个随机数序列模拟k和v:
我刚看到题主加的问题说明,我感觉你是不是想复杂了?题主的要求应该就是split(v, k)吧?要去重复的话那就是lapply(split(v, k), unique)?还是我又理解错了。。。

19
feng026 发表于 2016-1-6 21:16:25 来自手机
感觉用reshape2也可以啊

20
cheetahfly 在职认证  发表于 2016-1-7 00:10:39
suimong 发表于 2016-1-6 18:37
我刚看到题主加的问题说明,我感觉你是不是想复杂了?题主的要求应该就是split(v, k)吧?要去重复的话那就 ...
确实更快
确实是学无止境
我在写第九楼的时候,基本上把思索的过程都写下来了,啰哩啰嗦的,思路也不是很清晰,在第12楼补充的时候,思路基本就定型了,其核心也是unique+split,不过,我是先unique,把数据中的“水分”挤出,再进行split,以为这样会更快,并且我可能有个偏见,对apply家族并不信任,认为他们是把显性循环隐形化了!
为什么会这样呢?
我尝试找了一下原因,结果发现:
  1. > system.time(xu <- unique.matrix(x))
  2.    user  system elapsed
  3.    7.12    0.01    7.26
  4. > system.time(t <- unique(c(k,v)))
  5.    user  system elapsed
  6.    0.04    0.00    0.05
复制代码
我去!差了两个数量级!
原因应该在这里了。
多谢了!

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-30 08:16