J'essaie de mettre en œuvre un moyen de filtrer ce dataframe df
structure(list(Name = c("Jim", "Jane", "Jose", "Matt", "Mickey",
"Tom", "Peter", "Jane", "Jim", "Jose"), Progress = c("65", "20",
"80", "20", "65", "45", "20", "70", "25", "80"), EndDate = c("11/25/2018 16:45",
"11/25/2018 18:05", "11/25/2018 14:20", "12/1/2018 22:52", "11/29/2018 18:15",
"12/2/2018 15:27", "11/26/2018 12:07", "11/30/2018 11:18", "11/29/2018 18:04",
"11/29/2018 21:12")), row.names = c(NA, -10L), class = "data.frame")
Je veux le filtrer de telle sorte que s'il y a des réponses en double dans le Colonne de nom comme la façon dont Jim apparaît deux fois Je voudrais conserver la ligne qui a la date et l'heure les plus anciennes selon la colonne EndDate UNIQUEMENT si la valeur de la colonne Progression est supérieur à 70. Sinon, je veux prendre la ligne qui a une date et une heure ultérieures dans la colonne EndDate .
3 Réponses :
En fonction de la condition, nous convertissons la classe 'EndDate' en DateTime , puis arrangez par 'Name', 'EndDate', regroupés par 'Name' si le premier élément de 'Progres' est supérieur à 70 renvoyer l'index 1 ou else le dernier index de ligne de la tranche à sous-ensemble les lignes
library(tidyverse) library(lubridate) df %>% mutate(EndDate = mdy_hm(EndDate)) %>% # if there are multiple formats # mutate(EndDate = anytime::anytime(EndDate)) %>% arrange(Name, EndDate) %>% group_by(Name) %>% slice(if(first(Progress) > 70) 1 else n()) # A tibble: 7 x 3 # Groups: Name [7] # Name Progress EndDate # <chr> <chr> <dttm> #1 Jane 70 2018-11-30 11:18:00 #2 Jim 25 2018-11-29 18:04:00 #3 Jose 80 2018-11-25 14:20:00 #4 Matt 20 2018-12-01 22:52:00 #5 Mickey 65 2018-11-29 18:15:00 #6 Peter 20 2018-11-26 12:07:00 #7 Tom 45 2018-12-02 15:27:00
REMARQUE: s'il existe plusieurs formats 'DateHeure', une option est anytime :: anytime au lieu de mdy_hm
En utilisant dplyr , nous convertissons d'abord EndDate en objet date / heure en utilisant parse_date_time de lubridate puis nous group_by Nom et sélectionnez la ligne avec EndDate minimum si Progression> 70 et le nombre de lignes pour chaque Nom code> est supérieur à 1 et maximum EndDate dans le cas contraire. S'il n'y a qu'une seule ligne pour le Nom , nous ne sélectionnons que celle-là par défaut. library(dplyr)
library(lubridate)
df %>%
mutate(EndDate = parse_date_time(EndDate,c("%m-%d-%y %H:%M","%Y-%m-%d %H:%M:%S"))) %>%
group_by(Name) %>%
slice(ifelse(n() > 1,
ifelse(any(Progress > 70), which.min(EndDate), which.max(EndDate)), 1))
# Name Progress EndDate
# <chr> <chr> <dttm>
#1 Jane 70 2018-11-30 11:18:00
#2 Jim 25 2018-11-29 18:04:00
#3 Jose 80 2018-11-25 14:20:00
#4 Matt 20 2018-12-01 22:52:00
#5 Mickey 65 2018-11-29 18:15:00
#6 Peter 20 2018-11-26 12:07:00
#7 Tom 45 2018-12-02 15:27:00
J'ai reçu une note lorsque j'ai exécuté ceci sur mon très grand ensemble de données que «711 n'a pas réussi à analyser». À quoi cela fait-il référence?
@ M76 cela signifie très probablement qu'il existe certaines valeurs de EndDate qu'il n'a pas pu convertir en datetime en utilisant mdy_hm de lubridate . Peut-être sont-ils dans un format différent de celui montré?
Ouais c'est tout. Pour une raison quelconque, certains sont dans ce format 25/11/18 16:10 et je ne sais pas pourquoi, mais si je les convertis dans l'autre format, la fonction fonctionnerait-elle? De plus, d'après le code actuel, pensez-vous qu'il fonctionne avec ce format 25/11/18 16:10 ou ce format 2018-12-02 15:27:00 code >
@ M76 Actuellement, le code fonctionne pour 25/11/18 16:10 et 25/11/2018 16:10 . mdy_hm devrait fonctionner pour 18 ainsi que pour 2018 . Avez-vous des types de date en dehors de ces deux formats?
Non, la seule façon de présenter les dates est dans l'un de ces 2 formats: 2018-12-02 15:27:00 et 25/11/18 16:10
puis utilisez parse_date_time et spécifiez ces deux formats. J'ai mis à jour la réponse.
Marche parfaitement! Pouvez-vous également ajouter un) final à ("% m-% d-% y% H:% M", "% Y-% m-% d% H:% M:% S")) code>? Il en manque un
oups ... ajouté. Merci :)
Une (bien sûr) cela peut également être fait en utilisant data.table
exemple de données
microbenchmark::microbenchmark(
data.table = {
dt[, EndDate := as.POSIXct( EndDate, format = "%m/%d/%Y %H:%M") ]
setorder( dt, EndDate )
dt[ , list( Progress = ifelse( Progress[1] > 70, Progress[1], Progress[.N] ) ), by = .(Name)][]
},
tidyverse1 = {
df %>%
mutate(EndDate = mdy_hm(EndDate)) %>%
arrange(Name, EndDate) %>%
group_by(Name) %>%
slice(if(first(Progress) > 70) 1 else n())
},
tidyverse2 = {
df %>%
mutate(EndDate = mdy_hm(EndDate)) %>%
group_by(Name) %>%
slice(ifelse(n() > 1,
ifelse(any(Progress > 70), which.min(EndDate), which.max(EndDate)), 1))
}
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# data.table 1.654241 2.030820 2.709023 2.556978 2.782023 30.36590 100
# tidyverse1 6.847731 7.218286 8.742247 7.516838 8.034861 72.00902 100
# tidyverse2 6.173201 6.506398 7.286639 6.764582 7.088591 52.10180 100
code
#create the data.table (can also be done using setDT(df) ) dt <- as.data.table( df ) #set the dates to a proper POSIXct-format dt[, EndDate := as.POSIXct( EndDate, format = "%m/%d/%Y %H:%M") ] #order omn EndDate (by reference!) setorder( dt, EndDate ) #summarise by Name, if first Progress >70 then keep it, else keep last Progress dt[ , list( Progress = ifelse( Progress[1] > 70, Progress[1], Progress[.N] ) ), by = .(Name)][]
benchmarks
df <- structure(list(Name = c("Jim", "Jane", "Jose", "Matt", "Mickey",
"Tom", "Peter", "Jane", "Jim", "Jose"), Progress = c("65", "20",
"80", "20", "65", "45", "20", "70", "25", "80"), EndDate = c("11/25/2018 16:45",
"11/25/2018 18:05", "11/25/2018 14:20", "12/1/2018 22:52", "11/29/2018 18:15",
"12/2/2018 15:27", "11/26/2018 12:07", "11/30/2018 11:18", "11/29/2018 18:04",
"11/29/2018 21:12")), row.names = c(NA, -10L), class = "data.frame")
C'est bon, ce que je voulais dire, c'est que l'édition de votre question le rend clair pour tout le monde. Très rarement, les gens vérifient les commentaires sur les réponses des autres
Oh je vois ce que tu veux dire. Oui, je pensais que je ne pouvais pas inclure cela parce que la trame de données précédente n'avait pas ces formats de date et ne souhaitait pas invalider les réponses de certaines personnes. Est-il généralement préférable de modifier le cadre de données complet des questions et des exemples même si cela invalide les réponses précédentes?
Bien qu'il soit bon d'avoir une question bien construite avec tous les modèles inclus à l'avance, je comprends que le big data peut avoir des problèmes comme celui que vous avez mentionné. Dans ce cas, je modifierais la question si ce n'est pas trop un changement ou créerais une nouvelle question (si la question devient entièrement différente). Le problème avec la notification de la réponse d'une seule personne est que les autres ne connaîtront pas le problème et ne pourront peut-être pas changer la réponse. Dans ce cas, vous avez alerté l'utilisateur, il a changé et confirmé tandis que d'autres ne savent même pas si leur solution fonctionne