我需要
pivot_longer
跨多组列,创建多个名称-值对。
例如,我需要从这样的地方开始:
df_raw <- tribble(
~id, ~belief_dog, ~belief_bull_frog, ~belief_fish, ~age, ~norm_bull_frog, ~norm_fish, ~norm_dog, ~gender,
"b2x8", 1, 4, 3, 41, 4, 2, 10, 2,
"m89w", 3, 6, 2, 19, 1, 2, 3, 1,
"32x8", 1, 5, 2, 38, 9, 1, 8, 3
)
然后把它变成这样的东西:
df_final <- tribble(
~id, ~belief_animal, ~belief_rating, ~norm_animal, ~norm_rating, ~age, ~gender,
"b2x8", "dog", 1, "bull_frog", 4, 41, 2,
"b2x8", "bull_frog", 4, "fish", 2, 41, 2,
"b2x8", "fish", 3, "dog", 10, 41, 2,
"m89w", "dog", 3, "bull_frog", 1, 19, 1,
"m89w", "bull_frog", 6, "fish", 2, 19, 1,
"m89w", "fish", 2, "dog", 3, 19, 1,
"32x8", "dog", 1, "bull_frog", 9, 38, 3,
"32x8", "bull_frog", 5, "fish", 1, 38, 3,
"32x8", "fish", 2, "dog", 8, 38, 3
)
换句话说,任何以“belief_”开头的内容都应该转换为一个名称-值对,而任何以“norm_”开头的内容都应该转换为另一个名称-值对。
我尝试查看其他几个具有相关内容的 Stack Overflow 页面,但无法将这些解决方案转化为这种情况。
任何帮助将不胜感激,对dplyr
解决方案有
strong偏好。
谢谢!
使用
tidyverse
,您可以旋转以 belief
和 norm
开头的两组列。然后,使用正则表达式根据第一个下划线进行分组(因为某些列名称有多个下划线)。本质上,我们将 belief
或 norm
(列名称中的第一个组)放入它们自己的列中(即 .value
),然后将组的第二部分(即动物名称)放入一个列中名为 animal
的列。
library(tidyverse)
df_raw %>%
pivot_longer(cols = c(starts_with("belief"), starts_with("norm")),
names_to = c('.value', 'animal'),
names_pattern = '(.*?)_(.*)') %>%
rename(belief_rating = belief, norm_rating = norm)
输出
id age gender animal belief_rating norm_rating
<chr> <dbl> <dbl> <chr> <dbl> <dbl>
1 b2x8 41 2 dog 1 10
2 b2x8 41 2 bull_frog 4 4
3 b2x8 41 2 fish 3 2
4 m89w 19 1 dog 3 3
5 m89w 19 1 bull_frog 6 1
6 m89w 19 1 fish 2 2
7 32x8 38 3 dog 1 8
8 32x8 38 3 bull_frog 5 9
9 32x8 38 3 fish 2 1
通过更多的实验解决了这个问题!
关键在于
names_to
和 names_pattern
参数。
df_raw %>% pivot_longer(
cols = c(belief_dog:belief_fish, norm_bull_frog:norm_dog),
names_to = c(".value", "rating"),
names_pattern = "([a-z]+)_*(.+)"
)
我不太明白
".value"
或正则表达式 "([a-z]+)_*(.+)"
是如何工作的,但解决方案仍然有效。
对于这些数据:
library(dplyr)
library(tidyr)
df_raw %>%
pivot_longer(
cols = -c(id, age, gender),
names_to = "name1",
values_to = "belief_rating"
) %>%
separate(name1, c("A", "B"), sep = '\\_' , extra = 'merge') %>%
group_by(id) %>%
mutate(helper = rep(row_number(), each=3, length.out = n())) %>%
pivot_wider(
names_from = A,
values_from = B,
names_glue = "{A}_animal"
) %>%
mutate(norm_rating = ifelse(helper == 1, lead(belief_rating, 3), NA),
norm_animal = ifelse(helper == 1, lead(norm_animal, 3), NA)) %>%
slice(1:3) %>%
select(id, belief_animal, belief_rating, norm_animal, norm_rating, age, gender)
id belief_animal belief_rating norm_animal norm_rating age gender
<chr> <chr> <dbl> <chr> <dbl> <dbl> <dbl>
1 32x8 dog 1 bull_frog 9 38 3
2 32x8 bull_frog 5 fish 1 38 3
3 32x8 fish 2 dog 8 38 3
4 b2x8 dog 1 bull_frog 4 41 2
5 b2x8 bull_frog 4 fish 2 41 2
6 b2x8 fish 3 dog 10 41 2
7 m89w dog 3 bull_frog 1 19 1
8 m89w bull_frog 6 fish 2 19 1
9 m89w fish 2 dog 3 19 1