2 votes

Filtrer un cadre de données en fonction des valeurs minimales et maximales

J'ai un cadre de données comme ceci :

df
      A     B     C     D     E     F
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1   24.    6.   16.    5. 1.20     6.
 2   21.    2.   19.    2. 1.09     2.
 3   12.    2.   12.   79. 0.860    2.
 4   39.    7.   39.   39. 1.90     7.
 5   51.    1.   82.   27. 2.30     1.
 6   24.    9.   24.   40. 1.60     9.
 7   48.    1.   32.    5. 1.60     1.
 8   44.    1.   44.   12. 1.70     1.
 9   14.    1.   18.    6. 0.880    1.
10   34.    2.   51.    5. 2.70     2.
# ... with 4,688 more rows

Je voudrais filtrer ce cadre de données en fonction d'une liste, de sorte que pour chaque colonne de df, le minimum et le maximum soient conformes au minimum et au maximum de la liste Neighb :

[[1]]
[1] 15.7 15.9 16.0 16.1 16.2

[[2]]
[1] 0 1 2 3 4

[[3]]
[1] 15.0 15.3 16.0 16.3 16.5

[[4]]
[1] 3 4 5 6 7

[[5]]
[1] 1.08 1.09 1.10 1.11 1.12

[[6]]
[1] 0 1 2 3 4

Existe-t-il un moyen de faire cela efficacement avec dplyr/base R ? Jusqu'à présent, j'ai utilisé des boucles et filtré chaque colonne de df à la fois.

4voto

akrun Points 148302

Nous pouvons utiliser Map de base R

Map(function(x, y) x[x >= min(y) & x <= max(y)], df, Neighb)
#$A
#numeric(0)

#$B
#[1] 2 2 1 1 1 1 2

#$C
#[1] 16

#$D
#[1] 5 5 6 5

#$E
#[1] 1.09

#$F
#[1] 2 2 1 1 1 1 2

Si nous devons filter l'ensemble de données sur la base de l'index logique, c'est-à-dire les rangées qui ont toutes les TRUE sur la base de la comparaison avec "Neighb".

df[Reduce(`&`, Map(function(x, y) x >= min(y) & x <= max(y), df, Neighb)), ]

et si c'est un VRAI

df[Reduce(`|`, Map(function(x, y) x >= min(y) & x <= max(y), df, Neighb)),]

données

df <- structure(list(A = c(24, 21, 12, 39, 51, 24, 48, 44, 14, 34), 
                     B = c(6, 2, 2, 7, 1, 9, 1, 1, 1, 2), 
                     C = c(16, 19, 12, 39, 82, 24, 32, 44, 18, 51),
                     D = c(5, 2, 79, 39, 27, 40, 5, 12, 6, 5), 
                     E = c(1.2, 1.09, 0.86, 1.9, 2.3, 1.6, 1.6, 1.7, 0.88, 2.7), 
                     F = c(6, 2, 2, 7, 1, 9, 1, 1, 1, 2)), 
                .Names = c("A","B", "C", "D", "E", "F"), 
                class = "data.frame", 
                row.names = c(NA, -10L))

Neighb <- list(c(15.7, 15.9, 16.0, 16.1, 16.2),
               c(0, 1, 2, 3, 4),
               c(15.0, 15.3, 16.0, 16.3, 16.5),
               c(3, 4, 5, 6, 7),
               c(1.08, 1.09, 1.10, 1.11, 1.12),
               c(0, 1, 2, 3, 4))

2voto

phiver Points 978

Vous pouvez utiliser map2 de purrr en même temps que between de dplyr pour obtenir les résultats que vous souhaitez.

library(purrr)
library(dplyr)

map2(df, Neighb, function(x, y) x[between(x, min(y), max(y))] )
$A
numeric(0)

$B
[1] 2 2 1 1 1 1 2

$C
[1] 16

$D
[1] 5 5 6 5

$E
[1] 1.09

$F
[1] 2 2 1 1 1 1 2

données :

df <- structure(list(A = c(24, 21, 12, 39, 51, 24, 48, 44, 14, 34), 
                     B = c(6, 2, 2, 7, 1, 9, 1, 1, 1, 2), 
                     C = c(16, 19, 12, 39, 82, 24, 32, 44, 18, 51),
                     D = c(5, 2, 79, 39, 27, 40, 5, 12, 6, 5), 
                     E = c(1.2, 1.09, 0.86, 1.9, 2.3, 1.6, 1.6, 1.7, 0.88, 2.7), 
                     F = c(6, 2, 2, 7, 1, 9, 1, 1, 1, 2)), 
                .Names = c("A","B", "C", "D", "E", "F"), 
                class = "data.frame", 
                row.names = c(NA, -10L))

