【问题标题】:spread() where non-unique values are put into a new column [duplicate]将非唯一值放入新列的 spread() [重复]
【发布时间】:2019-11-04 01:46:00
【问题描述】:

我有一些看起来像这样的数据(最后的输入代码):

#>           artist          album year  source                     id
#> 1        Beatles  Sgt. Pepper's 1967  amazon             B0025KVLTM
#> 2        Beatles  Sgt. Pepper's 1967 spotify 6QaVfG1pHYl1z15ZxkvVDW
#> 3        Beatles  Sgt. Pepper's 1967  amazon             B06WGVMLJY
#> 4 Rolling Stones Sticky Fingers 1971 spotify 29m6DinzdaD0OPqWKGyMdz

我想修复 'id' 列(其中包括来自多个来源的 id,如 'source' 列中所示。

这应该是一个直截了当的spread(),但复杂的是,有时我们会从完全相同的来源获得重复的 id:参见上面的第 1 行和第 3 行。

有没有一种简单的方法来执行spread() 并将重复的 id 放入新列中?

我想要的结果是:


#>           artist          album year  source  amazon_id amazon_id_2
#> 1        Beatles  Sgt. Pepper's 1967  amazon B0025KVLTM  B06WGVMLJY
#> 2 Rolling Stones Sticky Fingers 1971 spotify       <NA>        <NA>
#>                  spotify
#> 1 6QaVfG1pHYl1z15ZxkvVDW
#> 2 29m6DinzdaD0OPqWKGyMdz

下面的代码是输入样本数据:

df <- data.frame(stringsAsFactors=FALSE,
      artist = c("Beatles", "Beatles", "Beatles", "Rolling Stones"),
       album = c("Sgt. Pepper's", "Sgt. Pepper's", "Sgt. Pepper's",
                 "Sticky Fingers"),
        year = c(1967, 1967, 1967, 1971),
      source = c("amazon", "spotify", "amazon", "spotify"),
          id = c("B0025KVLTM", "6QaVfG1pHYl1z15ZxkvVDW", "B06WGVMLJY",
                 "29m6DinzdaD0OPqWKGyMdz")
)
df

【问题讨论】:

    标签: r dataframe reshape tidyr spread


    【解决方案1】:

    这可以通过data.table 中的dcast 在一行(looong)中完成。但因此我认为非常优雅。

    library(data.table)
    dcast(df, artist + album + year ~ paste(source, rowid(artist, source), sep = "_"))
    #          artist          album year   amazon_1   amazon_2              spotify_1
    #1        Beatles  Sgt. Pepper's 1967 B0025KVLTM B06WGVMLJY 6QaVfG1pHYl1z15ZxkvVDW
    #2 Rolling Stones Sticky Fingers 1971       <NA>       <NA> 29m6DinzdaD0OPqWKGyMdz
    

    【讨论】:

      【解决方案2】:

      一种可能是:

      df %>%
       group_by(artist, album, year, source) %>%
       mutate(source2 = paste(source, row_number(), sep = "_")) %>%
       spread(source2, id) %>%
       ungroup()
      
        artist         album           year source  amazon_1   amazon_2   spotify_1             
        <chr>          <chr>          <dbl> <chr>   <chr>      <chr>      <chr>                 
      1 Beatles        Sgt. Pepper's   1967 amazon  B0025KVLTM B06WGVMLJY <NA>                  
      2 Beatles        Sgt. Pepper's   1967 spotify <NA>       <NA>       6QaVfG1pHYl1z15ZxkvVDW
      3 Rolling Stones Sticky Fingers  1971 spotify <NA>       <NA>       29m6DinzdaD0OPqWKGyMdz
      

      请注意,这里的输出由三行组成,因为spotify 是披头士专辑的唯一“来源”。

      如果你仍然想要两行,你可以这样做:

      df %>%
       group_by(artist, album, year, source) %>%
       mutate(source2 = paste(source, row_number(), sep = "_")) %>%
       ungroup() %>%
       select(-source) %>%
       spread(source2, id) 
      
        artist         album           year amazon_1   amazon_2   spotify_1             
        <chr>          <chr>          <dbl> <chr>      <chr>      <chr>                 
      1 Beatles        Sgt. Pepper's   1967 B0025KVLTM B06WGVMLJY 6QaVfG1pHYl1z15ZxkvVDW
      2 Rolling Stones Sticky Fingers  1971 <NA>       <NA>       29m6DinzdaD0OPqWKGyMdz
      

      如果您还想拥有“来源”列:

      df %>%
       group_by(artist, album, year, source) %>%
       mutate(source2 = paste(source, row_number(), sep = "_")) %>%
       group_by(artist, album, year) %>%
       mutate(source = toString(unique(source))) %>%
       spread(source2, id) %>%
       ungroup()
      
        artist         album           year source          amazon_1  amazon_2  spotify_1            
        <chr>          <chr>          <dbl> <chr>           <chr>     <chr>     <chr>                
      1 Beatles        Sgt. Pepper's   1967 amazon, spotify B0025KVL… B06WGVML… 6QaVfG1pHYl1z15ZxkvV…
      2 Rolling Stones Sticky Fingers  1971 spotify         <NA>      <NA>      29m6DinzdaD0OPqWKGyM…
      

      【讨论】:

      • 我正在尝试用两行(即您的第二个答案)来计算代码如何为您的答案工作。我想知道你是否可以帮助我理解它是如何阻止三行成为结果的?我尝试将代码分解,所以我可以看到每个步骤(上面的代码在 postscript 中提出问题)但以某种方式分解它意味着返回三行。
      • 我没有运气将代码发布为 cmets,但这就是我的意思:df2 % group_by(artist, album, year, source) %>% mutate(source2 =粘贴(来源,row_number(),sep =“_”))%>%取消组()%>%选择(-来源)df2#传播(来源2,id)df2 %传播(来源2,id)
      • 它通过删除步骤select(-source)中的“源”列来实现。
      【解决方案3】:

      也可以在带有avereshape 的基础R 中。

      df$source <- with(df, paste(source, 
                                  ave(artist, source, FUN=function(i) 
                                    cumsum(duplicated(i)) + 1)), sep="_")
      reshape(df, timevar="source", idvar=c("artist", "album", "year"), direction="wide")
      #           artist          album year id.amazon_1           id.spotify_1 id.amazon_2 id.amazon_3
      # 1        Beatles  Sgt. Pepper's 1967  B0025KVLTM 6QaVfG1pHYl1z15ZxkvVDW  B06WGVMLJY     SoMeFoO
      # 4 Rolling Stones Sticky Fingers 1971        <NA> 29m6DinzdaD0OPqWKGyMdz        <NA>        <NA>
      

      数据

      df <- structure(list(artist = c("Beatles", "Beatles", "Beatles", "Rolling Stones"
      ), album = c("Sgt. Pepper's", "Sgt. Pepper's", "Sgt. Pepper's", 
      "Sticky Fingers"), year = c(1967, 1967, 1967, 1971), source = c("amazon", 
      "spotify", "amazon", "spotify"), id = c("B0025KVLTM", "6QaVfG1pHYl1z15ZxkvVDW", 
      "B06WGVMLJY", "29m6DinzdaD0OPqWKGyMdz")), class = "data.frame", row.names = c(NA, 
      -4L))
      df <- rbind(df, df[1, ])
      df[5, 5] <- "SoMeFoO"
      

      【讨论】:

        【解决方案4】:

        这是一种方法。

        df %>% 
          group_by(artist,source) %>%  
          mutate(rownum = row_number()) %>% 
          unite(source, source, rownum, sep="_") %>% 
          spread(source,id)
        
        # A tibble: 2 x 6
        # Groups:   artist [2]
          artist         album           year amazon_1   amazon_2   spotify_1             
          <chr>          <chr>          <dbl> <chr>      <chr>      <chr>                 
        1 Beatles        Sgt. Pepper's   1967 B0025KVLTM B06WGVMLJY 6QaVfG1pHYl1z15ZxkvVDW
        2 Rolling Stones Sticky Fingers  1971 NA         NA         29m6DinzdaD0OPqWKGyMdz
        

        【讨论】:

        • 你能解释一下为什么最后一行`spread(source, id) 没有为披头士创建两行,尽管披头士有两个来源,即“amazon_1”和“amazon_2” ?
        • 另外,在这一行:unite(source, source, rownum, sep="_"),我想弄清楚为什么我们把“source”放了两次。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-10-23
        • 1970-01-01
        • 2022-01-17
        • 2015-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多