代码之家  ›  专栏  ›  技术社区  ›  Max Ghenis shoyer

将pandas数据帧写入gzip csv,存档上没有时间戳

  •  0
  • Max Ghenis shoyer  · 技术社区  · 6 年前

    将熊猫数据帧写入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
    

    我想在不使用时间戳的情况下编写它,这样相同数据帧的两个后续导出是相同的:

    df.to_csv('df2.csv.gz', compression='gzip')
    import filecmp
    filecmp.cmp('df.csv.gz', 'df2.csv.gz')
    # False
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Max Ghenis shoyer    6 年前

    看完熊猫守则后 CSV writing ,我建议最好使用 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文件的一部分,因此您需要使用相同的名称(或重写此名称)来使其具有确定性。

        2
  •  0
  •   Max Ghenis shoyer    6 年前

    您可以导出为未压缩的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