使用 python 和 pandas 传输和写入 Parquet 时出现时间戳错误

Transfer and write Parquet with python and pandas got timestamp error

我试图在 python 中用 pandas concat() 两个镶木地板文件。
它可以工作,但是当我尝试写入数据框并将其保存到镶木地板文件时,它显示错误:

 ArrowInvalid: Casting from timestamp[ns] to timestamp[ms] would lose data:

我查了文档。 of pandas,写入parquet文件时默认时间戳语法以毫秒为单位。
如何在 concat 后使用已用模式将 parquet 文件白色化?
这是我的代码:

import pandas as pd

table1 = pd.read_parquet(path= ('path.parquet'),engine='pyarrow')
table2 = pd.read_parquet(path= ('path.parquet'),engine='pyarrow')

table = pd.concat([table1, table2], ignore_index=True) 
table.to_parquet('./file.gzip', compression='gzip')

我认为这是一个错误,您应该按照 Wes 所说的进行操作。但是,如果您现在需要工作代码,我有一个解决方法。

对我有用的解决方案是将时间戳列指定为毫秒精度。如果您需要纳秒精度,这会破坏您的数据...但如果是这样,这可能是您的问题中最少的。

import pandas as pd

table1 = pd.read_parquet(path=('path1.parquet'))
table2 = pd.read_parquet(path=('path2.parquet'))

table1["Date"] = table1["Date"].astype("datetime64[ms]")
table2["Date"] = table2["Date"].astype("datetime64[ms]")

table = pd.concat([table1, table2], ignore_index=True) 
table.to_parquet('./file.gzip', compression='gzip')

我在使用 pd.to_parquet 时遇到了类似的问题,我最终的解决方法是使用参数 engine='fastparquet',但我意识到如果您需要专门使用 PyArrow,这并没有帮助。

我试过但没有用的东西:

  • @DrDeadKnee 的手动转换列 .astype("datetime64[ms]") 的解决方法对我不起作用(pandas v. 0.24.2
  • coerce_timestamps='ms' 作为 kwarg 传递给底层 parquet 操作并没有改变行为。

Pandas 至少从 v0.22 开始就已经将未知的 kwargs 转发给底层的镶木地板引擎。因此,使用 table.to_parquet(allow_truncated_timestamps=True) 应该有效——我针对 pandas v0.25.0 和 pyarrow 0.13.0 验证了它。有关更多关键字,请参阅 the pyarrow docs

感谢@axel link to Apache Arrow documentation:

allow_truncated_timestamps (bool, default False) – Allow loss of data when coercing timestamps to a particular resolution. E.g. if microsecond or nanosecond data is lost when coercing to ‘ms’, do not raise an exception.

似乎在现代 Pandas 版本中我们可以将参数传递给 ParquetWriter

以下代码对我来说工作正常(Pandas 1.1.1,PyArrow 1.0.1):

df.to_parquet(filename, use_deprecated_int96_timestamps=True)

我在将带有 datetime64[ns] 列的 dask DataFrame 写入 AWS S3 并将它们爬入 Athena 表时遇到了一个相关的数量级问题。

问题是后续的 Athena 查询将日期时间字段显示为年份 >57000 而不是 2020。我设法使用了以下修复:

df.to_parquet(path, times="int96")

将 kwarg **{"times": "int96"} 转发到 fastparquet.writer.write()。

我使用包 parquet-tools 检查了生成的 parquet 文件。它确实将日期时间列显示为 INT96 存储格式。在 Athena(基于 Presto)上,int96 格式得到很好的支持,不存在数量级问题。

参考:https://github.com/dask/fastparquet/blob/master/fastparquet/writer.py、函数 write()、kwarg times。 (dask 2.30.0 ; fastparquet 0.4.1 ; pandas 1.1.4)