提取 data.frame 中与另一个 data.frame 中的值匹配的所有 row.names
Extract all row.names in a data.frame that match a value in another data.frame
我有一个包含 150 个列名的 data.frame。对于每一列,我想提取最大值和最小值(行重复)以及每个最大值的行名称。我在另一个 data.frame 中提取了最小值和最大值,但不知道如何匹配它们。
我找到了与此非常接近的函数,例如最小值:
head(cars)
speed dist
1 4 2
2 4 10
3 7 4
4 7 22
5 8 16
6 9 10
sapply(cars,which.min)
speed dist
1 1
这里只给出最低速度的第一个指标
我试过像这样的循环:
for (i in (colnames(cars))){
print(min(cars[[i]]))
}
[1] 4
[1] 2
但这只是给我最小值,而不是如果它们重复以及每个重复值的行名。
我想要这样的东西:
min.value column rowname freq.times
4 speed 1,2 2
2 dist 1 1
谢谢,如果我有拼写错误,请见谅。没有母语人士
min.value <- sapply(cars, min)
columns <- names(min.value)
row.values <- sapply(columns, \(x) which(cars[[x]] == min.value[which(names(min.value) == x)]))
freq.times <- sapply(row.values, length)
row.values <- sapply(row.values, \(x) paste(x, collapse = ","))
names(min.value) <- names(row.values) <- names(freq.times) <- NULL
data.frame(min.value = min.value,
columns = columns,
row.values = row.values,
freq.times = freq.times)
min.value columns row.values freq.times
1 4 speed 1,2 2
2 2 dist 1 1
这里它被包装在函数中,这样你就可以在任何你需要的数据框和函数中使用它:
create_table <- function(df, FUN) {
values <- sapply(df, FUN)
columns <- names(values)
row.values <- sapply(columns, \(x) which(df[[x]] == values[which(names(values) == x)]))
freq.times <- sapply(row.values, length)
row.values <- sapply(row.values, \(x) paste(x, collapse = ","))
names(values) <- names(row.values) <- names(freq.times) <- NULL
data.frame(values = values,
columns = columns,
row.values = row.values,
freq.times = freq.times)
}
create_table(cars, min)
values columns row.values freq.times
1 4 speed 1,2 2
2 2 dist 1 1
create_table(cars, max)
values columns row.values freq.times
1 25 speed 50 1
2 120 dist 49 1
一种选择是使用 tidyverse
。我有点不清楚你是否想在同一个数据框中使用 min
和 max
,所以我将两者都包括在内。首先,我创建了一个带有行号的索引列。然后,我转向长格式以确定哪些值是最小值和最大值(使用 case_when
)。然后,我删除不是最小值或最大值的行(即类别中的 NA
)。然后,我使用 summarise
将行名称转换为单个字符串并获取给定最小值或最大值的频率。
library(tidyverse)
cars %>%
mutate(rowname = row_number()) %>%
pivot_longer(-rowname, names_to = "column", values_to = "value") %>%
group_by(column) %>%
mutate(category = case_when((value == min(value)) == TRUE ~ "min",
(value == max(value)) == TRUE ~ "max")) %>%
drop_na(category) %>%
group_by(column, value, category) %>%
summarise(rowname = toString(rowname), freq.times = n()) %>%
select(2:3, 1, 4, 5)
输出
# A tibble: 4 × 5
# Groups: column, value [4]
value category column rowname freq.times
<dbl> <chr> <chr> <chr> <int>
1 2 min dist 1 1
2 120 max dist 49 1
3 4 min speed 1, 2 2
4 25 max speed 50 1
但是,如果您想单独生成数据帧。然后,你可以调整这样的东西。在这里,我不使用 category
而是使用 filter
来删除所有不是 group/column 的最小值的行。然后,我们可以像上面那样summarise
。您也可以对 max
做同样的事情。
cars %>%
mutate(rowname = row_number()) %>%
pivot_longer(-rowname, names_to = "column", values_to = "min.value") %>%
group_by(column) %>%
filter(min.value == min(min.value)) %>%
group_by(column, min.value) %>%
summarise(rowname = toString(rowname), freq.times = n()) %>%
select(2, 1, 3, 4)
输出
# A tibble: 2 × 4
# Groups: column [2]
min.value column rowname freq.times
<dbl> <chr> <chr> <int>
1 2 dist 1 1
2 4 speed 1, 2 2
您可以使用which
获取位置。 sapply
应该可以。由于每一列都需要多个汇总统计信息,因此只需将它们包含在一个列表中即可。像这样
as.data.frame(sapply(cars, \(x) {
extrema <- range(x)
min.row <- which(x == extrema[[1L]])
max.row <- which(x == extrema[[2L]])
list(
min.value = extrema[[1L]], max.value = extrema[[2L]],
min.row = min.row, max.row = max.row,
freq.min = length(min.row), freq.max = length(max.row)
)
}))
输出
speed dist
min.value 4 2
max.value 25 120
min.row 1, 2 1
max.row 50 49
freq.min 2 1
freq.max 1 1
这是另一种tidyverse
方法:
which.min(.)
给出第一个索引,而 which(. == min(.))
将给出满足条件的所有索引!
获得我们可以使用的频率的类比:length(which(.==min(.)))
summarise
所有列 min.value
、rowname
和 freq.time
- 后面的部分是旋转以将列名放在适当的位置。
library(tidyverse)
cars %>%
summarise(across(dplyr::everything(), list(min.value = min,
rowname = ~list(which(. == min(.))),
freq.times = ~length(which(.==min(.)))))) %>%
pivot_longer(
cols = contains("_"),
names_to = "key",
values_to = "val",
values_transform = list(val = as.character)
) %>%
separate(key, c("column", "name"), sep="_") %>%
pivot_wider(
names_from = name,
values_from = val
) %>%
mutate(rowname = str_replace(rowname, '\:', '\,'))
column min.value rowname freq.times
<chr> <chr> <chr> <chr>
1 speed 4 1,2 2
2 dist 2 1 1
我有一个包含 150 个列名的 data.frame。对于每一列,我想提取最大值和最小值(行重复)以及每个最大值的行名称。我在另一个 data.frame 中提取了最小值和最大值,但不知道如何匹配它们。
我找到了与此非常接近的函数,例如最小值:
head(cars)
speed dist
1 4 2
2 4 10
3 7 4
4 7 22
5 8 16
6 9 10
sapply(cars,which.min)
speed dist
1 1
这里只给出最低速度的第一个指标
我试过像这样的循环:
for (i in (colnames(cars))){
print(min(cars[[i]]))
}
[1] 4
[1] 2
但这只是给我最小值,而不是如果它们重复以及每个重复值的行名。
我想要这样的东西:
min.value column rowname freq.times
4 speed 1,2 2
2 dist 1 1
谢谢,如果我有拼写错误,请见谅。没有母语人士
min.value <- sapply(cars, min)
columns <- names(min.value)
row.values <- sapply(columns, \(x) which(cars[[x]] == min.value[which(names(min.value) == x)]))
freq.times <- sapply(row.values, length)
row.values <- sapply(row.values, \(x) paste(x, collapse = ","))
names(min.value) <- names(row.values) <- names(freq.times) <- NULL
data.frame(min.value = min.value,
columns = columns,
row.values = row.values,
freq.times = freq.times)
min.value columns row.values freq.times
1 4 speed 1,2 2
2 2 dist 1 1
这里它被包装在函数中,这样你就可以在任何你需要的数据框和函数中使用它:
create_table <- function(df, FUN) {
values <- sapply(df, FUN)
columns <- names(values)
row.values <- sapply(columns, \(x) which(df[[x]] == values[which(names(values) == x)]))
freq.times <- sapply(row.values, length)
row.values <- sapply(row.values, \(x) paste(x, collapse = ","))
names(values) <- names(row.values) <- names(freq.times) <- NULL
data.frame(values = values,
columns = columns,
row.values = row.values,
freq.times = freq.times)
}
create_table(cars, min)
values columns row.values freq.times
1 4 speed 1,2 2
2 2 dist 1 1
create_table(cars, max)
values columns row.values freq.times
1 25 speed 50 1
2 120 dist 49 1
一种选择是使用 tidyverse
。我有点不清楚你是否想在同一个数据框中使用 min
和 max
,所以我将两者都包括在内。首先,我创建了一个带有行号的索引列。然后,我转向长格式以确定哪些值是最小值和最大值(使用 case_when
)。然后,我删除不是最小值或最大值的行(即类别中的 NA
)。然后,我使用 summarise
将行名称转换为单个字符串并获取给定最小值或最大值的频率。
library(tidyverse)
cars %>%
mutate(rowname = row_number()) %>%
pivot_longer(-rowname, names_to = "column", values_to = "value") %>%
group_by(column) %>%
mutate(category = case_when((value == min(value)) == TRUE ~ "min",
(value == max(value)) == TRUE ~ "max")) %>%
drop_na(category) %>%
group_by(column, value, category) %>%
summarise(rowname = toString(rowname), freq.times = n()) %>%
select(2:3, 1, 4, 5)
输出
# A tibble: 4 × 5
# Groups: column, value [4]
value category column rowname freq.times
<dbl> <chr> <chr> <chr> <int>
1 2 min dist 1 1
2 120 max dist 49 1
3 4 min speed 1, 2 2
4 25 max speed 50 1
但是,如果您想单独生成数据帧。然后,你可以调整这样的东西。在这里,我不使用 category
而是使用 filter
来删除所有不是 group/column 的最小值的行。然后,我们可以像上面那样summarise
。您也可以对 max
做同样的事情。
cars %>%
mutate(rowname = row_number()) %>%
pivot_longer(-rowname, names_to = "column", values_to = "min.value") %>%
group_by(column) %>%
filter(min.value == min(min.value)) %>%
group_by(column, min.value) %>%
summarise(rowname = toString(rowname), freq.times = n()) %>%
select(2, 1, 3, 4)
输出
# A tibble: 2 × 4
# Groups: column [2]
min.value column rowname freq.times
<dbl> <chr> <chr> <int>
1 2 dist 1 1
2 4 speed 1, 2 2
您可以使用which
获取位置。 sapply
应该可以。由于每一列都需要多个汇总统计信息,因此只需将它们包含在一个列表中即可。像这样
as.data.frame(sapply(cars, \(x) {
extrema <- range(x)
min.row <- which(x == extrema[[1L]])
max.row <- which(x == extrema[[2L]])
list(
min.value = extrema[[1L]], max.value = extrema[[2L]],
min.row = min.row, max.row = max.row,
freq.min = length(min.row), freq.max = length(max.row)
)
}))
输出
speed dist
min.value 4 2
max.value 25 120
min.row 1, 2 1
max.row 50 49
freq.min 2 1
freq.max 1 1
这是另一种tidyverse
方法:
which.min(.)
给出第一个索引,而 which(. == min(.))
将给出满足条件的所有索引!
获得我们可以使用的频率的类比:length(which(.==min(.)))
summarise
所有列min.value
、rowname
和freq.time
- 后面的部分是旋转以将列名放在适当的位置。
library(tidyverse)
cars %>%
summarise(across(dplyr::everything(), list(min.value = min,
rowname = ~list(which(. == min(.))),
freq.times = ~length(which(.==min(.)))))) %>%
pivot_longer(
cols = contains("_"),
names_to = "key",
values_to = "val",
values_transform = list(val = as.character)
) %>%
separate(key, c("column", "name"), sep="_") %>%
pivot_wider(
names_from = name,
values_from = val
) %>%
mutate(rowname = str_replace(rowname, '\:', '\,'))
column min.value rowname freq.times
<chr> <chr> <chr> <chr>
1 speed 4 1,2 2
2 dist 2 1 1