Neighb <- list(c(15.7, 15.9, 16.0, 16.1, 16.2),
               c(0, 1, 2, 3, 4),
               c(15.0, 15.3, 16.0, 16.3, 16.5),
               c(3, 4, 5, 6, 7),
               c(1.08, 1.09, 1.10, 1.11, 1.12),
               c(0, 1, 2, 3, 4))

1voto

Jaap Points 3814

Une solution possible :

# needed packages
library(data.table)

# get the minimum and maximum for each list item
nr <- lapply(Neighb, range)

# create a matrix with the 'inrange' function from 'data.table'
m <- mapply(function(x, y) x %inrange% y, df, nr)

cela donne :

> m
          A     B     C     D     E     F
 [1,] FALSE FALSE  TRUE  TRUE FALSE FALSE
 [2,] FALSE  TRUE FALSE FALSE  TRUE  TRUE
 [3,] FALSE  TRUE FALSE FALSE FALSE  TRUE
 [4,] FALSE FALSE FALSE FALSE FALSE FALSE
 [5,] FALSE  TRUE FALSE FALSE FALSE  TRUE
 [6,] FALSE FALSE FALSE FALSE FALSE FALSE
 [7,] FALSE  TRUE FALSE  TRUE FALSE  TRUE
 [8,] FALSE  TRUE FALSE FALSE FALSE  TRUE
 [9,] FALSE  TRUE FALSE  TRUE FALSE  TRUE
[10,] FALSE  TRUE FALSE  TRUE FALSE  TRUE

Vous pouvez maintenant filtrer df avec le rowSums -fonction :

df[rowSums(m) == ncol(df),]

En appliquant cette méthode aux données de l'exemple présenté ( df ) aboutira à un cadre de données vide, mais sur l'ensemble de données original, il est fort probable qu'il aboutisse à un cadre de données non vide.


Données utilisées :

df <- read.table(text="     A     B     C     D     E     F
                   1   24    6   16    5 1.20     6
                   2   21    2   19    2 1.09     2
                   3   12    2   12   79 0.860    2
                   4   39    7   39   39 1.90     7
                   5   51    1   82   27 2.30     1
                   6   24    9   24   40 1.60     9
                   7   48    1   32    5 1.60     1
                   8   44    1   44   12 1.70     1
                   9   14    1   18    6 0.880    1
                   10   34   2   51    5 2.70     2", header=TRUE, stringsAsFactors=FALSE)
Neighb <- list(c(15.7,15.9,16.0,16.1,16.2),c(0:4),c(15.0,15.3,16.0,16.3,16.5),c(3:7),seq(1.08,1.12,0.01),c(0:4))

1voto

Prem Points 9252

Une autre approche pourrait être

#minimum and maximum value from given list
filter_criteria <- lapply(lookup_list, function(x) c(min(x), max(x)))

df1 <- as.data.frame(mapply(function(x, y) replace(x, !(x>=y[1] & x<=y[2]), NA), 
                            df, filter_criteria))

df1
#    A  B  C  D    E  F
#1  NA NA 16  5   NA NA
#2  NA  2 NA NA 1.09  2
#3  NA  2 NA NA   NA  2
#4  NA NA NA NA   NA NA
#5  NA  1 NA NA   NA  1
#6  NA NA NA NA   NA NA
#7  NA  1 NA  5   NA  1
#8  NA  1 NA NA   NA  1
#9  NA  1 NA  6   NA  1
#10 NA  2 NA  5   NA  2

#final output
df1 <- na.omit(df1)   #as per given sample data it's empty

Exemple de données

df <- structure(list(A = c(24, 21, 12, 39, 51, 24, 48, 44, 14, 34), 
    B = c(6, 2, 2, 7, 1, 9, 1, 1, 1, 2), C = c(16, 19, 12, 39, 
    82, 24, 32, 44, 18, 51), D = c(5, 2, 79, 39, 27, 40, 5, 12, 
    6, 5), E = c(1.2, 1.09, 0.86, 1.9, 2.3, 1.6, 1.6, 1.7, 0.88, 
    2.7), F = c(6, 2, 2, 7, 1, 9, 1, 1, 1, 2)), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9", "10"))

lookup_list <- list(c(15.7, 15.9, 16, 16.1, 16.2), c(0, 1, 2, 3, 4), c(15, 15.3, 
16, 16.3, 16.5), c(3, 4, 5, 6, 7), c(1.08, 1.09, 1.1, 1.11, 1.12
), c(0, 1, 2, 3, 4))

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