【问题标题】:Convert multiple rows to multiple columns (long to wide format does not work (?))将多行转换为多列(长到宽格式不起作用(?))
【发布时间】:2026-01-06 21:10:01
【问题描述】:

我有一个包含多篇期刊文章的数据集。不同的物品都有不同的识别码(WoS_No)。不同的文章在不同的行。

这些文章有不同数量的作者。如果一篇论文的作者多于 1 位,则识别码会在多行中重复,每个作者一行。

df 中还有其他信息,其中一些与论文有关(并且对于具有相同 WoS_No 代码的所有行都是相同的。但是,有些仅与作者有关​​(如他们的教师),然后打印出来超过行。

请看下面的例子:

# Original df
df <- data.frame("WoS_No" = matrix(c("WOS:000352315900021", "WOS:000352315900021", "WOS:000352315900021", "WOS:000352315900021", "WOS:000362644700013", "WOS:000362644700013", "WOS:000382460200025", "WOS:000381736200014", "WOS:000371540200019"), 9, 1))
df$Author <- c("CHENEVIX, Georg", "CHENEVIX, Georg", "DOLCE, Ric", "DOLCE, Ric", "CLOUST, A", "STEVEN, A", "WANG, Zhi", "COIN, L", "BARL, Kare")
df$Faculty <- c("Medicine", NA, "HASS", NA, "HABS", "Medicine", "Medicine", "IMB", NA)
df$CNCI <- c(10.51, 10.51, 10.51, 10.51, 37.47, 37.47,  0.84,  8.05, 29.41)
sapply(data2, class)

我真的很想安排 df,这样每篇文章只有 1 行(即每行一个 WoS_No)。

我希望将作者姓名分成不同的列(请参阅下面的“Author1”、“Author2”列)。我尝试从长格式转换为宽格式,但没有成功,可能是因为大多数文章的作者不同 - 所以它给每个名字一个新列(我不能有,因为大约有 20,000 个名字)

如果这太繁琐,我会很高兴将所有作者姓名折叠到“作者”列中的一个字符串中,所有姓名用分号分隔(这意味着我可以稍后在需要时将它们拆分)。请参阅下面的“学院”列。

# New df options

dfnew <- data.frame("WoS_No" = matrix(c("WOS:000352315900021", "WOS:000362644700013", "WOS:000382460200025", "WOS:000381736200014", "WOS:000371540200019"), 5, 1))
dfnew$Author1 <- c("CHENEVIX, Georg", "CLOUST, A", "WANG, Zhi", "COIN, L", "BARL, Kare")
dfnew$Author2 <- c("DOLCE, Ric", "STEVEN, A", "", "", "")
dfnew$Faculties <- c("Medicine; NA; HASS; NA", "HABS; Medicine", "Medicine", "IMB", "NA")
dfnew$CNCI <- c(10.51, 37.47,  0.84,  8.05, 29.41)

我尝试循环遍历每个 WoS_No 并一个一个地折叠,但因为我有 68,000 个 WoS_No,所以未能在合理的时间内完成。

我真的很难过,非常感谢任何人能给我的任何帮助。

【问题讨论】:

    标签: r dataframe rows reshape


    【解决方案1】:

    您可以首先使用distinctgroup_byWoS_No 仅保留唯一行,以创建唯一标识符列并获取宽格式数据。

    library(dplyr)
    
    df %>%
      distinct(WoS_No, Author, .keep_all = TRUE) %>%
      group_by(WoS_No) %>%
      mutate(row = row_number()) %>%
      tidyr::pivot_wider(names_from = row, values_from = c(Author, Faculty))
    
    #  WoS_No               CNCI Author_1        Author_2   Faculty_1 Faculty_2
    #  <chr>               <dbl> <chr>           <chr>      <chr>     <chr>    
    #1 WOS:000352315900021 10.5  CHENEVIX, Georg DOLCE, Ric Medicine  HASS     
    #2 WOS:000362644700013 37.5  CLOUST, A       STEVEN, A  HABS      Medicine 
    #3 WOS:000382460200025  0.84 WANG, Zhi       NA         Medicine  NA       
    #4 WOS:000381736200014  8.05 COIN, L         NA         IMB       NA       
    #5 WOS:000371540200019 29.4  BARL, Kare      NA         NA        NA 
    

    请注意,我还将Faculty 转换为不同的列。如果您想将它们保留在一列中,如您的预期输出所示,您可以在代码中进行最少的更改。

    【讨论】:

      【解决方案2】:

      使用漂亮的reshape() 的一个不起眼的基础 R 解决方案:

      data <- df[!duplicated(df[, c("WoS_No", "Author")]),]
      data$grp.id <- ave(data$WoS_No, data$WoS_No, FUN = seq_along)
      
      reshaped_data  <- reshape(data, idvar= "WoS_No", timevar= "grp.id",
                                v.names=c("Author", "Faculty"), direction="wide")
      
                     WoS_No  CNCI        Author.1 Faculty.1   Author.2 Faculty.2
      1 WOS:000352315900021 10.51 CHENEVIX, Georg  Medicine DOLCE, Ric      HASS
      5 WOS:000362644700013 37.47       CLOUST, A      HABS  STEVEN, A  Medicine
      7 WOS:000382460200025  0.84       WANG, Zhi  Medicine       <NA>      <NA>
      8 WOS:000381736200014  8.05         COIN, L       IMB       <NA>      <NA>
      9 WOS:000371540200019 29.41      BARL, Kare      <NA>       <NA>      <NA>
      
      

      idvar 标识了我们想要在其中传播的组。

      timevar 标识组内的观察。我们需要为此创建grp.id

      v.names 命名我们要传播的列。

      direction 告诉我们转换为宽格式。

      【讨论】:

        【解决方案3】:

        这是一个解决方案,其中您将 AuthorsFaculties 用分号分隔,就像您预期的输出一样。

        library(dplyr)
        
        df %>% 
          group_by(WoS_No) %>% 
          mutate(
            Authors = paste(unique(Author), collapse = "; "),
            Faculties = paste(Faculty, collapse = "; ")
            ) %>% 
          select(WoS_No, Authors, Faculties, CNCI) %>% 
          distinct()
        
        # A tibble: 5 x 4
        # Groups:   WoS_No [5]
        #   WoS_No              Authors                     Faculties               CNCI
        #   <chr>               <chr>                       <chr>                  <dbl> 
        # 1 WOS:000352315900021 CHENEVIX, Georg; DOLCE, Ric Medicine; NA; HASS; NA 10.5 
        # 2 WOS:000362644700013 CLOUST, A; STEVEN, A        HABS; Medicine         37.5  
        # 3 WOS:000382460200025 WANG, Zhi                   Medicine                0.84
        # 4 WOS:000381736200014 COIN, L                     IMB                     8.05
        # 5 WOS:000371540200019 BARL, Kare                  NA                     29.4 
        

        【讨论】:

          【解决方案4】:

          这是一个data.table-方法

          library( data.table )
          #make df a data.table
          setDT(df)
          #first, paste the (unique) authors together by WoS_No
          ans <- df[, .( authors = paste0( unique(Author), collapse = ";" ),
                         Faculty = paste0( Faculty, collapse = ";" ),
                         CNCI = unique(CNCI) ), by = WoS_No][]
          #                 WoS_No                    authors             Faculty  CNCI
          # 1: WOS:000352315900021 CHENEVIX, Georg;DOLCE, Ric Medicine;NA;HASS;NA 10.51
          # 2: WOS:000362644700013        CLOUST, A;STEVEN, A       HABS;Medicine 37.47
          # 3: WOS:000382460200025                  WANG, Zhi            Medicine  0.84
          # 4: WOS:000381736200014                    COIN, L                 IMB  8.05
          # 5: WOS:000371540200019                 BARL, Kare                  NA 29.41
          
          #split the author column
          ans[, paste0( "Author", 1:length(tstrsplit( ans$authors, ";" ) )) := tstrsplit( authors, ";")]
          #                 WoS_No                    authors             Faculty  CNCI         Author1    Author2
          # 1: WOS:000352315900021 CHENEVIX, Georg;DOLCE, Ric Medicine;NA;HASS;NA 10.51 CHENEVIX, Georg DOLCE, Ric
          # 2: WOS:000362644700013        CLOUST, A;STEVEN, A       HABS;Medicine 37.47       CLOUST, A  STEVEN, A
          # 3: WOS:000382460200025                  WANG, Zhi            Medicine  0.84       WANG, Zhi       <NA>
          # 4: WOS:000381736200014                    COIN, L                 IMB  8.05         COIN, L       <NA>
          # 5: WOS:000371540200019                 BARL, Kare                  NA 29.41      BARL, Kare       <NA>
          

          【讨论】:

            最近更新 更多