首页 > 解决方案 > 使用 pivot_longer 将列分隔为长格式

问题描述

我有一个非有限长度的 df,如下表所示。这里的示例只有 2 个特征:“脂质”和“密度”。其他行可能有 50 个或更多特征。但将始终具有相同的特征、单位、方法模式。使用 read_excel 导入 R 时,它会将非唯一名称更改为 xxx...[col.number]。我想使用 pivot_longer 将数据从宽转换为长格式。我在操作该函数时遇到了困难,希望能得到一些帮助。我想要的最终列名是 geno_name、observation_id、trait、value、unit、method

样本数据 样本数据

期望的输出(没有 drop_na 语句来显示示例) 在此处输入图像描述

x <- structure(list(geno_name = "MB mixed", observation_id = 10, lipids = NA, 
    unit...3 = NA, method...4 = NA, density = 1.125, unit...6 = "g cm^-3", 
    method...7 = "3D scanning"), class = "data.frame", row.names = c(NA,-1L))

到目前为止,我有:

x %>% pivot_longer(
    cols = 3:ncol(x),
    names_to = c("trait","unit","method"),
    #need help with these other arguments
    values_drop_na = T)

标签: r

解决方案


以“长”格式使用的数据列名称在列名称中并不都具有相同的模式。因此,包括的步骤是

  • 重命名列名中没有..._的列,方法是添加paste/str_c

  • 整形为长格式pivot_longer- 考虑到名称中的模式names_sepnames_pattern,将 指定names_to为向量 的c(".value", "trait")顺序与我们希望将列值和后缀值存储为单独的列的顺序相同

  • 一旦我们重新塑造,创建一个基于“特征”中的值的分组列(其中一些是数字 - 创建一个逻辑向量并获得累积总和)以及其他分组“geno_name”,“observation_id”(不t 创建一个唯一的列))

  • 现在summarise其他列通过在基于 NA 元素排序后切片第一行,即如果没有 NA,第一个值将是非 NA,否则它将是 NA

library(dplyr)
library(stringr)
library(tidyr)
x %>%
   rename_at(vars(names(.)[!str_detect(names(.), "[_.]+")]), 
       ~ str_c("value...", .)) %>%
   pivot_longer(cols = 3:ncol(.), 
      names_to = c(".value", "trait"), names_sep = "\\.+") %>% 
   group_by(geno_name, observation_id, 
       grp = cumsum(str_detect(trait, "\\D+"))) %>%
   summarise(across(everything(), ~ .[order(is.na(.))][1]),
         .groups = 'drop') %>%
   select(-grp)

-输出

# A tibble: 2 x 6
#  geno_name observation_id trait   value unit    method     
#  <chr>              <dbl> <chr>   <dbl> <chr>   <chr>      
#1 MB mixed              10 lipids  NA    <NA>    <NA>       
#2 MB mixed              10 density  1.12 g cm^-3 3D scanning

数据

x <- structure(list(geno_name = "MB mixed", observation_id = 10, lipids = NA, 
    unit...3 = NA, method...4 = NA, density = 1.125, unit...6 = "g cm^-3", 
    method...7 = "3D scanning"), class = "data.frame", row.names = c(NA, 
-1L))

推荐阅读