Pandas 数据框 CSV 压缩磁盘空间

3

我需要制作一个包含世界各地机场距离的CSV文件来完成我的大学作业……问题是我的CSV文件大小为151MB,我希望尽可能地减小它的大小。

这是我的CSV文件:

enter image description here

这是我的代码:

# 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')

我也尝试在保存之前重新索引它:
# remove all NaN values
airportdists = airportdists.stack().reset_index()
airportdists.columns = ['airport1','airport2','distance']

但是结果是一个有3列和1700万行的数据框,磁盘大小为419Mb...并没有太大的改进...
你能帮我缩小csv文件的大小吗?谢谢!

17,000,000行* 3列/1024 / 1024 = 48 Mb(如果假定一行一个字符) 151 Mb=平均每行3个字符...你想如何缩小输出文件?除非您要多个较小的文件,否则不可能。 - Frenchy
谢谢@Frenchy,是的,我不确定是否可以减小文件大小,这就是我在问的呢。 - Fabio Magarelli
你有多少个机场? - Frenchy
@Frenchy 9541 个机场 - Fabio Magarelli
1
并不算太多。9541个机场意味着你有大约9100万个机场对,如果忽略重复的话则为4550万个。对于大多数情况下,你需要3-4个字符来表示距离,以及一个分隔符。考虑到这些因素,151 MiB已经相当不错了。CSV作为纯文本并不是非常节省空间。除非你使用压缩和/或二进制格式,否则你不会得到更好的效果。| 无论如何,这是什么问题呢? - Dan Mašek
4个回答

4
我过去完成过类似的应用程序; 我将会做以下事情:
文件缩小难度较大, 但如果您的应用程序需要例如一个机场与其他机场之间的距离, 我建议您创建9541个文件,每个文件将是一个机场到其他机场的距离, 文件名将是机场的名称。
在这种情况下, 文件的加载非常快速。

1
我会尽快尝试并告诉你的;-) - Fabio Magarelli

3

我的建议是,不要将数据存储为 CSV 格式,而是使用键值对数据结构,如 JSON。这样在检索时速度会更快。或者尝试使用 Parquet 文件格式,它的存储空间只有 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

欢迎来到 StackOverflow,如果需要更好地理解答案以便尽快解决其他人的问题,请添加一些详细描述和代码。 - Nensi Kasundra

2
问题的标题“..减小磁盘大小”可以通过输出压缩版本的csv文件来解决。
airportdists.to_csv(r'../Project Data Files-20190322/distances.csv', compression='zip')

或者使用Pandas 0.24.0更新更好

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

你会发现 CSV 文件已经被大幅压缩。

当然,这并不能解决优化加载和保存时间以及对工作内存的影响。但是当磁盘空间有限或云存储需要付费时,希望能有所帮助。


嗯,是的,我实际上正在寻找一种不涉及压缩文件的解决方案:就像音乐mp3或图像png、jpeg一样:我想避免压缩文件,而是使用不同的压缩算法来减少它在磁盘上的空间。 - Fabio Magarelli
我并不完全理解。0.24.0版本有多种压缩策略,zip只是其中之一。所以我认为你可能希望在pandas加载数据时减少工作内存的使用量。为此,这将是一个需要解决算法/数据结构问题的挑战。 - Rich Andrews

1
最好的压缩方式是存储每个机场的纬度和经度,然后在需要时计算任意两对之间的距离。例如,每个机场使用两个32位浮点值和标识符,大约需要110K字节。压缩比约为1300。

嗨,马克,你能更具体一些吗?什么是压缩因子? - Fabio Magarelli
将未压缩位数除以压缩位数。 - Mark Adler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接