2017-01-25 1 views
2

Lors de la conversion d'une trame de données en xts, j'ai réalisé qu'il y avait un problème avec le formateur. Voici un exemple dataframe:R supprime les heures, les minutes et les secondes à partir de la date

effective_date   price 
"1990-01-01" "100" 
"1990-01-02 00:05:00" "200" 

Ceci est un exemple de sortie d'un paquet que j'utilise.

La conversion de ce à xts est straight-forward

xts(df["price"], order_by=as.POSIXct(df["effective_date"], format="%Y-%m-%d %H:%M:%S")

Cependant cette erreur, en disant NAs ne peut pas être dans les noms de ligne, et le résultat est:

<NA>  100 
1990-01-02 00:05:00 200 

De toute évidence xts ne peut pas comprendre quoi faire avec la date étrange là (minuit) et il ne le contraindra pas.

Si j'ajoute tz="UTC"-as.POSIXct cela ne fonctionne pas. De plus, as.POSIXlt ne change rien ici non plus. Que puis-je faire pour contraindre la date de minuit au format correct?

Répondre

8

Deux questions:

1) Vous ne pouvez pas analyser une seule date comme POSIXct avec un format donné:

R> as.POSIXct(c("2017-01-02", "2017-01-03 04:05:06"), format="%Y-%m-%d %H:%M:%S") 
[1] NA      "2017-01-03 04:05:06 CST" 
R> 

2) Vous pouvez toutefois utiliser la fonction anytime() pour le faire:

R> anytime::anytime(c("2017-01-02", "2017-01-03 04:05:06")) 
[1] "2017-01-02 00:00:00 CST" "2017-01-03 04:05:06 CST" 
R> 

Une fois que vous avez un POSIXct, formant le xts est facile.

Notez également que vous avez des fautes de frappe: vous avez besoin d'une virgule avant l'indicateur de colonne: df[, "price"].

Edit: Obtenir un peu fatigué de @ commentaire de 42 sur la solution de Gabor (fine) "dominant" celui-ci, voici donc référence minimale:

R> library(microbenchmark) 
R> v <- c("2017-01-02", "2017-01-03 04:05:06") 
R> library(anytime) 
R> print(microbenchmark(anytime(v), do.call("c", lapply(v, as.POSIXct))), digits=3) 
Unit: microseconds 
           expr min lq mean median uq max neval cld 
          anytime(v) 33.6 36.8 42.1 45.6 46.6 80.7 100 a 
do.call("c", lapply(v, as.POSIXct)) 571.5 579.1 586.4 586.8 589.5 695.7 100 b 
R> 

si bref "pas vraiment". Il utilise uniquement la base R, qui est un plus, mettre un) plus difficile lire et comprendre, b) plus limitée car elle traite de exactement un format (dans le style ISO) et c) il est d'environ treize fois plus lent.

+0

Upvote obligatoire pour la correction de faute de frappe. 'anytime' est assez propre. Le meilleur que j'ai pu trouver dans la base R était 'do.call (pmax, c (Map (as.POSIXct, dat [" effective_date "], format = liste ("% Y-% m-% d% H:% M:% S ","% Y-% m-% d ")), na.rm = TRUE))' – thelatemail

+2

Je pense que la solution de base de G.Grothendeick dominerait celle-ci. –

+0

Non, pas vraiment. Voir ma modification. –

1

En supposant que vous voulez que les horodateurs, prétraiter avec quelque chose comme:

temp <- c("1990-01-01", "1990-01-02 00:05:00") 

# match a date string at the end of string (indicated by $). Replace 
# with the full string (indicated by \\1 and 00:00:00 
temp2 <- gsub("(\\d{4}\\-\\d{2}\\-\\d{2}$)", "\\1 00:00:00", temp) 

# [1] "1990-01-01 00:00:00" "1990-01-02 00:05:00" 
+3

C'est assez difficile. Je recommande généralement de ne pas utiliser l'expression rationnelle lorsque vous essayez d'analyser des dates ou de les transformer. Voir ma réponse pour une meilleure façon possible. –

3

La plupart des fonctions d'analyse de lubridate ont un paramètre truncated qui prend un nombre indiquant le nombre d'éléments qui peuvent être manquants à la fin. Les éléments manquants seront remplacés par zéro.

Exemple avec les données à la main:

lubridate::ymd_hms(c("2017-01-02", "2017-01-03 04:05:06"), truncated = 3) 
## [1] "2017-01-02 00:00:00 UTC" "2017-01-03 04:05:06 UTC" 
+0

Eh bien, mais c'est toujours inférieur à 'anytime :: anytime()' _ comme vous devez fournir l'argument 'truncated'. –

+0

Cela demande un peu plus d'efforts, oui, mais cela vous donne également plus de contrôle si vous voulez que ces dates échouent avec un avertissement. – alistaire

+0

Eh bien, zéro est toujours inférieur à un. Ma solution est simplement plus générique car elle échouera dans moins de scénarios d'entrée bizarres, et nécessitera moins de maintiens et de contrôles d'opérateurs que celui-ci. Tant pis. –

7

1) Pour obtenir le essayer vecteur datetime "POSIXct" convertir chaque datetime à "POSIXct" séparément, puis les concaténer ensemble:

do.call("c", lapply(df$effective_date, as.POSIXct)) 

Une autre solution de base qui est encore plus courte et est également sensiblement plus rapide est la suivante qui repose sur le fait que as.POSIXct va ignorer indésirable à la fin.

as.POSIXct(paste(df$effective, "00:00:00")) 
+0

Chapeau pour utiliser Base R, mais c'est un tas plus lent (voir ma réponse) et limité au format ISO en entrée. –