web-dev-qa-db-fra.com

Comment filtrer une plage de nombres dans R?

Disons que j'ai le cadre de données Mydata comme indiqué ci-dessous:

Mydata <- data.frame(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                     y = c(20, 30, 45, 54, 65, 78, 97, 102, 123, 156))

Je souhaite filtrer ce bloc de données et créer un autre bloc de données, de sorte que seules les valeurs de x entre 3 et 7 et leurs valeurs y correspondantes soient affichées. J'ai tenté ce qui suit:

new_frame <- Mydata %>% filter(x == (3:7))

Cela n'a pas fonctionné. Comment puis-je filtrer pour une plage spécifiée?

Merci d'avance pour toute aide

5
Paul Ibrahim

Utilisez %in%

library(dplyr)
new_frame<- Mydata%>% filter(x %in% (3:7))
new_frame
#   x  y
# 1 3 45
# 2 4 54
# 3 5 65
# 4 6 78
# 5 7 97
5
MHammer

Beaucoup de bonnes solutions Dplyr telles que le filtrage ou le codage en dur des limites supérieure et inférieure déjà présentes dans certaines des réponses:

MydataTable%>% filter(between(x, 3, 70))
Mydata %>% filter(x %in% 3:7)
Mydata %>% filter(x>=3&x<=7)

Vous pouvez également utiliser data.table, qui est très rapide pour les grands ensembles de données. inrange et between fonctionnent de manière identique à cette fin

library(data.table)
MydataTable <- data.table(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                          y = c(20, 30, 45, 54, 65, 78, 97, 102, 123, 156))
MydataTable[x %inrange% c(3,7)]
MydataTable[x %between% c(3,7)]

Un avantage de cette méthode (outre la vitesse de data.table) est que vous devez uniquement spécifier la plage min et max. Vous ne créez pas de tableau pour sous-définir le filtre.

Une comparaison temporelle de ces méthodes:

> df <- data.frame(x = sample(1:10, 10000000, replace = T),
+                      y = sample(1:10, 10000000, replace = T))
> system.time({ df %>% filter(between(x, 3, 7)) })
   user  system elapsed 
   0.18    0.05    0.14 
> system.time({ df %>% filter(x %in% 3:7) })
       user  system elapsed 
       0.19    0.06    0.29 
> system.time({ df %>% filter(x>=3&x<=7)  })
   user  system elapsed 
   0.17    0.09    0.26 

> dt <- data.table(df)
> system.time( {dt[x %inrange% c(3,7)] })
   user  system elapsed 
   0.13    0.07    0.21 
> system.time( {dt[x %between% c(3,7)] })
   user  system elapsed 
   0.18    0.05    0.13
3
Anna

Piggybacking sur la réponse de @Anna, je viens de lancer quelques-unes des options pour voir laquelle était la plus rapide sur un jeu de données plus volumineux pour résoudre un problème au travail. J'ai utilisé la configuration à partir d'ici ( Méthode plus rapide pour sous-définir les lignes d'un bloc de données dans R? ). Je l'ai vérifiée sur un jeu de données d'un milliard de lignes (16 Go). On dirait que data.table a légèrement dépassé dplyr. Je commence tout juste à utiliser data.table, alors je n’ai peut-être pas utilisé le code le plus efficace. Oh, aussi, je l'ai réduit à ces 4 en fonction des temps d'un jeu de données de 100 millions de lignes. Voir ci-dessous: 

set.seed(42)  
# 1 billion rows
df <- data.frame(age=sample(1:65,1e9,replace=TRUE),x=rnorm(1e9),y=rpois(1e9,25))



microbenchmark(df1 <- df %>% filter(age >= 5 & age <= 25),
               df2 <- df %>% filter(dplyr::between(df$age, 5, 25)),
               times=10)


Unit: seconds
                                      expr      min     lq   mean median     uq    max  neval
df %>% filter(age >= 5 & age <= 25)          15.327 15.796 16.526 16.601 17.086 17.996    10
df %>% filter(dplyr::between(df$age, 5, 25)) 14.214 14.752 15.413 15.487 16.121 16.447    10


DT <- as.data.table(df)
microbenchmark(dt1 <- DT[age %inrange% c(5, 25)],
               dt2 <- DT[age %between% c(5, 25)],
               times = 10)


Unit: seconds
                              expr    min     lq   mean median     uq    max neval
 dt1 <- DT[age %inrange% c(5, 25)] 15.122 16.042 17.180 16.969 17.310 22.138    10
 dt2 <- DT[age %between% c(5, 25)] 10.212 11.121 11.675 11.436 12.132 13.913    10
1
Andrew

La réponse ci-dessus est probablement plus conviviale, mais voici quelques autres ...

Modifier pour voter à la baisse sur l'index:

Mydata[Mydata$x >= 3 & Mydata$x <= 7, ]

  x  y
3 3 45
4 4 54
5 5 65
6 6 78
7 7 97

Ce qui peut être étendu pour retourner d’autres colonnes, par exemple, si vous vouliez juste y:

Mydata[Mydata$x >= 3 & Mydata$x <= 7, 'y']

[1] 45 54 65 78 97

Il peut également renvoyer plusieurs colonnes, par exemple:

Mydata <- data.frame(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                     y = c(20, 30, 45, 54, 65, 78, 97, 102, 123, 156),
                     z = c(5, 4, 3, 2, 1, 0, -1, -2, -3, -4))   

Mydata[Mydata$x >= 3 & Mydata$x <= 7, c('y','z')]

   y  z
3 45  3
4 54  2
5 65  1
6 78  0
7 97 -1
0
antimuon

Solution de base R: 

df <- Mydata[Mydata$x >= 3 & Mydata$x <= 7, ]

df
  x  y
3 3 45
4 4 54
5 5 65
6 6 78
7 7 97
0
samadhi

Et le bon vieux base::subset:

subset(Mydata, x >= 3 & x <= 7)
subset(Mydata, x %in% 3:7)
0
Moody_Mudskipper