【问题标题】:How to change a R table from long to wide with dates as well?如何使用日期将 R 表从长更改为宽?
【发布时间】:2023-05-29 05:56:01
【问题描述】:

我有一个关于个人购买事件和年龄的数据框。

Name     Item     Date
PersonA   Apple    1/1/14
PersonA   Banana   1/1/13
PersonA   Pear     1/1/12
PersonB   Orange   1/1/15
PersonC   Kiwi     1/1/17
PersonC   Grapes   1/1/12
PersonD   Lemon    1/1/16

我想把它从长到宽重新排列,但同时保留每个购买活动的日期,即

Name     Item.x    Date.x     Item.y     Date.y     Item.z     Item.z
PersonA   Pear      1/1/12     Banana     1/1/13     Apple      1/1/14
PersonB   Orange    1/1/15     NA         NA         NA         NA       
PersonC   Grapes    1/1/12     Kiwi       1/1/17     NA         NA  
PersonD   Lemon     1/1/16

我看到很多从长到宽的通用问题,但不确定如何在涉及两列(项目加上日期)时将其拉入宽格式。

【问题讨论】:

    标签: r melt spread


    【解决方案1】:

    我们可以使用pivot_wider

    library(dplyr)
    library(tidyr)
    library(lubridate)
    df1 %>%
        arrange(Name, mdy(Date)) %>%
        group_by(Name) %>% 
        mutate(rn = c('x', 'y', 'z')[row_number()]) %>% 
        ungroup %>%
        pivot_wider(names_from = rn, values_from = c(Item, Date), names_sep=".")%>% 
        select(Name, ends_with('x'), ends_with('y'), ends_with('z'))
    # A tibble: 4 x 7
    #  Name    Item.x Date.x Item.y Date.y Item.z Date.z
    #  <chr>   <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
    #1 PersonA Pear   1/1/12 Banana 1/1/13 Apple  1/1/14
    #2 PersonB Orange 1/1/15 <NA>   <NA>   <NA>   <NA>  
    #3 PersonC Grapes 1/1/12 Kiwi   1/1/17 <NA>   <NA>  
    #4 PersonD Lemon  1/1/16 <NA>   <NA>   <NA>   <NA>  
    

    数据

    df1 <- structure(list(Name = c("PersonA", "PersonA", "PersonA", "PersonB", 
    "PersonC", "PersonC", "PersonD"), Item = c("Apple", "Banana", 
    "Pear", "Orange", "Kiwi", "Grapes", "Lemon"), Date = c("1/1/14", 
    "1/1/13", "1/1/12", "1/1/15", "1/1/17", "1/1/12", "1/1/16")), 
    class = "data.frame", row.names = c(NA, 
    -7L))
    

    【讨论】:

      【解决方案2】:

      在基础 R 中你可以这样做:

      df2 <- transform(df1, time = ave(Item, Name, FUN = function(x)c("x", "y", "z")[seq(x)]))
      
      reshape(df2, idvar = "Name", dir = "wide")
      
           Name Item.x Date.x Item.y Date.y Item.z Date.z
      1 PersonA  Apple 1/1/14 Banana 1/1/13   Pear 1/1/12
      4 PersonB Orange 1/1/15   <NA>   <NA>   <NA>   <NA>
      5 PersonC   Kiwi 1/1/17 Grapes 1/1/12   <NA>   <NA>
      7 PersonD  Lemon 1/1/16   <NA>   <NA>   <NA>   <NA>
      

      如果你不关心x,y,z,你可以这样做:

      reshape(transform(df1,time = ave(Item,Name,FUN = seq_along)),idvar = "Name",dir="wide")
      
           Name Item.1 Date.1 Item.2 Date.2 Item.3 Date.3
      1 PersonA  Apple 1/1/14 Banana 1/1/13   Pear 1/1/12
      4 PersonB Orange 1/1/15   <NA>   <NA>   <NA>   <NA>
      5 PersonC   Kiwi 1/1/17 Grapes 1/1/12   <NA>   <NA>
      7 PersonD  Lemon 1/1/16   <NA>   <NA>   <NA>   <NA>
      

      【讨论】: