根据 R 中另一个 DataFrame 的条件从 DataFrame 中提取值

Extract values from a DataFrame based on condition on another DataFrame in R

我有以下两个示例数据框:

df1 <- data.frame(EVI_GT=c(0.23, 0.54, 0.36, 0.92), EVI_GNT=c(0.33, 0.65, 0.42, 0.73), EVI_GGT=c(0.43, 0.34, 0.22, 0.98))
df2 <- data.frame(T_ET_GT=c(0.56, 0.23, 0.95, 0.82), T_ET_GNT=c(0.10, 0.74, 0.36, 0.35), T_ET_GGT=c(0.52, 0.31, 0.65, 0.58))

我必须从 df2 中提取对应于 df1(每行)的最小值和最大值的值。例如,df1 中第一行的最小(最大值)值为 0.23(0.43),即第 1 列(第 3 列),因此第一行应从 df2 中提取的值为 0.56 和 0.52。第 2 行类似,依此类推。下面是我想要的输出数据框:

df3 <- data.frame(column1=c(0.56, 0.31, 0.65, 0.35), column2=c(0.52, 0.74, 0.36, 0.58))

我们如何使用 df1 上的条件从 df2 获取 df3?

假设您的数据框具有相同的维度,那应该相当容易!

一种非常直观和简单的方法是循环查找 df1(或 df2)中的行数,并找到 df1 中每一行的元素最大和最小的列,因此使用该信息对 df2 进行子集化并将该值归因于 df3。

df3 <- data.frame(
  min = NA,
  max = NA
)

for (i in seq_len(nrow(df1))) {
  max_val <- which.max(df1[i, ])
  min_val <- which.min(df1[i, ])
  df3[i, 1] <- df2[i, min_val]
  df3[i, 2] <- df2[i, max_val]
}

一种更“动态”的方法是逐行(通过应用语句)从 df1 中提取“which.max”和“which.min”,从而形成一个列表指标。然后,可以为第一个和第二个条件(最小值和最大值)定义一个行列对矩阵(将其视为坐标!)。

indexes <- apply(df1, MARGIN = 1, function(x) {
  return(list(min_idx = which.min(x), max_idx = which.max(x)))
})

indexes <- dplyr::bind_rows(indexes)
indexes$row <- 1:nrow(indexes)
mins_indexes <- as.matrix(dplyr::select(indexes, c("row", "min_idx")))
maxes_indexes <- as.matrix(dplyr::select(indexes, c("row", "max_idx")))

df3 <- data.frame(
  min_vals = df2[mins_indexes],
  max_vals = df2[maxes_indexes]
)

这个解决方案大致基于这个问题 Selecting specific elements from a matrix all at once!

注意:我已使该过程尽可能直观,您当然可以使用更巧妙的名称并使用更少的代码行。

您可以使用which.minwhich.max分别获取最小值和最大值的索引。使用 apply 执行按行操作并对 df2.

中的数据进行子集化
data.frame(column1 = df2[cbind(1:nrow(df1), apply(df1, 1, which.min))],
           column2 = df2[cbind(1:nrow(df1), apply(df1, 1, which.max))])

#  column1 column2
#1    0.56    0.52
#2    0.31    0.74
#3    0.65    0.36
#4    0.35    0.58

一种使用purrr

的方法
library(dplyr)
library(purrr)

df1 %>%
  # list of row for df1
  pmap(~c(...)) %>%
  map2_dfr(.y = df2 %>% pmap(~c(...)), # map with list of row df2
    .f = function(a, b) { # function that take min/max each row of df1 and extract df2
      min_index <- which.min(a)
      max_index <- which.max(a)
      tibble(min = b[min_index], max = b[max_index])
    })

# Output
# A tibble: 4 x 2
    min   max
  <dbl> <dbl>
1  0.56 0.52 
2  0.31 0.74 
3  0.65 0.36 
4  0.35 0.580