36 votes

Comment charger rapidement des données dans R?

J'ai quelques R scripts, où j'ai charger plusieurs dataframe dans la R le plus rapidement possible. C'est tout à fait important que la lecture des données est la partie la plus lente de la procédure. E. g.: traçage à partir de différents dataframes. Je reçois les données en sav (SPSS), mais je pourrais le transformer en n'importe quel format comme le suggère. La fusion de la dataframes n'est pas une option, malheureusement.

Ce qui pourrait être le moyen le plus rapide pour charger les données? Je pensais à la suivante:

  • la transformation de sav binaire R de l'objet (Rdata) dans le premier temps, et plus tard, toujours à la charge, comme il semble beaucoup plus rapide que l' read.spss.
  • la transformation de sav pour csv fichiers et la lecture des données à partir de ceux ayant donné paramètres présentés dans cette rubrique,
  • ou est-il utile de définir un backend MySQL sur localhost et de charger des données à partir de cela? Pourrait-il être plus rapide? Si oui, puis-je également enregistrer des personnalisés attr des valeurs des variables (par exemple, la variable.des étiquettes à partir de Spss fichiers importés)? Ou cela doit être fait dans un tableau distinct?

D'autres commentaires sont les bienvenus. Merci pour toutes les suggestions à l'avance!


J'ai fait une petite expérience ci-dessous sur la base des réponses que vous avez donné, et a également ajouté (24/01/2011) un très "hackish" mais vraiment de solution rapide de chargement de seulement quelques variables/les colonnes d'un fichier binaire. Ce dernier semble être la méthode la plus rapide que je peux imaginer maintenant, c'est pourquoi j'ai fait (05/03/2011: ver. 0.3) un petit paquet nommé enregistre à traiter avec cette fonctionnalité. L'emballage est "lourd" de développement, toute recommandation est la bienvenue!

Je vais bientôt publier une vignette avec précision les résultats d'un benchmark avec l'aide de microbenchmark paquet.

39voto

daroczig Points 11126

Merci à vous tous pour les conseils et les réponses, j'ai fait de la synthèse et de l'expérience sur cette base.

Voir un petit test avec une base de données publique (ESS 2008 en Hongrie) ci-dessous. La base de données ont 1508 cas et 508 variables, de sorte qu'il pourrait être une de données de taille moyenne. Cela pourrait être un bon exemple pour faire le test sur (pour moi), mais bien sûr des besoins spéciaux nécessiterait une expérience avec des données adéquates.

La lecture des données à partir de SPSS sav fichier sans aucune modification:

> system.time(data <- read.spss('ESS_HUN_4.sav'))
   user  system elapsed 
  2.214   0.030   2.376 

Chargement avec un converti objet binaire:

> save('data',file='ESS_HUN_4.Rdata')
> system.time(data.Rdata <- load('ESS_HUN_4.Rdata'))
   user  system elapsed 
   0.28    0.00    0.28 

Essayer avec csv:

> write.table(data, file="ESS_HUN_4.csv")
> system.time(data.csv <- read.csv('ESS_HUN_4.csv'))
   user  system elapsed 
  1.730   0.010   1.824 

Essaie avec "affiner" csv chargement:

> system.time(data.csv <- read.table('ESS_HUN_4.csv', comment.char="", stringsAsFactors=FALSE, sep=","))
   user  system elapsed 
  1.296   0.014   1.362 

Aussi avec le paquet sqldf, qui semble pour charger les fichiers csv beaucoup plus rapide:

> library(sqldf)
> f <- file("ESS_HUN_4.csv")
>  system.time(bigdf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F, sep="\t")))
   user  system elapsed 
  0.939   0.106   1.071 

Et également le chargement de données à partir d'une base de données MySQL en cours d'exécution sur localhost:

