在存档上没有时间戳的情况下将pandas DataFrame写入gzip csv

时间:2019-01-08 17:43:40

标签: python pandas gzip

将pandas DataFrame写入gzip压缩的CSV会将时间戳添加到归档文件中:

import pandas as pd
df = pd.DataFrame({'a': [1]})
df.to_csv('df.csv.gz', compression='gzip')
# Timestamp is the large number per https://unix.stackexchange.com/a/79546/88807.
!<df.csv.gz dd bs=4 skip=1 count=1 | od -t d4
# 1+0 records in
# 1+0 records out
# 4 bytes copied, 5.6233e-05 s, 71.1 kB/s
# 0000000  1546978755
# 0000004df.csv

我想在没有时间戳的情况下编写它,以便同一DataFrame的两个后续导出是相同的:

df.to_csv('df2.csv.gz', compression='gzip')
import filecmp
filecmp.cmp('df.csv.gz', 'df2.csv.gz')
# False

2 个答案:

答案 0 :(得分:1)

浏览CSV writing的Pandas代码后,我建议的最好方法是直接使用gzip模块。这样,您可以直接设置mtime attribute,而这似乎正是您想要的:

import pandas as pd
from gzip import GzipFile
from io import TextIOWrapper

def to_gzip_csv_no_timestamp(df, f, *kwargs):
    # Write pandas DataFrame to a .csv.gz file, without a timestamp in the archive
    # header, using GzipFile and TextIOWrapper.
    #
    # Args:
    #     df: pandas DataFrame.
    #     f: Filename string ending in .csv (not .csv.gz).
    #     *kwargs: Other arguments passed to to_csv().
    #
    # Returns:
    #     Nothing.
    with TextIOWrapper(GzipFile(f, 'w', mtime=0), encoding='utf-8') as fd:
        df.to_csv(fd, *kwargs)

to_gzip_csv_no_timestamp(df, 'df.csv.gz')
to_gzip_csv_no_timestamp(df, 'df2.csv.gz')

filecmp.cmp('df.csv.gz', 'df2.csv.gz')
# True

对于这个小型数据集,此方法的效果优于下面的两步subprocess方法:

%timeit to_gzip_csv_no_timestamp(df, 'df.csv')                                                                                                                                                                                                                                    
693 us +- 14.6 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)

%timeit to_gzip_csv_no_timestamp_subprocess(df, 'df.csv')
10.2 ms +- 167 us per loop (mean +- std. dev. of 7 runs, 100 loops each)

我正在使用TextIOWrapper()来处理将字符串转换为字节Pandas does的情况,但是如果您知道自己不会节省太多数据,也可以这样做:

with GzipFile('df.csv.gz', 'w', mtime=0) as fd:
    fd.write(df.to_csv().encode('utf-8'))

请注意,gzip -lv df.csv.gz仍显示“当前时间”,但这只是将其从inode的mtime中拉出。使用hexdump -C进行转储会显示该值已保存在文件中,而mtime(使用touch -mt 0711171533 df.csv.gz)更改文件会使gzip显示不同的值

还请注意,原始的“文件名”也是gzip压缩文件的一部分,因此您需要写相同的名称(或覆盖它)以使其具有确定性。

答案 1 :(得分:0)

您可以导出为未压缩的CSV,然后使用gzip标志调用-n以避免时间戳记(这也是不将文件名保存在存档中的指令):

import subprocess

def to_gzip_csv_no_timestamp_subprocess(df, f, *kwargs):
    # Write pandas DataFrame to a .csv.gz file, without a timestamp in the archive
    # header.
    # Args:
    #     df: pandas DataFrame.
    #     f: Filename string ending in .csv (not .csv.gz).
    #     *kwargs: Other arguments passed to to_csv().
    # Returns:
    #     Nothing.
    import subprocess
    df.to_csv(f, *kwargs)
    # -n for the timestamp, -f to overwrite.
    subprocess.check_call(['gzip', '-nf', f])

to_gzip_csv_no_timestamp(df, 'df.csv')
to_gzip_csv_no_timestamp(df, 'df2.csv')
filecmp.cmp('df.csv.gz', 'df2.csv.gz')
# True