使用arrange、groupby与索引计算百分比变动的相关疑问
library(crypto2) library(dplyr) coins = crypto_list(only_active = TRUE) coins = coins[(coins$symbol %in% c("BTC","ETH")),] thirteen.months.data = crypto_history(coins, start_date=Sys.Date() - (13 * 30)) mydf <- thirteen.months.data[substr(thirteen.months.data$timestamp,1,10) %in% as.character((Sys.Date()-c(1,31,366))),] %>% select(timestamp,name,close,market_cap) %>% arrange(name,timestamp) %>% as.data.frame # Present df1 <- mydf %>% group_by(name) %>% slice(3) %>% select(-1) # M-o-M growth df2 <- mydf %>% group_by(name) %>% summarise(m.o.m = (close[3]-close[2])/close[2]*100) # Y-o-Y growth df3 <- mydf %>% group_by(name) %>% summarise(y.o.y = (close[3]-close[1])/close[1]*100)
问题1:arrange排序后执行group_by,是否会打乱之前的排序结果?
不会。dplyr的group_by()仅负责按指定变量分组,不会修改每个分组内部的行顺序,组内的行排列会完全继承arrange()后的排序结果。你这里先按name和timestamp升序排列,分组后每个币种(BTC/ETH)的组内数据依然保持timestamp从小到大的顺序,这也是后续能通过索引取对应时间点数据的基础。
问题2:计算M-oM、Y-oY的逻辑是否符合预期?group_by后用close[2]这类索引是否允许?
逻辑是否符合预期?
符合。从你的筛选逻辑来看,mydf里每个币种对应三个时间点的数据:Sys.Date()-366(去年同期)、Sys.Date()-31(上月同期)、Sys.Date()-1(昨日),经过arrange(name, timestamp)后,每个分组内的close顺序是「去年→上月→昨日」。
- M-o-M(月环比)计算的是(昨日收盘价 - 上月收盘价)/上月收盘价×100,逻辑正确;
- Y-o-Y(同比)计算的是(昨日收盘价 - 去年收盘价)/去年收盘价×100,逻辑也符合预期。
索引方式是否允许?
允许,但有前提:每个分组必须恰好有3行数据(你的代码里通过日期筛选保证了这一点,所以当前场景下没问题)。如果某个分组的行数不等于3,这种索引方式会返回NA或者报错。
不过更推荐用dplyr原生的nth()函数来替代直接索引,可读性更强,也更贴合dplyr的语法风格,修改后的代码如下:
# M-o-M growth(优化后) df2 <- mydf %>% group_by(name) %>% summarise(m.o.m = (nth(close,3)-nth(close,2))/nth(close,2)*100) # Y-o-Y growth(优化后) df3 <- mydf %>% group_by(name) %>% summarise(y.o.y = (nth(close,3)-nth(close,1))/nth(close,1)*100)
内容的提问来源于stack exchange,提问作者user2338823
相关产品推荐
相关产品推荐