> library(RMySQL) 
> con <- dbConnect(MySQL(), user='root', dbname='test', host='localhost', password='')
> dbWriteTable(con, "data", as.data.frame(data), overwrite = TRUE)
> system.time(data <- dbReadTable(con, 'data'))
   user  system elapsed 
  0.583   0.026   1.055 
> query <-('SELECT * FROM data')
> system.time(data.sql <- dbGetQuery(con, query))
   user  system elapsed 
  0.270   0.020   0.473 

Ici, je pense que nous devrions ajouter les deux system.time signalés, de même que la connexion aux données compte aussi dans notre cas. S'il vous plaît commentaire, si j'ai mal compris quelque chose.

Mais nous allons voir si l'interrogation uniquement certaines variables, comme par exemple. alors qu'elle préparait nous n'avons pas besoin de tous les dataframe dans la plupart des cas, l'interrogation et le seulement deux variables est suffisant pour créer un beau terrain d'entre eux:

> query <-('SELECT c1, c19 FROM data')
> system.time(data.sql <- dbGetQuery(con, query))
   user  system elapsed 
  0.030   0.000   0.112 

Ce qui semble vraiment super! Bien sûr, juste après le chargement de la table avec dbReadTable

Résumé: rien à battre lecture de l'ensemble de données à partir d'un fichier binaire, mais la lecture de seulement quelques colonnes (ou d'autres données filtrées) à partir de la même table de base de données pourrait également être pondéré dans certains cas particuliers.

Environnement de Test: HP 6715b ordinateur portable (AMD X2 2 ghz, 4 Go de mémoire DDR2) avec un bas de gamme de SSD.


Mise à JOUR (24/01/2011): j'ai ajouté un plus à du bidouillage, mais très "créatif" moyen de chargement de seulement quelques colonnes d'un objet binaire - qui semble beaucoup plus rapide que n'importe quelle méthode examiné ci-dessus.

Attention: le code est vraiment mauvais, mais toujours très efficace :)

Tout d'abord, j'ai enregistrer toutes les colonnes de données.cadre en différents objets binaires via la boucle suivante:

attach(data)
for (i in 1:length(data)) {
    save(list=names(data)[i],file=paste('ESS_HUN_4-', names(data)[i], '.Rdata', sep=''))
}
detach(data)

Puis-je charger des deux colonnes de données:

> system.time(load('ESS_HUN_4-c19.Rdata')) + 
>     system.time(load('ESS_HUN_4-c1.Rdata')) + 
>     system.time(data.c1_c19 <- cbind(c1, c19))
    user  system elapsed 
    0.003   0.000   0.002 

Qui ressemble à un "superfast" la méthode! :- ) Note: il a été chargé à 100 fois plus rapide que le plus rapide (chargement de l'ensemble de l'objet binaire) la méthode ci-dessus.

J'ai fait un très petit paquet (nommé: sauve), regardez dans github pour plus de détails si vous êtes intéressé.


Mise à JOUR (06/03/2011): une nouvelle version de mon petit paquet (sauve) a été transféré à CRAN, dans lequel il est possible d'enregistrer et de charger des variables encore plus rapide - si et seulement si l'utilisateur n'a besoin que d'un sous-ensemble des variables disponibles dans une trame de données ou liste. Voir la vignette dans le package des sources pour plus de détails sur ma page d'accueil, et laissez-moi vous présenter aussi une belle boîte à moustaches de certains de référence fait:

Comparison of different data frame/list loading mechanism by speed

Cette boîte à moustaches montre les avantages de l'utilisation sauve colis à charger uniquement un sous-ensemble de variables à l'encontre load et read.table ou read.csv à partir de la base, read.spss d'étrangers ou d' sqldf ou RMySQL des paquets.

19voto

Joris Meys Points 38980

Cela dépend de ce que vous voulez faire et comment vous devez traiter les données plus loin. Dans tous les cas, le chargement à partir d'un binaire R de l'objet est toujours va être plus rapide, à condition, vous devez toujours le même jeu de données. La limitation de vitesse est la vitesse de votre disque dur, pas de R. de La forme binaire est la représentation interne du dataframe dans l'espace de travail, donc il n'y a aucune transformation n'a plus besoin de vous.

