2
votes

Comment importer xlsx avec des types de date mixtes dans la même colonne?

J'essaye d'importer une feuille de calcul Excel dans R (via read.xlsx2 () ). Les données Excel ont une colonne de date. Cette colonne de date contient des types mixtes de formats de date, par exemple certaines lignes sont 42669 , et certaines sont au format date, par exemple 26/10/2016.

read.xlsx2 () le lit comme un facteur, je l'ai donc converti en as.Date en utilisant le code ci-dessous. Cela fonctionne pour toutes les dates sous forme numérique (ex: 42669 ) mais R me prévient qu'il a ajouté des NA s (pour celles au format 26/10 / 2016 ). Ma question est de savoir comment importer les données Excel avec des dates appropriées pour toutes les variables, c'est-à-dire dire à R qu'il y a des données mixtes?

library(xlsx)
#Import excel file
df <- read.xlsx2(mydata, 1, header=true)

#Output = recd_date : Factor w/ 590 levels "", "26/10/2016", "42669" ...
levels(df$recd_date)

#Output = [1] "" "26/10/2016" "42669" ...

#This works for numeric dates: 

df$recd_date <- as.Date( as.numeric (as.character(df$recd_date) ),origin="1899-12-30")

#Output = recd_date : Date, format "2016-10-26" ...

#but it doesn't work for dd/mm/yyyy dates, R just replaces these with NA


2 commentaires

Ne serait-il pas plus facile de changer toutes les dates au même format dans Excel?


J'ai essayé cela en premier, mais pour une raison quelconque, certains champs sont restés dans le mauvais format et j'ai de nombreuses colonnes de date à parcourir


3 Réponses :


1
votes

Nous pourrions appliquer une fonction pour nettoyer la date si nécessaire, en gros comme ceci:

> df2
  X.   date.chr   date.num   date.mix
1  1 2019-02-01 2019-02-01 2019-02-01
2  2 2019-02-02 2019-02-02 2019-02-02
3  3 2019-02-03 2019-02-03 2019-02-03

Exemple

date.cols <- c("date.chr", "date.num", "date.mix")  # select date columns
df2[date.cols] <- lapply(df2[date.cols], cleanDate)

Maintenant, nous appliquons la fonction en utilisant lapply().

# generate test df
df1 <- data.frame(date.chr=as.character(as.Date(1:3, origin=Sys.Date())), 
                  date.num=as.numeric(as.Date(1:3, origin=Sys.Date())),
                  date.mix=as.character(as.Date(1:3, origin=Sys.Date())),
                  stringsAsFactors=FALSE)

df1[2, 3] <- as.character(as.numeric(as.Date(df1[2, 1])))
> df1
    date.chr date.num   date.mix
1 2019-02-01    17928 2019-02-01
2 2019-02-02    17929      17929
3 2019-02-03    17930 2019-02-03

# write it to working directory
library(xlsx)
write.xlsx2(df1, "df1.xlsx")

# read it
# we use opt. `stringsAsFactors=FALSE` to prevent generation of factors
df2 <- read.xlsx2("df1.xlsx", 1, stringsAsFactors=FALSE)
> df2
  X.   date.chr date.num   date.mix
1  1 2019-02-01    17928 2019-02-01
2  2 2019-02-02    17929      17929
3  3 2019-02-03    17930 2019-02-03

Result

cleanDate <- function(x) {
  if (all(nchar(df2$date.mix) < 10)) {
    cd <- as.Date(x)
  } else {
    cd <- do.call(c, 
                  lapply(x, function(i)
                    if (nchar(i) < 10)  
                      as.Date(as.numeric(i), origin="1970-01-01")
                    else as.Date(i)))
  }
  return(cd)
}


2 commentaires

Cela fonctionne-t-il avec différentes structures de date dans la même colonne?


@Chabo Merci, les questions doivent être lues attentivement ^^ Voir la réponse mise à jour.



0
votes

Voici un moyen de le faire,

Une fois que nous avons lu les données, nous convertissons les colonnes de date (df $ recd_date) en caractère de classe, puis créons deux listes, une avec les dates jj / mm / AAAA, et l'autre avec les dates numériques. Une fois que cela est fait, nous convertissons indépendamment en classe de date, puis fusionnons les deux pour obtenir un produit final.

#Test Data, read in anyway you want
data<-c("26/10/2016","27/10/2016","42669","52673","28/10/2016")
Index<-c(1:5)
df<-data.frame(Index, date=data)

#Put entire date column into character format
df$date<-as.character(df$date)

#Create Date from Numeric Date, Create Date from Character Date
Date_N<-as.Date(as.numeric(df$date),origin="1899-12-30")
Date_C<-as.Date(as.character(df$date),format="%d/%m/%Y")

#Create DF from list
Date_N_df<-as.data.frame(Date_N)
Date_C_df<-as.data.frame(Date_C)

#Replace NA from Date_C_df with index from Date_N_df
Date_C_df[is.na(Date_C_df)] <- Date_N_df[is.na(Date_C_df)]
Final<-Date_C_df 
names(Final)<-"Date"

> Final
        Date
1 2016-10-26
2 2016-10-27
3 2016-10-26
4 2044-03-17
5 2016-10-28


1 commentaires

Je vous remercie. Cela a fonctionné aussi mais je pense que la réponse ci-dessus est plus ce que je recherchais.



0
votes

Essayez convert_to_date à partir du package de conciergerie, en spécifiant la fonction character-to-date du package lubridate qui correspond à votre format de date:

library(janitor)
x <- c("26/10/2016", "42669")
convert_to_date(x, character_fun = lubridate::dmy)
#> [1] "2016-10-26" "2016-10-26"

Self -promotion disclaimer: je maintiens ce package. J'ajoute cette réponse car cette fonction a été créée pour résoudre ce problème exact d'un mélange de numéros de date Excel et de dates formatées dans la même variable.


0 commentaires