根据 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
原创(错误)
您可以使用 dplyr
和 rank
实现此目的:
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
预期输出有些混乱。在这里,我展示了一种获取两个版本输出的方法。
使用 split
和 mapply
的基础 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))
我有以下面板数据集:
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
原创(错误)
您可以使用 dplyr
和 rank
实现此目的:
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
预期输出有些混乱。在这里,我展示了一种获取两个版本输出的方法。
使用 split
和 mapply
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))