【问题标题】:Binds dataframe in rows when duplicated id重复 id 时在行中绑定数据框
【发布时间】:2020-03-01 23:59:41
【问题描述】:

我在 R 中有一个带有重复 ID 的数据框,我想在同一行上对齐。

df <- data_frame(id = c("A1", "A2", "C2", "A2", "C2", "A2"),
             date = c("2010-01-15", "2016-03-05", "2017-05-21", "2013-09-03", "2015-11-25", "2011-07-07"),
             iT = c("z", "z", "v", "w", "z", "v"))

我想将同一行上的每个 ID 与 for 循环对齐,但一次只能子集一个变量(实际上我实际上有大约 10 个)。

datalist = list()
datalist1 = list()
unique_id <- unique(df$id)
for (i in unique_id) {
  subdf <- subset(df$date, df$id == i)
  datalist[[i]] <- subdf
  subdf1 <- subset(df$iT, df$id == i)
  datalist1[[i]] <- subdf1
}
df1 <- plyr::ldply(datalist, rbind)
df2 <- plyr::ldply(datalist1, rbind)
df3 <- merge.data.frame(df1,df2, by.x = ".id", by.y = ".id")

我有数千行这样的行,有 2 到 7 个重复 ID

这是我的愿望:

df3 <- data_frame(id = c("A1", "A2", "C2"),
  date1 = c("2010-01-15", "2016-03-05", "2017-05-21"),
  iT = c("z", "z", "v"),
  date2 = c("NA", "2013-09-03","2015-11-25"),
  iT.2 = c("NA", "w", "z"),
  date3 = c("NA", "2011-07-07", "NA"),
  iT.3 = c("NA", "v", "NA"))

【问题讨论】:

  • 因为你想要每行一个 id?像宽格式 data.frame 一样?

标签: r loops duplicates rbind


【解决方案1】:

dcast() 可以一次重塑多个值列:

library(data.table)
dcast(setDT(df), id ~ rowid(id), value.var = c("date", "iT"))
   id     date_1     date_2     date_3 iT_1 iT_2 iT_3
1: A1 2010-01-15       <NA>       <NA>    z <NA> <NA>
2: A2 2016-03-05 2013-09-03 2011-07-07    z    w    v
3: C2 2017-05-21 2015-11-25       <NA>    v    z <NA>

【讨论】:

    【解决方案2】:

    使用dplyrtidyr,您可以获得长格式的数据,为id 和列名的每个组合创建唯一的ID,并将数据恢复为宽格式。

    library(dplyr)
    library(tidyr)
    
    df %>%
      pivot_longer(cols = -id) %>%
      group_by(id, name) %>%
      mutate(name1 = paste0(name, row_number())) %>%
      ungroup() %>%
      select(-name) %>%
      pivot_wider(names_from = name1, values_from = value)
    
    #  id    date1      iT1   date2      iT2   date3      iT3  
    #  <chr> <chr>      <chr> <chr>      <chr> <chr>      <chr>
    #1 A1    2010-01-15 z     NA         NA    NA         NA   
    #2 A2    2016-03-05 z     2013-09-03 w     2011-07-07 v    
    #3 C2    2017-05-21 v     2015-11-25 z     NA         NA   
    

    【讨论】:

      【解决方案3】:

      考虑带有transformaveseq_alongreshapegrepmergepaste0outer 的基本 R:

      # CREATE A RUNNING GROUP NUMBER FOR RESHAPING
      df$id_num <- with(transform(df, n=1), ave(n, id, FUN=seq_along))
      
      # MERGE TWO WIDE FORMAT SETS FOR date and iT
      df <- merge(reshape(df[c("id", "id_num", names(df)[grep("date", names(df))])], 
                          v.names = "date", timevar = "id_num", direction = "wide"),
                  reshape(df[c("id", "id_num", names(df)[grep("iT", names(df))])], 
                          v.names = "iT", timevar = "id_num", direction = "wide"),
                  by = "id", suffices = c("", "_"))
      
      # RE-ORDER COLUMNS BY PAIR COMBINATIONS
      df <- df[c("id", outer(c("date.", "iT."), c(1:3), paste0))]
      df
      #   id     date.1 iT.1     date.2 iT.2     date.3 iT.3
      # 1 A1 2010-01-15    z       <NA> <NA>       <NA> <NA>
      # 2 A2 2016-03-05    z 2013-09-03    w 2011-07-07    v
      # 3 C2 2017-05-21    v 2015-11-25    z       <NA> <NA>
      

      Online Demo

      【讨论】:

        【解决方案4】:

        “在同一行对齐”= reshape. ;)

        基础 R(重塑)

        df <- as.data.frame(df)[order(df$id),] # Convert to data frame and order by id
        df$time <- ave(df$id, df$id, FUN=seq_along) # Add "time" variable.
        
        stats::reshape(df, direction="wide", v.names=c("date","iT")) # just one line.
        

          id     date.1 iT.1     date.2 iT.2     date.3 iT.3
        1 A1 2010-01-15    z       <NA> <NA>       <NA> <NA>
        2 A2 2016-03-05    z 2013-09-03    w 2011-07-07    v
        3 C2 2017-05-21    v 2015-11-25    z       <NA> <NA>
        

        【讨论】:

          【解决方案5】:

          @Uwe 的回答效果很好。对于一个小数据,我也使用tidyverse找到了这种方式。

          %>% group_by(id) %>%
            summarise_at(vars(date, iT), paste, collapse = "; ") %>%
            separate(col = date, paste("date", 1:10, sep=""), sep = "; ", extra = "warn", fill = "right") %>%
            separate(col = iT, paste("iT", 1:10, sep=""), sep = "; ", extra = "warn", fill = "right") %>% 
            purrr::keep(~!all(is.na(.)))
          

          正如我所说,最好将它用于小数据,或者如果您想将重复 ID 的信息合并到一个单元格中。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-10-27
            • 2021-03-11
            • 1970-01-01
            • 1970-01-01
            • 2015-11-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多