根据 R 中不同列内的值对列内的值进行排序

Order values within column according to values within different column by group in R

我有以下面板数据集:

group  i  f  r  d
1      4  8  3  3
1      9  4  5  1
1      2  2  2  2
2      5  5  3  2
2      3  9  3  3
2      9  1  3  1

我想根据每个组的 d 列中的值重新排序此数据框中的 i 列。因此,第 i 列中第 1 组的最高值应对应于第 d 列中的最高值。最后我的 data.frame 应该是这样的:

group  i  f  r  d
1      9  8  3  3
1      2  4  5  1
1      4  2  2  2
2      5  5  3  2
2      9  9  3  3
2      3  1  3  1

这是一个dplyr解决方案。

首先,按 group 分组。然后在临时新列 ord 中获取列 d 的排列重排,并用它重新排序 i.

library(dplyr)

df1 %>%
  group_by(group) %>%
  mutate(ord = order(d),
         i = i[ord]) %>%
  ungroup() %>%
  select(-ord)
## A tibble: 6 x 5
#  group     i     f     r     d
#  <int> <int> <int> <int> <int>
#1     1     9     8     3     3
#2     1     2     4     5     1
#3     1     4     2     2     2
#4     2     9     5     3     2
#5     2     5     9     3     3
#6     2     3     1     3     1

原创(错误)

您可以使用 dplyrrank 实现此目的:

library(dplyr)

df1 %>% group_by(group) %>%
  mutate(i = i[rev(rank(d))])

编辑

这个问题实际上比乍看起来更棘手,我发布的原始答案不正确。在按 d 的等级子集之前,正确的解决方案按 i 排序。这给出了 OP 所需的输出,而我之前的回答没有(没有注意!)

df1 %>% group_by(group) %>%
  mutate(i = i[order(i)][rank(d)])
# A tibble: 6 x 5
# Groups:   group [2]
#  group     i     f     r     d
#  <int> <int> <int> <int> <int>
#1     1     9     8     3     3
#2     1     2     4     5     1
#3     1     4     2     2     2
#4     2     5     5     3     2
#5     2     9     9     3     3
#6     2     3     1     3     1

预期输出有些混乱。在这里,我展示了一种获取两个版本输出的方法。

使用 splitmapply

的基础 R
df$i <- c(mapply(function(x, y) sort(y)[x], 
                  split(df$d, df$group), split(df$i, df$group)))

df
#  group i f r d
#1     1 9 8 3 3
#2     1 2 4 5 1
#3     1 4 2 2 2
#4     2 5 5 3 2
#5     2 9 9 3 3
#6     2 3 1 3 1

或其他版本

df$i <- c(mapply(function(x, y) y[order(x)], 
                 split(df$d, df$group), split(df$i, df$group)))

df
#  group i f r d
#1     1 9 8 3 3
#2     1 2 4 5 1
#3     1 4 2 2 2
#4     2 9 5 3 2
#5     2 5 9 3 3
#6     2 3 1 3 1

我们也可以为此使用 dplyr :

第一个版本

library(dplyr)
df %>%
  group_by(group) %>%
  mutate(i = sort(i)[d])

@Rui 已经使用 order

展示了第二个版本
df %>%
  group_by(group) %>%
  mutate(i = i[order(d)])

选项data.table

library(data.table)
setDT(df1)[, i := i[order(d)], group]
df1
#   group i f r d
#1:     1 9 8 3 3
#2:     1 2 4 5 1
#3:     1 4 2 2 2
#4:     2 9 5 3 2
#5:     2 5 9 3 3
#6:     2 3 1 3 1

如果我们需要第二个版本

setDT(df1)[, i := sort(i)[d], group]

数据

df1 <- structure(list(group = c(1L, 1L, 1L, 2L, 2L, 2L), i = c(4L, 9L, 
2L, 5L, 3L, 9L), f = c(8L, 4L, 2L, 5L, 9L, 1L), r = c(3L, 5L, 
2L, 3L, 3L, 3L), d = c(3L, 1L, 2L, 2L, 3L, 1L)), class = "data.frame",
row.names = c(NA, 
-6L))