将 pandas DataFrame 写入 gzip csv,存档上没有时间戳
Write pandas DataFrame to a gzip csv without a timestamp on the archive
正在将 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
直接查看 CSV writing, the best I can suggest is to use the gzip
module directly. that way you can set the mtime
attribute 的 Pandas 代码后,这似乎是您想要的:
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
仍然显示 "current time" 但它只是从 inode 的 mtime 中提取它。使用 hexdump -C
转储显示值保存在文件中,更改文件 mtime(使用 touch -mt 0711171533 df.csv.gz
)导致 gzip
显示不同的值
另请注意,原始 "filename" 也是 gzip 文件的一部分,因此您需要写入相同的名称(或也覆盖它)以使其具有确定性。
您可以导出为未压缩的 CSV,然后使用 -n
标志调用 gzip
以避免时间戳(这也是不在存档中保存文件名的说明):
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
正在将 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
直接查看 CSV writing, the best I can suggest is to use the gzip
module directly. that way you can set the mtime
attribute 的 Pandas 代码后,这似乎是您想要的:
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
仍然显示 "current time" 但它只是从 inode 的 mtime 中提取它。使用 hexdump -C
转储显示值保存在文件中,更改文件 mtime(使用 touch -mt 0711171533 df.csv.gz
)导致 gzip
显示不同的值
另请注意,原始 "filename" 也是 gzip 文件的一部分,因此您需要写入相同的名称(或也覆盖它)以使其具有确定性。
您可以导出为未压缩的 CSV,然后使用 -n
标志调用 gzip
以避免时间戳(这也是不在存档中保存文件名的说明):
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