Tout type de fichier texte est une autre histoire, comme vous comprennent invariablement une surcharge : chaque fois que vous lisez dans le texte, le fichier de données doit être transformé pour le binaire R de l'objet. J'avais oublier. Ils ne sont utiles que pour le portage de jeux de données provenant d'une application à une autre.

La configuration d'un backend MySQL est très utile si vous avez besoin de différentes parties de ces données, ou de sous-ensembles différents dans différentes combinaisons. Surtout lorsque l'on travaille avec d'énormes ensembles de données, le fait que vous n'avez pas à charger dans le jeu de données entier avant que vous pouvez commencer à sélectionner les lignes/colonnes, vous pouvez gagner un peu de temps. Mais cela ne fonctionne qu'avec d'énormes ensembles de données, comme la lecture d'un fichier binaire est un peu plus rapide que la recherche dans une base de données.

Si les données ne sont pas trop gros, vous pouvez enregistrer différents dataframes dans un fichier RData, vous donnant la possibilité de rationaliser les choses un peu plus. J'ai souvent un ensemble de dataframes dans une liste ou dans un autre environnement (voir aussi ?environment pour des exemples simples). Cela permet de lapply / eapply solutions pour traiter plusieurs dataframes à la fois.

1voto

Matt Bannert Points 6390

Je suis assez heureux avec RMySQL. Je ne suis pas sûr de savoir si j'ai reçu votre question le droit chemin, mais les étiquettes ne devraient pas être un problème. Il existe plusieurs fonctions de confort, utilisez la valeur par défaut de SQL de la table et les noms de lignes, mais bien sûr vous pouvez utiliser des instructions SQL.

Je dirais (en dehors de grands ensembles de données qui justifient l'agitation) l'une des principales raisons de l'utilisation d'RMySQL est familier plus familier avec la syntaxe SQL de R des données de jonglerie fonctions. Personnellement, je préfère GROUPE PAR plus globale. Notez que l'utilisation de procédures stockées à partir de l'intérieur de R ne fonctionne pas particulièrement bien.

Bas de ligne... la mise en place d'un MySQL localhost n'est pas trop d'effort, – lui donner un essai! Je ne peux pas dire exactement à propos de la vitesse, mais j'ai l'impression qu'il y a une chance c'est plus rapide. Cependant, je vais essayer de revenir ici.

EDIT: voici le test... et le gagnant est: spacedman

# SQL connection
source("lib/connect.R")

dbQuery <- "SELECT * FROM mytable"
mydata <- dbGetQuery(con,dbQuery)
system.time(dbGetQuery(con,dbQuery))
# returns
#user  system elapsed 
# 0.999   0.213   1.715 

save.image(file="speedtest.Rdata")
system.time(load("speedtest.Rdata"))
#user  system elapsed 
#0.348   0.006   0.358 

La Taille du fichier n'était que d'environ 1 MO ici. MacBook Pro 4 GO de Ram 2.4 GHZ Intel Core Duo, Mac OSX 10.6.4, MySQL 5.0.41 Jamais essayé, parce que je travaille avec les plus grandes dataset généralement et le chargement n'est pas le problème, mais plutôt le traitement... si il y a des problèmes de temps à tous. +1 pour le Q!

1voto

Roman Luštrik Points 19295

Si c'est possible, faites transformer les données en csv ou tout autre format "simple" pour rendre la lecture aussi rapide que possible (voir la réponse de Joris). J'importe des fichiers csv en masse avec la fonction apply , quelque chose comme:

 list.of.files <- as.list(list.files("your dir"))
lapply(list.of.files, FUN = function(x) {
    my.object <- read.table(...) # or some other function, like read.spss
})
 

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