我有一个带有两个id变量和多个变量的数据框。在这些变量中,一些变量仅取决于id1
而变化,而其他变量则取决于id1
和id2
。现在,我想使用tidyr::pivot_wider()
重塑数据框的范围。下面是一个代表,实际数据集包含更多的变量。
library(tidyverse)
set.seed(42)
(d <- tibble(
id1 = rep(LETTERS[1:4], each = 3),
id2 = rep(letters[1:3], length.out = 12),
x = rpois(12, 3),
y = rep(rpois(4, 5), each = 3)
))
#> # A tibble: 12 x 4
#> id1 id2 x y
#> <chr> <chr> <int> <int>
#> 1 A a 5 9
#> 2 A b 6 9
#> 3 A c 2 9
#> 4 B a 5 3
#> 5 B b 3 3
#> 6 B c 3 3
#> 7 C a 4 5
#> 8 C b 1 5
#> 9 C c 4 5
#> 10 D a 4 9
#> 11 D b 3 9
#> 12 D c 4 9
透视示例框架将产生以下框架:
(d <- pivot_wider(d, names_from = id2, values_from = x:y))
#> # A tibble: 4 x 7
#> id1 x_a x_b x_c y_a y_b y_c
#> <chr> <int> <int> <int> <int> <int> <int>
#> 1 A 5 6 2 9 9 9
#> 2 B 5 3 3 3 3 3
#> 3 C 4 1 4 5 5 5
#> 4 D 4 3 4 9 9 9
从输出中可以看到,y_a
,y_b
和y_c
都是相同的,因此是重复的。
我想得到的是一个没有冗余的数据帧:
d %>%
rename(y = y_a) %>%
select(-y_b, -y_c)
#> # A tibble: 4 x 5
#> id1 x_a x_b x_c y
#> <chr> <int> <int> <int> <int>
#> 1 A 5 6 2 9
#> 2 B 5 3 3 3
#> 3 C 4 1 4 5
#> 4 D 4 3 4 9
该解决方案应产生一个没有重复列的数据帧,并且无需用户输入就可以产生多余的列。 tidyverse解决方案会很好,但是也欢迎其他解决方案。
到目前为止,我自己想解决的唯一方法是编写一个函数,该函数根据前缀识别列组,然后检查组中的列是否相同,删除冗余列并重命名剩下的变量删除后缀。我认为这一定是更简洁的方法。
我也对此问题进行了搜索,但结果往往是关于重复的列名或重复的行,并且没有为眼前的问题找到任何解决方案。
答案 0 :(得分:2)
我找到了一个可行的解决方案,但这并不漂亮。它依赖于选择帮助器tidyselect::where()
和一个lambda函数,如果存在至少一个TRUE
的唯一值且id1
中有多个唯一的对应元素,则该函数将返回.x
其他FALSE
。
d %>%
pivot_wider(
names_from = id2,
names_glue = "{.value}_{id2}",
values_from = where(~ tibble(d$id1, .x) %>%
distinct() %>%
{
nrow(.) != length(unique(.[[1]])) & !identical(d$id2, .x)
})
)
#> # A tibble: 4 x 5
#> id1 y x_a x_b x_c
#> <chr> <int> <int> <int> <int>
#> 1 A 9 5 6 2
#> 2 B 3 5 3 3
#> 3 C 5 4 1 4
#> 4 D 9 4 3 4
答案 1 :(得分:1)
请勿在{{1}}中使用y
。试试:
values_from
答案 2 :(得分:0)
此解决方案可提供所需的输出
pivot_wider(d, names_from = id2, names_glue = "{.value}_{id2}", values_from = x)
输出
# id1 y x_a x_b x_c
# <chr> <int> <int> <int> <int>
# 1 A 9 5 6 2
# 2 B 3 5 3 3
# 3 C 5 4 1 4
# 4 D 9 4 3 4