J'essaie de lire un gros fichier csv (environ 6 Go) dans pandas et j'obtiens une erreur de mémoire:
MemoryError Traceback (most recent call last)
<ipython-input-58-67a72687871b> in <module>()
----> 1 data=pd.read_csv('aphro.csv',sep=';')
...
MemoryError:
Une aide à ce sujet?
Réponses:
L'erreur montre que la machine ne dispose pas de suffisamment de mémoire pour lire le CSV entier dans un DataFrame en même temps. En supposant que vous n'avez pas besoin de l'ensemble de données en mémoire en une seule fois, une façon d'éviter le problème serait de traiter le CSV en morceaux (en spécifiant le
chunksize
paramètre):chunksize = 10 ** 6 for chunk in pd.read_csv(filename, chunksize=chunksize): process(chunk)
Le
chunksize
paramètre spécifie le nombre de lignes par bloc. (Le dernier morceau peut contenir moins dechunksize
lignes, bien sûr.)la source
DF.append(chunk)
à l'intérieur de la boucle. Cela utilisera desO(N^2)
opérations de copie. Il est préférable d'ajouter les données agrégées à une liste , puis de créer le DataFrame à partir de la liste avec un appel àpd.DataFrame
oupd.concat
(selon le type de données agrégées).DF.append(chunk)
dans une boucle nécessite desO(N^2)
opérations de copie oùN
est la taille des morceaux, car chaque appel àDF.append
renvoie un nouveau DataFrame. L'appelpd.DataFrame
oupd.concat
une fois en dehors de la boucle réduit la quantité de copie versO(N)
.chunksize
paramètre fait référence au nombre de lignes par bloc. Le dernier morceau peut contenir moins dechunksize
lignes, bien sûr.pd.concat([list_of_dfs])
une fois après la boucle est beaucoup plus rapide que d'appelerpd.concat
oudf.append
plusieurs fois dans la boucle. Bien sûr, vous aurez besoin d'une quantité considérable de mémoire pour contenir l'intégralité du csv de 6 Go en un seul DataFrame.La segmentation ne devrait pas toujours être le premier port d'escale pour ce problème.
Le fichier est-il volumineux en raison de données non numériques répétées ou de colonnes indésirables?
Si tel est le cas, vous pouvez parfois constater des économies de mémoire massives en lisant les colonnes sous forme de catégories et en sélectionnant les colonnes requises via le paramètre pd.read_csv
usecols
.Votre flux de travail nécessite-t-il un découpage, une manipulation, une exportation?
Si tel est le cas, vous pouvez utiliser dask.dataframe pour découper, effectuer vos calculs et exporter de manière itérative. La segmentation est effectuée silencieusement par dask, qui prend également en charge un sous-ensemble d'API pandas.
Si tout le reste échoue, lisez ligne par ligne via des morceaux.
Chunk via pandas ou via la bibliothèque csv en dernier recours.
la source
Pour les données volumineuses, je vous recommande d'utiliser la bibliothèque "dask"
par exemple:
# Dataframes implement the Pandas API import dask.dataframe as dd df = dd.read_csv('s3://.../2018-*-*.csv')
Vous pouvez en savoir plus dans la documentation ici .
Une autre excellente alternative serait d'utiliser modin car toutes les fonctionnalités sont identiques à celles des pandas tout en exploitant des bibliothèques de dataframe distribuées telles que dask.
la source
J'ai procédé comme ceci:
chunks=pd.read_table('aphro.csv',chunksize=1000000,sep=';',\ names=['lat','long','rf','date','slno'],index_col='slno',\ header=None,parse_dates=['date']) df=pd.DataFrame() %time df=pd.concat(chunk.groupby(['lat','long',chunk['date'].map(lambda x: x.year)])['rf'].agg(['sum']) for chunk in chunks)
la source
read_csv
àread_table
?La réponse ci-dessus satisfait déjà le sujet. Quoi qu'il en soit, si vous avez besoin de toutes les données en mémoire, jetez un œil à bcolz . Sa compression des données en mémoire. J'ai eu une très bonne expérience avec. Mais il manque beaucoup de fonctionnalités de pandas
Edit: J'ai eu des taux de compression d'environ 1/10 ou de la taille d'origine je pense, bien sûr en fonction du type de données. Les éléments importants manquants étaient les agrégats.
la source
chunks
méthode mentionnée, puis utiliser bcolz si vous avez besoin de toutes les données en mémoire pour faire une analyse. Juste une pensée.Vous pouvez lire les données sous forme de morceaux et enregistrer chaque morceau sous forme de cornichon.
import pandas as pd import pickle in_path = "" #Path where the large file is out_path = "" #Path to save the pickle files to chunk_size = 400000 #size of chunks relies on your available memory separator = "~" reader = pd.read_csv(in_path,sep=separator,chunksize=chunk_size, low_memory=False) for i, chunk in enumerate(reader): out_file = out_path + "/data_{}.pkl".format(i+1) with open(out_file, "wb") as f: pickle.dump(chunk,f,pickle.HIGHEST_PROTOCOL)
À l'étape suivante, vous lisez les cornichons et ajoutez chaque cornichon à la trame de données souhaitée.
import glob pickle_path = "" #Same Path as out_path i.e. where the pickle files are data_p_files=[] for name in glob.glob(pickle_path + "/data_*.pkl"): data_p_files.append(name) df = pd.DataFrame([]) for i in range(len(data_p_files)): df = df.append(pd.read_pickle(data_p_files[i]),ignore_index=True)
la source
df
tient entièrement en mémoire (comme implicite) et contient la même quantité de données que votre entrée, vous n'avez sûrement pas besoin de segmenter du tout?La fonction read_csv et read_table est presque la même. Mais vous devez affecter le délimiteur «,» lorsque vous utilisez la fonction read_table dans votre programme.
def get_from_action_data(fname, chunk_size=100000): reader = pd.read_csv(fname, header=0, iterator=True) chunks = [] loop = True while loop: try: chunk = reader.get_chunk(chunk_size)[["user_id", "type"]] chunks.append(chunk) except StopIteration: loop = False print("Iteration is stopped") df_ac = pd.concat(chunks, ignore_index=True)
la source
Je souhaite apporter une réponse plus complète basée sur la plupart des solutions potentielles déjà proposées. Je tiens également à souligner une autre aide potentielle qui peut aider le processus de lecture.
Option 1: dtypes
"dtypes" est un paramètre assez puissant que vous pouvez utiliser pour réduire la pression mémoire des
read
méthodes. Voyez ceci et cette réponse. Les pandas, par défaut, essaient de déduire les dtypes des données.En se référant aux structures de données, à chaque donnée stockée, une allocation de mémoire a lieu. Au niveau de base, reportez-vous aux valeurs ci-dessous (le tableau ci-dessous illustre les valeurs pour le langage de programmation C):
The maximum value of UNSIGNED CHAR = 255 The minimum value of SHORT INT = -32768 The maximum value of SHORT INT = 32767 The minimum value of INT = -2147483648 The maximum value of INT = 2147483647 The minimum value of CHAR = -128 The maximum value of CHAR = 127 The minimum value of LONG = -9223372036854775808 The maximum value of LONG = 9223372036854775807
Reportez-vous à cette page pour voir la correspondance entre les types NumPy et C.
Disons que vous avez un tableau d'entiers de chiffres . Vous pouvez à la fois théoriquement et pratiquement affecter, par exemple, un tableau de type entier 16 bits, mais vous alloueriez alors plus de mémoire que ce dont vous avez réellement besoin pour stocker ce tableau. Pour éviter cela, vous pouvez activer l'
dtype
optionread_csv
. Vous ne souhaitez pas stocker les éléments du tableau sous forme d'entier long où vous pouvez en fait les insérer avec un entier 8 bits (np.int8
ounp.uint8
).Observez la carte dtype suivante.
Source: https://pbpython.com/pandas_dtypes.html
Vous pouvez passer le
dtype
paramètre comme paramètre sur les méthodes pandas comme dict surread
comme {column: type}.import numpy as np import pandas as pd df_dtype = { "column_1": int, "column_2": str, "column_3": np.int16, "column_4": np.uint8, ... "column_n": np.float32 } df = pd.read_csv('path/to/file', dtype=df_dtype)
Option 2: lire par morceaux
La lecture des données par blocs vous permet d'accéder à une partie des données en mémoire, et vous pouvez appliquer un prétraitement sur vos données et conserver les données traitées plutôt que les données brutes. Ce serait bien mieux si vous combinez cette option avec la première, dtypes .
Je tiens à souligner les sections du livre de recettes pandas pour ce processus, où vous pouvez le trouver ici . Notez ces deux sections ici;
Option 3: Dask
Dask est un framework défini sur le site Web de Dask comme:
Il est né pour couvrir les parties nécessaires où les pandas ne peuvent pas atteindre. Dask est un framework puissant qui vous permet d'accéder beaucoup plus aux données en les traitant de manière distribuée.
Vous pouvez utiliser dask pour prétraiter vos données dans leur ensemble, Dask s'occupe de la partie de segmentation, donc contrairement aux pandas, vous pouvez simplement définir vos étapes de traitement et laisser Dask faire le travail. Dask n'applique pas les calculs avant d'être explicitement poussé par
compute
et / oupersist
(voir la réponse ici pour la différence).Autres aides (idées)
la source
Solution 1:
Utiliser des pandas avec des données volumineuses
Solution 2:
TextFileReader = pd.read_csv(path, chunksize=1000) # the number of rows per chunk dfList = [] for df in TextFileReader: dfList.append(df) df = pd.concat(dfList,sort=False)
la source
dfList.append
, traitez simplement chaque morceau (df
) séparémentVoici un exemple:
chunkTemp = [] queryTemp = [] query = pd.DataFrame() for chunk in pd.read_csv(file, header=0, chunksize=<your_chunksize>, iterator=True, low_memory=False): #REPLACING BLANK SPACES AT COLUMNS' NAMES FOR SQL OPTIMIZATION chunk = chunk.rename(columns = {c: c.replace(' ', '') for c in chunk.columns}) #YOU CAN EITHER: #1)BUFFER THE CHUNKS IN ORDER TO LOAD YOUR WHOLE DATASET chunkTemp.append(chunk) #2)DO YOUR PROCESSING OVER A CHUNK AND STORE THE RESULT OF IT query = chunk[chunk[<column_name>].str.startswith(<some_pattern>)] #BUFFERING PROCESSED DATA queryTemp.append(query) #! NEVER DO pd.concat OR pd.DataFrame() INSIDE A LOOP print("Database: CONCATENATING CHUNKS INTO A SINGLE DATAFRAME") chunk = pd.concat(chunkTemp) print("Database: LOADED") #CONCATENATING PROCESSED DATA query = pd.concat(queryTemp) print(query)
la source
Vous pouvez essayer sframe, qui a la même syntaxe que les pandas mais vous permet de manipuler des fichiers plus gros que votre RAM.
la source
Si vous utilisez des pandas, lisez un gros fichier en bloc, puis cédez ligne par ligne, voici ce que j'ai fait
import pandas as pd def chunck_generator(filename, header=False,chunk_size = 10 ** 5): for chunk in pd.read_csv(filename,delimiter=',', iterator=True, chunksize=chunk_size, parse_dates=[1] ): yield (chunk) def _generator( filename, header=False,chunk_size = 10 ** 5): chunk = chunck_generator(filename, header=False,chunk_size = 10 ** 5) for row in chunk: yield row if __name__ == "__main__": filename = r'file.csv' generator = generator(filename=filename) while True: print(next(generator))
la source
En plus des réponses ci-dessus, pour ceux qui souhaitent traiter CSV puis exporter vers csv, parquet ou SQL, d6tstack est une autre bonne option. Vous pouvez charger plusieurs fichiers et il traite des changements de schéma de données (colonnes ajoutées / supprimées). La prise en charge de base est déjà intégrée.
def apply(dfg): # do stuff return dfg c = d6tstack.combine_csv.CombinerCSV([bigfile.csv], apply_after_read=apply, sep=',', chunksize=1e6) # or c = d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), apply_after_read=apply, chunksize=1e6) # output to various formats, automatically chunked to reduce memory consumption c.to_csv_combine(filename='out.csv') c.to_parquet_combine(filename='out.pq') c.to_psql_combine('postgresql+psycopg2://usr:pwd@localhost/db', 'tablename') # fast for postgres c.to_mysql_combine('mysql+mysqlconnector://usr:pwd@localhost/db', 'tablename') # fast for mysql c.to_sql_combine('postgresql+psycopg2://usr:pwd@localhost/db', 'tablename') # slow but flexible
la source
Au cas où quelqu'un cherche toujours quelque chose comme ça, j'ai trouvé que cette nouvelle bibliothèque appelée modin peut aider. Il utilise l'informatique distribuée qui peut aider à la lecture. Voici un bel article comparant ses fonctionnalités aux pandas. Il utilise essentiellement les mêmes fonctions que les pandas.
import modin.pandas as pd pd.read_csv(CSV_FILE_NAME)
la source
modin
comparaison de ce nouveau module avec le bien établidask.dataframe
? Par exemple, consultez passer de pandas à dask pour utiliser tous les cœurs de processeur locaux .Avant d'utiliser l'option chunksize, si vous voulez être sûr de la fonction de processus que vous souhaitez écrire dans la boucle for de segmentation comme mentionné par @unutbu, vous pouvez simplement utiliser l'option nrows.
small_df = pd.read_csv(filename, nrows=100)
Une fois que vous êtes sûr que le bloc de processus est prêt, vous pouvez le placer dans la boucle de segmentation for pour l'ensemble de la trame de données.
la source