J'ai un script qui génère des numpy
array
s bidimensionnels avec dtype=float
et forme de l'ordre de (1e3, 1e6)
. En ce moment j'utilise np.save
et np.load
pour effectuer IO opérations avec les tableaux. Cependant, ces fonctions prennent plusieurs secondes pour chaque tableau. Existe-t-il des méthodes plus rapides pour enregistrer et charger les tableaux entiers (c'est-à-dire sans faire d'hypothèses sur leur contenu) et les réduire)? Je suis prêt à convertir les array
en un autre type avant de les sauvegarder tant que les données sont conservées exactement.
Pour les très grandes baies, j'ai entendu parler de plusieurs solutions, et elles ont surtout été paresseuses sur les E/S:
ndarray
(Toute classe acceptant ndarray accepte memmap
)Utilisez Python pour HDF5, un format de fichier prêt pour les bigdata, comme PyTables ou h5py
décapage de Python système (hors course, mentionné pour la Pythonicité plutôt que pour la vitesse)
À partir des documents de NumPy.memmap :
Créez une carte mémoire vers un tableau stocké dans un fichier binaire sur le disque.
Les fichiers mappés en mémoire sont utilisés pour accéder à de petits segments de fichiers volumineux sur le disque, sans lire l'intégralité du fichier en mémoire
L'objet memmap peut être utilisé partout où un ndarray est accepté. Étant donné n'importe quel memmap
fp
,isinstance(fp, numpy.ndarray)
renvoie True.
Depuis le doc h5py
Vous permet de stocker d'énormes quantités de données numériques et de manipuler facilement ces données à partir de NumPy. Par exemple, vous pouvez découper en ensembles de données de plusieurs téraoctets stockés sur le disque, comme s'il s'agissait de véritables tableaux NumPy. Des milliers d'ensembles de données peuvent être stockés dans un seul fichier, classés et étiquetés comme vous le souhaitez.
Le format prend en charge la compression des données de différentes manières (plus de bits chargés pour la même lecture d'E/S), mais cela signifie que les données deviennent moins faciles à interroger individuellement, mais dans votre cas (purement chargement/vidage de tableaux), cela pourrait être efficace
Voici une comparaison avec PyTables.
Je ne peux pas me lever (int(1e3), int(1e6)
en raison de restrictions de mémoire. Par conséquent, j'ai utilisé un tableau plus petit:
data = np.random.random((int(1e3), int(1e5)))
NumPy save
:
%timeit np.save('array.npy', data)
1 loops, best of 3: 4.26 s per loop
NumPy load
:
%timeit data2 = np.load('array.npy')
1 loops, best of 3: 3.43 s per loop
Écriture de PyTables:
%%timeit
with tables.open_file('array.tbl', 'w') as h5_file:
h5_file.create_array('/', 'data', data)
1 loops, best of 3: 4.16 s per loop
Lecture de PyTables:
%%timeit
with tables.open_file('array.tbl', 'r') as h5_file:
data2 = h5_file.root.data.read()
1 loops, best of 3: 3.51 s per loop
Les chiffres sont très similaires. Donc pas de vrai gain avec PyTables ici. Mais nous sommes assez proches du taux d'écriture et de lecture maximum de mon SSD.
L'écriture:
Maximum write speed: 241.6 MB/s
PyTables write speed: 183.4 MB/s
En train de lire:
Maximum read speed: 250.2
PyTables read speed: 217.4
La compression n'aide pas vraiment en raison du caractère aléatoire des données:
%%timeit
FILTERS = tables.Filters(complib='blosc', complevel=5)
with tables.open_file('array.tbl', mode='w', filters=FILTERS) as h5_file:
h5_file.create_carray('/', 'data', obj=data)
1 loops, best of 3: 4.08 s per loop
La lecture des données compressées devient un peu plus lente:
%%timeit
with tables.open_file('array.tbl', 'r') as h5_file:
data2 = h5_file.root.data.read()
1 loops, best of 3: 4.01 s per loop
Ceci est différent pour les données régulières:
reg_data = np.ones((int(1e3), int(1e5)))
L'écriture est nettement plus rapide:
%%timeit
FILTERS = tables.Filters(complib='blosc', complevel=5)
with tables.open_file('array.tbl', mode='w', filters=FILTERS) as h5_file:
h5_file.create_carray('/', 'reg_data', obj=reg_data)
1 boucles, meilleur de 3: 849 ms par boucle
Il en va de même pour la lecture:
%%timeit
with tables.open_file('array.tbl', 'r') as h5_file:
reg_data2 = h5_file.root.reg_data.read()
1 loops, best of 3: 1.7 s per loop
Conclusion: Plus vos données sont régulières, plus vite elles devraient utiliser PyTables.
D'après mon expérience, np.save () & np.load () est la solution la plus rapide pour transférer des données entre le disque dur et la mémoire jusqu'à présent. J'ai fortement compté mes données de chargement sur la base de données et le système HDFS avant de réaliser cette conclusion. Mes tests montrent que: La bande passante de chargement des données de la base de données (du disque dur à la mémoire) pourrait être d'environ 50 Mbps (octets/seconde), mais la bande passante np.load () est presque la même que la bande passante maximale de mon disque dur: 2 Go/s (octets/Seconde). Les deux environnements de test utilisent la structure de données la plus simple.
Et je ne pense pas que ce soit un problème d'utiliser plusieurs secondes pour charger un tableau de forme: (1e3, 1e6). Par exemple. La forme de votre tableau est (1000, 1000000), son type de données est float128, puis la taille de données pure est (128/8) * 1000 * 1,000,000 = 16,000,000,000 = 16GBytes et si cela prend 4 secondes, votre bande passante de chargement de données est alors de 16GBytes/4 secondes = 4 Go/s. La bande passante maximale SATA3 est de 600 Mo/s = 0,6 Go/s, votre bande passante de chargement de données est déjà 6 fois supérieure, vos performances de chargement de données pourraient presque rivaliser avec bande passante maximale de DDR , que voulez-vous d'autre?
Donc ma conclusion finale est:
N'utilisez pas Pickle de python, n'utilisez aucune base de données, n'utilisez aucun système de Big Data pour stocker vos données sur le disque dur, si vous pouviez utiliser np.save () et np .charge(). Jusqu'à présent, ces deux fonctions sont la solution la plus rapide pour transférer des données entre le disque dur et la mémoire.
J'ai également testé le HDF5 , et j'ai trouvé qu'il était plus lent que np.load () et np.save (), alors utilisez np.save () & np.load () si vous avez suffisamment de mémoire DDR dans votre platfrom.