根据日期顺序创建列,旋转数据集R.

时间:2018-01-25 17:09:50

标签: r date data-manipulation tidyr

我有一个如下所示的数据集:

ID= c("A","A","A","A","B","B","C","C","C")
Date= as.Date(c("2017-09-24", "2017-09-26", "2017-09-23", "2017-09-30","2017-09-12", "2017-09-15", "2017-09-01", "2017-09-30", "2017-09-25"))
Data= c(10,5,15,20,8,9,5,6,2)
df= data.frame(ID, Date, Data)
d
  ID       Date Data
1  A 2017-09-24   10
2  A 2017-09-26    5
3  A 2017-09-23   15
4  A 2017-09-30   20
5  B 2017-09-12    8
6  B 2017-09-15    9
7  C 2017-09-01    5
8  C 2017-09-30    6
9  C 2017-09-25    2

我正在尝试按降序顺序添加按每个ID的Date列降序排列的其他列,以便我有以下输出:

   ID Order      Date   Data
1  A     3 2017-09-24   10
2  A     2 2017-09-26    5
3  A     4 2017-09-23   15
4  A     1 2017-09-30   20
5  B     2 2017-09-12    8
6  B     1 2017-09-15    9
7  C     3 2017-09-01    5
8  C     1 2017-09-30    6
9  C     2 2017-09-25    2

我已经使用了striptime()和order()来尝试获取Order列,但我不确定如何根据ID循环它。

然后我尝试旋转数据框,以便每个Order都有自己的列,并且观察结果是数据列中包含的数据:

  ID Order4 Order3 Order2 Order1
1  A     15     10      5     20
2  B                    8      9
3  C             5      2      6

我曾尝试使用tidyr的spread()来完成数据集的旋转,但由于存在不同长度的列,因此效果不佳。

非常感谢

3 个答案:

答案 0 :(得分:0)

关于你的第一个问题。

library(dplyr)

df2 <- df %>%
  group_by(ID) %>%
  mutate(Order = dense_rank(desc(Date))) %>%
  ungroup() %>%
  select(ID, Order, Date, Data)
# df2
#   ID    Order Date        Data
#   <fct> <int> <date>     <dbl>
# 1 A         3 2017-09-24 10.0 
# 2 A         2 2017-09-26  5.00
# 3 A         4 2017-09-23 15.0 
# 4 A         1 2017-09-30 20.0 
# 5 B         2 2017-09-12  8.00
# 6 B         1 2017-09-15  9.00
# 7 C         3 2017-09-01  5.00
# 8 C         1 2017-09-30  6.00
# 9 C         2 2017-09-25  2.00

关于你的第二个问题。

library(tidyr)

df3 <- df2 %>%
  select(-Date) %>%
  mutate(Order = paste0("Order", Order)) %>%
  spread(Order, Data)
df3
# # A tibble: 3 x 5
#   ID    Order1 Order2 Order3 Order4
# * <fct>  <dbl>  <dbl>  <dbl>  <dbl>
# 1 A      20.0    5.00  10.0    15.0
# 2 B       9.00   8.00  NA      NA  
# 3 C       6.00   2.00   5.00   NA  

答案 1 :(得分:0)

使用库data.table

library(data.table)
df= data.frame(ID, Date, Data)
setDT(df)[,Order:=(.N:1)[rank(Date)],by=ID][,.(ID,Order,Date,Data)]
   ID Order       Date Data
1:  A     3 2017-09-24   10
2:  A     2 2017-09-26    5
3:  A     4 2017-09-23   15
4:  A     1 2017-09-30   20
5:  B     2 2017-09-12    8
6:  B     1 2017-09-15    9
7:  C     3 2017-09-01    5
8:  C     1 2017-09-30    6
9:  C     2 2017-09-25    2
dcast(df[,order:=.(paste0("Order",Order))],ID~order,value.var = "Data")
   ID Order1 Order2 Order3 Order4
1:  A     20      5     10     15
2:  B      9      8     NA     NA
3:  C      6      2      5     NA

答案 2 :(得分:0)

OP要求将数据集从长格式转换为宽格式,其中每个ID的订单应按Date的降序编号,即最近的订单将显示在列中Order1Order2中的第二个最近订单等,

这可以通过dcast() 一步使用rowid()功能实现:

library(data.table)
dcast(setDT(df)[order(-Date)], ID ~ rowid(ID, prefix = "Order"))
   ID Order1 Order2 Order3 Order4
1:  A     20      5     10     15
2:  B      9      8     NA     NA
3:  C      6      2      5     NA

现在,OP的预期结果也显示Order列也按降序排列。这可以通过扭转因子水平来实现:

dcast(setDT(df)[order(-Date)], ID ~ forcats::fct_rev(rowid(ID, prefix = "Order")))
   ID Order4 Order3 Order2 Order1
1:  A     15     10      5     20
2:  B     NA     NA      8      9
3:  C     NA      5      2      6

最后,我们可以通过胁迫角色来摆脱NA值:

dcast(setDT(df)[order(-Date)], ID ~ forcats::fct_rev(rowid(ID, prefix = "Order")), 
      toString)
   ID Order4 Order3 Order2 Order1
1:  A     15     10      5     20
2:  B                    8      9
3:  C             5      2      6

现在,这几乎完全复制了OP的预期结果。

买者

如果每ID个订单超过9个,则需要修改列名以保持列的正确顺序:

dcast(setDT(df)[order(-Date)], ID ~ forcats::fct_rev(sprintf("Order%02i", rowid(ID))), 
      toString)

%02i调用中的格式说明符sprintf()可确保订单号在转换为字符时始终使用两位数。比较sort(as.character(1:10))sort(sprintf("%02i", 1:10))