使用多个 ID 列和值列通过 pivot_longer() 简化 gather()
Simplifying gather() with pivot_longer() using multiple ID columns and value columns
我正在努力更好地处理来自 gather
用户的 pivot_longer
。从源文档看来,我应该能够使用 name_pattern 或 names_sep
在单个命令中执行以下操作,但我一直无法找到可行的解决方案。
数据
id1 <- c("person1","person2","person3")
id2 <- c("1001","1002","1003")
id3 <- c("2001","2002", "2003")
value_1 <- c(10,50,100)
value_2 <- c(20,200, 2000)
status_1 <- c("OK","BAD","GOOD")
status_2 <- c("AWFUL","EXCELLENT","AVERAGE")
df <- data.frame(id1,id2,id3,value_1,value_2,status_1,status_2)
预期输出:
id1 id2 id3 gradeLevel status value
1 person1 1001 2001 1 OK 10
2 person1 1001 2001 2 AWFUL 20
3 person2 1002 2002 1 BAD 50
4 person2 1002 2002 2 EXCELLENT 200
5 person3 1003 2003 1 GOOD 100
6 person3 1003 2003 2 AVERAGE 2000
我可以通过 gather
语句和一些额外的行来实现:
df %>%
gather(key, value,-id1, -id2,-id3) %>%
separate(key, c('cat', 'gradeLevel'),sep ="_") %>%
distinct() %>%
spread(cat,value)
有没有办法用 pivot_longer
来简化这个?我认为 names_pattern 很有前途,但我在正则表达式方面遇到了困难。我的大部分尝试都是尝试组合不同类型的列(双精度和因子)
df %>%
pivot_longer(cols = value_1:status_2, names_to = c('col', '.value'), names_pattern = "(.*)_(.)")
您可以使用以下解决方案。在本例中,我们创建了 2 个捕获组。 .value
在这里所做的实际上是为 pivot_longer
定义名称的一部分,其中包含我们要测量的值的名称。这里下划线的左边是值 value
和 status
。下划线的右侧实际上是我们第二个捕获组的结果定义了 id
。并且应该注意 names_to
参数的长度应该与 names_pattern
或可能 names_sep
.
中捕获组的数量相同
library(tidyr)
df %>%
pivot_longer(!c(id1, id2, id3), names_to = c(".value", "gradelevel"),
names_pattern = "(\w+)_(\d+)")
# A tibble: 6 x 6
id1 id2 id3 gradelevel value status
<chr> <chr> <chr> <chr> <dbl> <chr>
1 person1 1001 2001 1 10 OK
2 person1 1001 2001 2 20 AWFUL
3 person2 1002 2002 1 50 BAD
4 person2 1002 2002 2 200 EXCELLENT
5 person3 1003 2003 1 100 GOOD
6 person3 1003 2003 2 2000 AVERAGE
我正在努力更好地处理来自 gather
用户的 pivot_longer
。从源文档看来,我应该能够使用 name_pattern 或 names_sep
在单个命令中执行以下操作,但我一直无法找到可行的解决方案。
数据
id1 <- c("person1","person2","person3")
id2 <- c("1001","1002","1003")
id3 <- c("2001","2002", "2003")
value_1 <- c(10,50,100)
value_2 <- c(20,200, 2000)
status_1 <- c("OK","BAD","GOOD")
status_2 <- c("AWFUL","EXCELLENT","AVERAGE")
df <- data.frame(id1,id2,id3,value_1,value_2,status_1,status_2)
预期输出:
id1 id2 id3 gradeLevel status value
1 person1 1001 2001 1 OK 10
2 person1 1001 2001 2 AWFUL 20
3 person2 1002 2002 1 BAD 50
4 person2 1002 2002 2 EXCELLENT 200
5 person3 1003 2003 1 GOOD 100
6 person3 1003 2003 2 AVERAGE 2000
我可以通过 gather
语句和一些额外的行来实现:
df %>%
gather(key, value,-id1, -id2,-id3) %>%
separate(key, c('cat', 'gradeLevel'),sep ="_") %>%
distinct() %>%
spread(cat,value)
有没有办法用 pivot_longer
来简化这个?我认为 names_pattern 很有前途,但我在正则表达式方面遇到了困难。我的大部分尝试都是尝试组合不同类型的列(双精度和因子)
df %>%
pivot_longer(cols = value_1:status_2, names_to = c('col', '.value'), names_pattern = "(.*)_(.)")
您可以使用以下解决方案。在本例中,我们创建了 2 个捕获组。 .value
在这里所做的实际上是为 pivot_longer
定义名称的一部分,其中包含我们要测量的值的名称。这里下划线的左边是值 value
和 status
。下划线的右侧实际上是我们第二个捕获组的结果定义了 id
。并且应该注意 names_to
参数的长度应该与 names_pattern
或可能 names_sep
.
library(tidyr)
df %>%
pivot_longer(!c(id1, id2, id3), names_to = c(".value", "gradelevel"),
names_pattern = "(\w+)_(\d+)")
# A tibble: 6 x 6
id1 id2 id3 gradelevel value status
<chr> <chr> <chr> <chr> <dbl> <chr>
1 person1 1001 2001 1 10 OK
2 person1 1001 2001 2 20 AWFUL
3 person2 1002 2002 1 50 BAD
4 person2 1002 2002 2 200 EXCELLENT
5 person3 1003 2003 1 100 GOOD
6 person3 1003 2003 2 2000 AVERAGE