2
votes

Pandas dataframe CSV réduit la taille du disque

pour ma mission universitaire, je dois produire un fichier csv avec toutes les distances des aéroports du monde ... le problème est que mon fichier csv pèse 151Mo. Je veux le réduire autant que possible: Voici mon csv:

entrez la description de l'image ici

et voici mon code:

# remove all NaN values
airportdists = airportdists.stack().reset_index()
airportdists.columns = ['airport1','airport2','distance']

J'ai aussi essayé de le réindexer avant de l'enregistrer:

# drop all features we don't need
for attribute in df:
    if attribute not in ('NAME', 'COUNTRY', 'IATA', 'LAT', 'LNG'):
        df = df.drop(attribute, axis=1)

# create a dictionary of airports, each airport has the following structure:
# IATA : (NAME, COUNTRY, LAT, LNG)
airport_dict = {}
for airport in df.itertuples():
    airport_dict[airport[3]] = (airport[1], airport[2], airport[4], airport[5])

# From tutorial 4 soulution:
airportcodes=list(airport_dict)
airportdists=pd.DataFrame()
for i, airport_code1 in enumerate(airportcodes):
    airport1 = airport_dict[airport_code1]
    dists=[]
    for j, airport_code2 in enumerate(airportcodes):
        if j > i:
            airport2 = airport_dict[airport_code2]
            dists.append(distanceBetweenAirports(airport1[2],airport1[3],airport2[2],airport2[3]))
        else:
        # little edit: no need to calculate the distance twice, all duplicates are set to 0 distance
            dists.append(0)
    airportdists[i]=dists
airportdists.columns=airportcodes
airportdists.index=airportcodes

# set all 0 distance values to NaN
airportdists = airportdists.replace(0, np.nan)
airportdists.to_csv(r'../Project Data Files-20190322/distances.csv')

mais le résultat est un dataframe avec 3 colonnes et 17 millions de colonnes et un disque taille de 419Mb ... ce n'est pas une amélioration ...

Pouvez-vous m'aider à réduire la taille de mon csv? Merci!


5 commentaires

17 000 000 lignes * 3 colonnes / 1024/1024 = 48 Mo si on suppose un caractère par ligne 151 Mo = 3 caractères en moyenne par ligne ... comment voulez-vous réduire votre fichier de sortie? pas possible? sauf si vous voulez plusieurs fichiers plus petits


Merci @Frenchy ouais je ne sais pas s'il est possible de réduire la dimension du fichier, c'est ce que je demande eh eh


combien d'aéroports avez-vous?


@Frenchy 9541 aéroports


Pas de manière significative. 9541 aéroports signifie que vous avez environ 91 millions de paires d'aéroports, 45,5 millions si vous ignorez les doublons. Pour la plupart d'entre eux, vous avez besoin de 3 à 4 caractères pour la distance et d'un pour le séparateur. Cela considéré comme 151 MiB est plutôt bon. CSV en texte brut n'est pas très efficace en termes d'espace. À moins d'utiliser la compression et / ou le format binaire, vous ne ferez pas beaucoup mieux. | Pourquoi est-ce un problème de toute façon?


4 Réponses :


2
votes

Le titre de la question, ".. réduire la taille du disque" est résolu en sortant une version compressée du csv.

airportdists.to_csv(r'../Project Data Files-20190322/distances.csv.zip')

Ou mieux avec Pandas 0.24.0

airportdists.to_csv(r'../Project Data Files-20190322/distances.csv', compression='zip')

Vous constaterez que le csv est extrêmement compressé.

Cela ne résout bien sûr pas l'optimisation de la charge et le gain de temps et ne fait rien pour la mémoire de travail. Mais, espérons-le, utile lorsque l'espace disque est limité ou que le stockage dans le cloud est payé.


2 commentaires

Euh, ouais je cherchais en fait une solution qui n'implique pas de fichier zip: comme avec de la musique mp3 ou avec des images png, jpeg: je voudrais éviter de compresser le fichier mais à la place utiliser un algorithme de compression différent pour réduire son espace sur le disque


Je ne comprends pas tout à fait. 0.24.0 a une variété de stratégies de compression. zip n'en est qu'un. Je pense donc que vous espérez peut-être réduire la quantité de mémoire de travail pendant que les données sont chargées dans les pandas. Pour cela, ce sera un problème d'algorithme / structures de données à résoudre.



3
votes

J'ai fait une application similaire dans le passé; voici ce que je vais faire:

Il est difficile de réduire votre fichier, mais si votre application a besoin d'avoir par exemple une distance entre un aéroport des autres, je vous propose de créer 9541 fichiers, chaque fichier sera la distance d'un aéroport aux autres et son nom sera le nom de l'aéroport.

Dans ce cas, le chargement du fichier est très rapide.


1 commentaires

J'essaierai cela dès que possible et je vous le ferai savoir ;-)



1
votes

La meilleure compression serait de stocker à la place la latitude et la longitude de chaque aéroport, puis de calculer la distance entre deux paires sur demande. Disons, deux valeurs à virgule flottante de 32 bits pour chaque aéroport et l'identifiant, qui serait d'environ 110 Ko. Compressé par un facteur d'environ 1300.


2 commentaires

Salut Mark, pouvez-vous être plus précis? qu'est-ce qu'un facteur de compression?


Divisez le nombre de bits non compressés par le nombre de bits compressés.



1
votes

Ma suggestion sera au lieu de stocker au format CSV, d'essayer de stocker dans une structure de données de paires de valeurs clés comme JSON. Ce sera très rapide lors de la récupération. Ou essayez le format de fichier parquet qui consommera 1/4 du stockage du fichier CSV.

import pandas as pd
import numpy as np
from pathlib import Path
from string import ascii_letters

#created a dataframe
df = pd.DataFrame(np.random.randint(0,10000,size=(1000000, 52)),columns=list(ascii_letters))

df.to_csv('csv_store.csv',index=False)
print('CSV Consumend {} MB'.format(Path('csv_store.csv').stat().st_size*0.000001))
#CSV Consumend 255.22423999999998 MB

df.to_parquet('parquate_store',index=False)
print('Parquet Consumed {} MB'.format(Path('parquate_store').stat().st_size*0.000001))
#Parquet Consumed 93.221154 MB


1 commentaires

Bienvenue dans StackOverflow, ajoutez plus de description et de code si nécessaire pour comprendre la réponse, car cela résoudra le problème de quelqu'un d'autre dès que possible.