3 votes

Extraire des valeurs d'un DataFrame en fonction d'une condition sur un autre DataFrame en R

Je possède les deux dataframes suivants :

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))

Je dois extraire les valeurs de df2 correspondant au minimum et au maximum de df1 (chaque ligne). Par exemple, la valeur minimale (maximale) de la première ligne de df1 est de 0.23 (0.43) c'est-à-dire, colonne 1 (colonne 3) donc les valeurs à extraire de df2 seront de 0.56 et 0.52 pour la première ligne. Similaire pour la ligne 2 et ainsi de suite. Ci-dessous se trouve mon dataframe de sortie souhaité :

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

Comment pouvons-nous obtenir df3 à partir de df2 en utilisant les conditions sur df1 ?

4voto

Ronak Shah Points 24715

Vous pouvez utiliser which.min et which.max pour obtenir respectivement l'indice de la valeur minimale et maximale. Utilisez apply pour effectuer une opération par ligne et sous-ensemble des données de 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

2voto

eduardokapp Points 1000

En supposant que vos dataframes aient les mêmes dimensions, cela devrait être assez facile!

Une manière très intuitive et simple consisterait à boucler pour le nombre de lignes dans df1 (ou df2) et à trouver la colonne dont les éléments sont max et min pour chaque ligne de df1, utilisant ensuite cette information pour filtrer df2 et attribuer cette valeur à 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]
}

Une façon plus "dynamique" de faire cela serait d'extraire les "which.max" et "which.min" de df1 ligne par ligne (à travers une instruction apply), formant ainsi une liste d'indexes. Ensuite, on pourrait définir une matrice de paires ligne,col (imaginez cela comme des coordonnées!) pour les premières et deuxièmes conditions (valeurs min et max).

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]
)

Cette solution est vaguement basée sur ce problème Sélectionner des éléments spécifiques d'une matrice tous en une fois!

NOTE: J'ai rendu le processus aussi intuitif que possible, vous pourriez certainement utiliser des noms plus astucieux et peut-être utiliser moins de lignes de code.

2voto

Sinh Nguyen Points 162

Une approche utilisant purrr

library(dplyr)
library(purrr)

df1 %$%
  # liste des lignes pour df1
  pmap(~c(...)) %$%
  map2_dfr(.y = df2 %$% pmap(~c(...)), # map avec la liste des lignes de df2
    .f = function(a, b) { # fonction qui prend min/max de chaque ligne de df1 et extrait df2
      min_index <- which.min(a)
      max_index <- which.max(a)
      tibble(min = b[min_index], max = b[max_index])
    })

# Sortie
# Un tibble: 4 x 2
    min   max
   
1   0,56  0,52 
2   0,31  0,74 
3   0,65  0,36 
4   0,35  0,580

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X