在组内重新排序因子水平

5

我希望在一个分组列内重新排列一个因子变量的水平。

以下是一个简单的数据集示例:

df <- structure(list(a_factor = structure(1:6, .Label = c("a", "b", 
"c", "d", "e", "f"), class = "factor"), group = structure(c(1L, 
1L, 1L, 2L, 2L, 2L), .Label = c("group1", "group2"), class = "factor"), 
value = 1:6), class = "data.frame", row.names = c(NA, -6L
))

> df
  a_factor  group value
1        a group1     1
2        b group1     2
3        c group1     3
4        d group2     4
5        e group2     5
6        f group2     6

更精确地说,我如何重新排序因子水平,例如按value降序排列,其中df$group == "group1",但按value升序排列,其中df$group == "group2",最好使用dplyr?
预期输出可能是:
> df
  a_factor  group value
1        c group1     3
2        b group1     2
3        a group1     1
4        d group2     4
5        e group2     5
6        f group2     6

虽然问题更一般地涉及如何在dplyr中解决这个问题。


你需要 df %>% arrange(group, desc(value)) 吗? - akrun
不,我需要更多控制如何在不同组之间排列值(或理想情况下是因子水平)。因此,对于group == group1,我可能希望保持升序排序,但对于group == group2,我可能希望降序排序(或者反过来,这只是一个例子)。 - Joris
你可以更新一下预期输出吗? - akrun
4个回答

2
我们可以根据组值进行否定,然后排序:

按照组值进行否定,再进行排序:

df %>% 
  arrange(case_when(
    group == "group1" ~ -value,
    group == "group2" ~ value))

#   a_factor  group value
# 1        c group1     3
# 2        b group1     2
# 3        a group1     1
# 4        d group2     4
# 5        e group2     5
# 6        f group2     6

2
以下是基于R语言的解决方案。
sp <- split(df$value, df$group)
sp <- lapply(seq_along(sp), function(i) sort(sp[[i]], decreasing = i == 1))
df$a_factor <- factor(df$a_factor, levels = df$a_factor[unlist(sp)])

df$a_factor
#[1] a b c d e f
#Levels: c b a d e f

df[order(df$a_factor), ]
#  a_factor  group value
#3        c group1     3
#2        b group1     2
#1        a group1     1
#4        d group2     4
#5        e group2     5
#6        f group2     6

1
一个选项是使用group_split并传递一个逻辑值列表,对应于如何执行arrange
library(tidyverse)   
df %>% 
    group_split(group) %>%
    map2_df(., list(FALSE, TRUE), ~ if(.y) .x %>%
       arrange(value) else  .x %>% arrange(desc(value)))
# A tibble: 6 x 3
#  a_factor group  value
#  <fct>    <fct>  <int>
#1 c        group1     3
#2 b        group1     2
#3 a        group1     1
#4 d        group2     4
#5 e        group2     5
#6 f        group2     6

1

要重新排列因子水平,您可以使用 forcatstidyverse 的一部分),并执行以下操作...

library(forcats)
df2 <- df %>% mutate(a_factor = fct_reorder(a_factor,
                                            value*(-1 + 2 * (group=="group1"))))

levels(df2$a_factor)
[1] "f" "e" "d" "a" "b" "c"

这不会重新排列数据框本身...

df2
  a_factor  group value
1        a group1     1
2        b group1     2
3        c group1     3
4        d group2     4
5        e group2     5
6        f group2     6

1
这更接近我所希望的解决方案,因为它正在重新排序因子水平。您能解释一下fct_reorder中的代码是什么意思,特别是value*(-1 + 2 * 部分? - Joris
@Joris 如果 group 不是 group1,则 -1+2*(group=="group1") 的值为 -1,如果是 group1,则值为 +1。因此,级别将根据序列 1,2,3,-4,-5,-6 的排序进行重新排序,即 -6,-5,-4,1,2,3。我刚刚注意到你实际上想要它们相反,所以只需在公式中用 group2 替换 group1 即可。对此感到抱歉! - Andrew Gustar
哦,反正这只是一个例子,两种方式都可以。非常感谢您的解释! - Joris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接