You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言中对两组列执行pivot_longer的正确实现方法咨询

问题描述

给定以下使用tidyverse创建的数据集:

library(tidyverse)

df <- data.frame(names = c("John", "Peter", "Mary", "Allan", "Anne"),
                 year = 2001:2005,
                 first_class = letters[1:5],
                 second_class = c("NA", "c", "d", "NA", "e"),
                 third_class = c(letters[1:3], "NA", "NA"),
                 first_day = c("one", "two", "NA", "two", "one"),
                 second_day = c("two", "NA", "one", "one", "two"),
                 third_day = c("NA", "one", "two", "NA", "two"))

需要对first_class:third_class和first_day:third_day这两组列执行pivot_longer操作,尝试了以下代码:

df |>
  pivot_longer(cols = first_class:third_class,
               values_to = "my_class",
               names_to = NULL) |>
  pivot_longer(cols = first_day:third_day,
               values_to = "my_day",
               names_to = NULL)

但输出出现信息重复(两次pivot生成笛卡尔积导致45行结果):

# A tibble: 45 × 4
   names  year my_class my_day
   <chr> <int> <chr>    <chr> 
 1 John   2001 a        one   
 2 John   2001 a        two   
 3 John   2001 a        NA    
 4 John   2001 NA       one   
 5 John   2001 NA       two   
 6 John   2001 NA       NA    
 7 John   2001 a        one   
 8 John   2001 a        two   
 9 John   2001 a        NA    
10 Peter  2002 b        two  

预期结果是按first/second/third的对应关系匹配class和day:

names year my_class my_day
1  John 2001        a    one
2  John 2001       NA    two
3  John 2001        a     NA
4 Peter 2002        b    two
5 Peter 2002        c     NA
6 Peter 2002        b    one
解决方案

两次独立的pivot_longer会生成笛卡尔积(每个class对应所有day),正确做法是一次pivot_longer同时处理两组列,通过提取列名中的共同前缀关联class和day:

df |>
  pivot_longer(
    cols = starts_with(c("first_", "second_", "third_")),
    names_to = c("group", ".value"),
    names_sep = "_"
  ) |>
  rename(my_class = class, my_day = day)

代码说明:

  • cols = starts_with(c("first_", "second_", "third_")):选中所有以first_/second_/third_开头的目标列
  • names_to = c("group", ".value"):按_分割列名,第一部分(first/second/third)存入group列,第二部分(class/day)作为新的列名(.value表示这部分是值的类型)
  • rename:将自动生成的class和day列重命名为需求的my_class和my_day

执行后得到的结果与预期一致,若不需要group列,可在管道末尾添加select(-group):

df |>
  pivot_longer(
    cols = starts_with(c("first_", "second_", "third_")),
    names_to = c("group", ".value"),
    names_sep = "_"
  ) |>
  rename(my_class = class, my_day = day) |>
  select(-group)

内容的提问来源于stack exchange,提问作者always.learning

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:57:48