ITPub博客

首页 > > > R语言数据操作:练习题跟帖2

R语言数据操作:练习题跟帖2

作者:浪花小雨滴 时间:2020-01-10 10:25:17 0 删除 编辑

作者:黄天元,复旦大学博士在读,热爱数据科学与开源工具(R),致力于利用数据科学迅速积累行业经验优势和科学知识发现,涉猎内容包括但不限于信息计量、机器学习、数据可视化、应用统计建模、知识图谱等,著有《R语言数据高效处理指南》(《R语言数据高效处理指南》(黄天元)【摘要 书评 试读】- 京东图书,《R语言数据高效处理指南》(黄天元)【简介_书评_在线阅读】 - 当当图书)。知乎专栏:R语言数据挖掘。邮箱:huang.tian-yuan@qq.com.欢迎合作交流。


延续上一次的练习提跟帖:

HopeR:R语言数据操作:练习题跟帖1

这次新的内容(R练习50题 - 第二期)出来了,我们继续用dtplyr来对data.table的代码进行优化,并且尝试告诉大家为什么要这么做。话不多说,先上代码:

# 3.每天每个交易所上涨、下跌的股票各有多少?

# data.table
data[, .(num = uniqueN(symbol)), 
     keyby = .(date, 
               exchange = str_sub(symbol, start = -2, end = -1), 
               updown = ifelse(close - pre_close > 0, "UP", "DOWN"))
     ]

# dtplyr
data %>% 
  lazy_dt() %>% 
  mutate(exchange = str_sub(symbol, start = -2, end = -1)) %>% 
  mutate(updown = ifelse(close - pre_close > 0, "UP", "DOWN")) %>% 
  group_by(date,exchange) %>% 
  count(updown,name = "num") %>% 
  as_tibble()

# 4.沪深300成分股中,每天上涨、下跌的股票各有多少?

# data.table
data[index_w300 > 0, 
     .(num = uniqueN(symbol)), 
     keyby = .(date, updown = ifelse(close - pre_close > 0, "UP", "DOWN"))
     ]

# dtplyr
data %>% 
  lazy_dt() %>% 
  filter(index_w300 > 0) %>% 
  mutate(updown = ifelse(close - pre_close > 0, "UP", "DOWN")) %>% 
  group_by(date) %>% 
  count(updown) %>% 
  as_tibble()

# 5.每天每个行业各有多少只股票?

# data.table
data[, .(stk_num = uniqueN(symbol)), 
     keyby = .(date, industry)
     ]

# dtplyr
data %>% 
  lazy_dt() %>% 
  group_by(date,industry) %>% 
  distinct(symbol) %>% 
  summarise(stk_num = n()) %>% 
  tibble()

# 7.每天涨幅超过5%、跌幅超过5%的股票各有多少?

# data.table
data[, ':='(ret = (close - pre_close)/pre_close)
     ][ret > 0.05 | ret < -0.05, 
       .(symbol_amount = uniqueN(symbol)), 
       keyby = .(date, updown = ifelse(ret > 0.05, "up5%+", "down5%+"))
       ]

# dtplyr
data %>% 
  lazy_dt() %>% 
  mutate(ret = (close - pre_close)/pre_close) %>% 
  filter(ret > 0.05 | ret < -0.05) %>% 
  mutate(updown = ifelse(ret > 0.05, "up5%+", "down5%+")) %>% 
  group_by(date,updown) %>% 
  distinct(symbol) %>% 
  summarise(symbol_amount = n()) %>% 
  as_tibble()
  

重点解释以下几点:

1、为什么dtplyr总是比data.table代码长?

首先,为了转化为data.table的代码,我们总是在开端设置了惰性评估(lazy evaluation)函数,即为lazy_dt。

其次,为了把数据收集回来(collect),总是在最后加上as_tibble。

