如何在R中使用多个列类别(无数字)进行pivot_langer

  • 本文关键字:无数字 进行 langer pivot r dplyr
  • 更新时间 :
  • 英文 :


我有一个类似于以下的df:

df <- data.frame("name" = c("sue","joe","tom"),
"x0_date" = c("2020-1-20", "2020-2-20", "2020-3-20"),
"x0_class" = c("biology", "physics", "chemistry"),
"x1_date" = c("2021-4-18", NA, "2021-6-18"),
"x1_class" = c("english", NA, "drama"))
df
name   x0_date  x0_class   x1_date x1_class
1  sue 2020-1-20   biology 2021-4-18  english
2  joe 2020-2-20   physics      <NA>     <NA>
3  tom 2020-3-20 chemistry 2021-6-18    drama

我正在努力调整更长的时间,这样我的结果如下:

name      date     class
1  sue 2020-1-20   biology
2  sue 2021-4-18   english
3  joe 2020-2-20   physics
4  tom 2020-3-20 chemistry
5  tom 2021-6-18     drama

我想我只在某些数据是数字的时候才进行过数据透视,所以我遇到了麻烦。我试过这样的东西:

test <- df %>% 
pivot_longer(matches("date|class"),
names_to = c("date", "class"), 
names_pattern = "(\d+)_(.+)",
values_drop_na = TRUE)

但产出并不完全正确。如果相关的话,我的宽数据是非常宽的("x0"到"x_400"(。感谢您的帮助!

我们需要names_to作为.value。根据?pivot_longer

names_to-如果长度>1,将创建多个列。在这种情况下,必须提供names_sep或names_pattern中的一个来指定如何拆分列名。还有两个额外的字符值可以利用:

NA将丢弃列名的相应组件。

"。值";指示列名的相应组件定义包含单元格值的输出列的名称,完全覆盖values_to。

因此,将其指定为.value,并使用names_pattern仅捕获_之后的字符,即(_(.*)(

library(dplyr)
library(tidyr)
df %>% 
pivot_longer(cols = -name, names_to = c(".value"),
names_pattern = ".*_(.*)", values_drop_na = TRUE)

-输出

# A tibble: 5 × 3
name  date      class    
<chr> <chr>     <chr>    
1 sue   2020-1-20 biology  
2 sue   2021-4-18 english  
3 joe   2020-2-20 physics  
4 tom   2020-3-20 chemistry
5 tom   2021-6-18 drama    

如果我们需要x0x1前缀作为另一列,那么我们需要为前缀指定列名,还需要捕获前缀部分

df %>%
pivot_longer(cols = -name, names_to = c("categ", ".value"),
names_pattern = "(.*)_(.*)", values_drop_na = TRUE)

-输出

# A tibble: 5 × 4
name  categ date      class    
<chr> <chr> <chr>     <chr>    
1 sue   x0    2020-1-20 biology  
2 sue   x1    2021-4-18 english  
3 joe   x0    2020-2-20 physics  
4 tom   x0    2020-3-20 chemistry
5 tom   x1    2021-6-18 drama    

OP代码不起作用的原因

df %>% 
+   pivot_longer(matches("date|class"),
+     names_to = c("date", "class"), 
+     names_pattern = "(\d+)_(.+)",
+     values_drop_na = TRUE)
# A tibble: 10 × 4
name  date  class value    
<chr> <chr> <chr> <chr>    
1 sue   0     date  2020-1-20
2 sue   0     class biology  
3 sue   1     date  2021-4-18
4 sue   1     class english  
5 joe   0     date  2020-2-20
6 joe   0     class physics  
7 tom   0     date  2020-3-20
8 tom   0     class chemistry
9 tom   1     date  2021-6-18
10 tom   1     class drama    

是因为它捕获了_之前的一个或多个数字(\d+(,然后将其余的(.+(作为列前缀和后缀,因此我们从"date"中的"x0"、"x1"one_answers"class"中的后缀部分获得了0,1,由于我们没有指定.value,默认列value将返回列的值

  • 我们可以通过将df拆分为列名为name , data , classdata.frame列表来使用Base Rrbind函数
lapply(1:((ncol(df)-1)/2) , (i) df[c(1,2*i,2*i+1)]) |> 
lapply((x) {colnames(x) <- c("name" , "data" , "class") ; x}) |> 
do.call(rbind , args = _) |> na.omit()
  • 输出
name      data     class
1  sue 2020-1-20   biology
2  joe 2020-2-20   physics
3  tom 2020-3-20 chemistry
4  sue 2021-4-18   english
6  tom 2021-6-18     drama

最新更新