楼主: zl66983279
3817 12

[问答] 向量化处理数据(避免循环),purr包遍历求助 [推广有奖]

  • 6关注
  • 1粉丝

博士生

20%

还不是VIP/贵宾

-

威望
0
论坛币
950 个
通用积分
88.5266
学术水平
3 点
热心指数
3 点
信用等级
1 点
经验
128364 点
帖子
161
精华
0
在线时间
290 小时
注册时间
2015-10-20
最后登录
2020-12-11

楼主
zl66983279 在职认证  发表于 2018-4-6 17:30:51 |AI写论文
50论坛币
如题,近期再处理一批数据,数据量很大。循环太慢了,想用purrr包中进行处理
案例:
  1. data <- data.table(dt=rep(seq.Date(as.Date('2018-01-01'),as.Date('2018-01-07'),1),5),x1=rep(letters[1:7],5),x2=rep(letters[2:8],5),y1=rep(2:8,5),y2=rep(3:9))
复制代码

其中:x为维度,y为指标。
要求分别计算每一个维度,求每个指标平均值,最大值。在计算某一个维度时,需要按照这个维度和dt进行分组,所有指标进行求和。
输出格式为 维度名称、维度值、指标名称、指标平均值、指标最小值
结果样例:(样例并不是上面的案例的结果,只是示意)
  1. result <- data.table(dim_name = rep(c("x1","x2"),5),dim_value=letters[1:10],index_name=rep(c("y1","y2"),5),mean=1:10,max=5:14)
复制代码
说明:维度和指标非常多,需要进行遍历,最终要按照数据框输出,维度字段和指标字段通过名字是可以识别的(维度都以x开头,指标都以y开头)
不能有循环,我自己的想法是purrr的map,但是写的不好求大师帮忙!!!
另外,有能力的大神可以帮忙想一下任意两个维度的遍历。





最佳答案

cheetahfly 查看完整内容

之前我想岔了,这样的应用不需要用到map()这样的复杂工具,用lapply()完全可以胜任。 麻烦你反馈一下代码执行一次计算需要多长时间?
关键词:处理数据 向量化 PUR Data

沙发
cheetahfly 在职认证  发表于 2018-4-6 17:30:52
之前我想岔了,这样的应用不需要用到map()这样的复杂工具,用lapply()完全可以胜任。
  1. library(tidyverse)
  2. dim_names <- c("x1", "x2")  # 数据维度的名称
  3. idx_names <- c("y1", "y2")   # 数据指标的名称
  4. fun_names <- c("mean", "max")   # 要应用的函数的名称

  5. # dim_names的循环,用lapply来实现
  6. # idx_nemas的循环,用summarise_at实现
  7. lapply(dim_names, function(x) {
  8.     data %>%
  9.       group_by(get(x)) %>%  
  10.       summarise_at(vars(idx_names),  
  11.                    sapply(fun_names, get)) %>%  
  12.       set_names(c("dim_value", colnames(.)[-1])) %>%
  13.       mutate(dim_name = x)
  14.     }) %>%
  15.   bind_rows() %>%
  16.   gather(idx_name_fun, value, c(-1, -ncol(.))) %>%
  17.   separate(idx_name_fun, c("idx_name", "fun")) %>%
  18.   select(dim_name, dim_value, everything()) %>%
  19.   spread(fun, value) %>%
  20.   distinct()
复制代码


麻烦你反馈一下代码执行一次计算需要多长时间?

藤椅
zl66983279 在职认证  发表于 2018-4-8 07:38:09 来自手机
顶.......

板凳
zl66983279 在职认证  发表于 2018-4-8 15:48:36
没有数据处理的大神吗

报纸
cheetahfly 在职认证  发表于 2018-4-9 14:40:59
我个人不觉得把所有维度的问题都用map统一解决是个好主意,因为这会增加内存的压力,不过技术上是可以实现的:
  1. library(tidyverse)
  2. data %>%
  3.     gather(dim_name, dim_value, 2:3) %>%
  4.     group_by(dim_name) %>%
  5.     nest() %>%
  6.     mutate(result = map(data, .f = function(x) {x %>%
  7.             group_by(dim_value) %>%
  8.             select(-dt) %>%
  9.             summarise_all(c(mean, max)) %>%
  10.             gather(type, value, -1) %>%
  11.             separate(type, into = c("index_name", "cal")) %>%
  12.             spread(cal, value) %>%
  13.             set_names(c(names(.)[1:2], "mean", "max"))})) %>%
  14.     select(-data) %>%
  15.     unnest(result)
复制代码

注:你需要自己用data.table的语法去优化,但不可能彻底优化(我猜),因为核心的nest(),unnest(),map()等都是tibble体系的。其次,运行会出现警告信息“Expected 2 pieces. Additional pieces discarded”,这是在拆分名字的时候发生的,不影响结果。

地板
zl66983279 在职认证  发表于 2018-4-9 14:55:36
cheetahfly 发表于 2018-4-9 14:40
我个人不觉得把所有维度的问题都用map统一解决是个好主意,因为这会增加内存的压力,不过技术上是可以实现的 ...
那有什么更好的办法吗,维度遍历的

7
cheetahfly 在职认证  发表于 2018-4-9 15:22:06
zl66983279 发表于 2018-4-9 14:55
那有什么更好的办法吗,维度遍历的
如果是一次性的工作,循环一次也不会有太大问题,如果是重复性的工作,你自己测试一些对时间和内存的压力到底哪种方法大。

8
zl66983279 在职认证  发表于 2018-4-9 15:27:13
cheetahfly 发表于 2018-4-9 14:40
我个人不觉得把所有维度的问题都用map统一解决是个好主意,因为这会增加内存的压力,不过技术上是可以实现的 ...
试了一下您的方案,第一步gather就跑不动了。

我自己写了一个
  1. list_order_data <- map(select_at(data,vars(dim_loc)),
  2.                        function (x){
  3.                          map(select_at(data,vars(index_loc)),function(y){
  4.                            data.table(dt =dt_data,dim_subject_name=x,index_value=y)%>% group_by(dt,dim_subject_name) %>% summarise(index_value=sum(index_value)) %>%  
  5.                              ungroup() %>% group_by(dim_subject_name)   %>%summarise(
  6.                                                                                                                                value=last(index_value),
  7.                                                                                                                                mean=mean(index_value),
  8.                                                                                                                                min = min(index_value)
  9.                                                                                                       
  10.                                                                                                                              )
  11.                          }
  12.                         
  13.                          )
  14.                        })
复制代码
其中dt_data是日期数据,dim_loc是维度的列数,index是指标的列数。我这种等于拆到日期、一个指标和一个维度计算,计算速度还是可以的,但有个问题,返回的是list,维度名称和指标名称变成了list的名字,如何能把拆分的list不用循环的情况下合并成data.table,并增加两列,对应是维度和指标名称。

9
zl66983279 在职认证  发表于 2018-4-9 15:32:37
cheetahfly 发表于 2018-4-9 15:22
如果是一次性的工作,循环一次也不会有太大问题,如果是重复性的工作,你自己测试一些对时间和内存的压力 ...
需要做成常规的,我自己写的那个速度要比循环快上不少。另外大神能不能帮忙看看这个问题
https://bbs.pinggu.org/thread-6300437-1-1.html

10
cheetahfly 在职认证  发表于 2018-4-9 16:46:06
zl66983279 发表于 2018-4-9 15:27
试了一下您的方案,第一步gather就跑不动了。

我自己写了一个其中dt_data是日期数据,dim_loc是维度的 ...
把list变成data.frame(data.table)难度应该相比小很多啊

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

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