最后而最重要的是,dplyr的核心思想就是把任何一个复杂的工序,分解成最小简单组分,然后拼接到一起,完成一个大的任务。这不仅仅是在编程中,而是在任何大型的工程中都极为重要的思想。而把复杂的东西一大团浆糊一样糊在[i,j,by]中,则让人容易迷乱。一个简单的思考:data.table的[i,j,by]模式总是先i后by最后j,如果我告诉大家做事情要先1后3再2,那是足够2的一件事情...

2、如果你还是想写data.table但是不知道怎么写,怎么办?

上面的代码,大家不写as_tibble试试,马上获得机器翻译的data.table代码,十拿九稳的准确。所以会dplyr的同学甚至可以不学data.table,马上获得data.table的速度。例子如下:

# 3.每天每个交易所上涨、下跌的股票各有多少?


# dtplyr
data %>% 
  lazy_dt() %>% 
  mutate(exchange = str_sub(symbol, start = -2, end = -1)) %>% 
  mutate(updown = ifelse(close - pre_close > 0, "UP", "DOWN")) %>% 
  group_by(date,exchange) %>% 
  count(updown,name = "num") %>% 


Source: local data table [?? x 4]
Call:   copy(`_DT21`)[, `:=`(exchange = str_sub(symbol, start = -2, end = -1))][, 
    `:=`(updown = ifelse(close - pre_close > 0, "UP", "DOWN"))][, 
    .(num = .N), keyby = .(date, exchange, updown)]

      date exchange updown   num
     <int> <chr>    <chr>  <int>
1 20120104 SH       DOWN     836
2 20120104 SH       UP        85
3 20120104 SZ       DOWN    1293
4 20120104 SZ       UP       106
5 20120105 SH       DOWN     847
6 20120105 SH       UP        74

# Use as.data.table()/as.data.frame()/as_tibble() to access results

Call中就是翻译好的data.table代码。

总结来说,data.table的设计违反了程序自上而下的顺序结构(132),很难让人有一步一步清晰往下 处理的既视感,而dplyr则可以把所有任务分解为最小可操作单元,这是一个非常大的进步。这提高了代码的可读性,降低初学者的学习成本和用户的代码交流成本。事实上,我们看dplyr的动词代码,甚至比直接看文字来描述数据操作理解得更快,这打破了思维逻辑与实现操作的壁垒。

下面,我手撕一个“具有争议”的第6题,让大家看看它的威力。第6题的描述如下:

6. 股票数最大的行业和总成交额最大的行业是否总是同一个行业?

这句话先这么理解,“A行业”和“B行业”是不是“总是”同一个行业?

那么我们需要先求得“A行业”和“B行业”,因为问了是不是“总是”,所以有一个时间的概念在里面,需要按照日期分组来求“A行业”和“B行业”。

A行业,股票数最大的行业,这样求:

# 每天股票数最大行业
data %>% 
  lazy_dt() %>% 
  distinct(date,industry,symbol) %>% 
  count(date,industry,sort = T) %>% 
  group_by(date) %>% 
  slice(1) %>% 
  as_tibble() -> A

B行业,每天成交额最大的行业,这样求:

# 每天成交额最大的行业
data %>% 
  lazy_dt() %>% 
  group_by(date) %>% 
  count(industry,wt = amount,sort = T) %>% 
  slice(1) %>% 
  as_tibble() -> B

是不是同一行业,这样求:

A %>% 
  inner_join(B,by = "date") %>% 
  mutate(same = industry.x == industry.y) -> same_or_not

看看具体情况:

same_or_not %>% 
  pull(same) %>% 
  table()

.
FALSE  TRUE 
  102    15 

也就是说在117个交易日中,用15天是同一行业,其余不是同一行业。

代码不一定短,但是肯定是无比地清晰。所谓data.table短小的代码其实都是在大量人类掉头发试错之后的短小,而上面这些清晰的代码其实写起来并不会花特别长的时间(也可能我已经过分熟练了...)。

最后,这个系列的代码我会统一上传到Github(hope-data-science/R_ETL)供大家玩耍,不过数据太大我就不重复上传了,大家可以去原始网站(renkun-ken/r-data-practice)来下载。

原文作者:;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2018-05-16

  • 博文量
    4259
  • 访问量
    39849