Пишите DataFrame панд в czv gzip без метки времени в архиве - PullRequest
0 голосов
/ 08 января 2019

Запись DataFrame pandas в сжатый 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 ]

0 голосов
/ 08 января 2019

Вы можете экспортировать как несжатый 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
0 голосов
/ 08 января 2019

После просмотра кода Pandas для записи CSV лучшее, что я могу предложить, - это использовать модуль gzip напрямую. таким образом, вы можете установить атрибут mtime напрямую, что, как вам кажется:

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 делает , но вы также можете сделать это, если знаете, что не собираетесь сохранять много данных:

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

Обратите внимание, что gzip -lv df.csv.gz по-прежнему показывает "текущее время", но оно просто извлекает его из mtime inode. дамп с hexdump -C показывает, что значение сохранено в файле, а при изменении файлов mtime (с touch -mt 0711171533 df.csv.gz) gzip отображает другое значение

Также обратите внимание, что исходное «имя файла» также является частью файла gzipped, поэтому вам нужно записать его под тем же именем (или переопределить это), чтобы сделать его детерминированным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...