保存 pd.DataFrame 时如何强制 parquet dtypes?

Posted

技术标签:

【中文标题】保存 pd.DataFrame 时如何强制 parquet dtypes?【英文标题】:How to force parquet dtypes when saving pd.DataFrame? 【发布时间】:2018-10-11 02:40:32 【问题描述】:

有没有办法强制 parquet 文件将 pd.DataFrame 列编码为给定类型,即使该列的所有值都为空? parquet 在其架构中自动分配“null”这一事实阻止了我将许多文件加载到单个 dask.dataframe 中。

尝试使用 df.column_name = df.column_name.astype(sometype) 投射 pandas 列没有成功。

我为什么要问这个

我想将许多 parquet 文件加载到一个 dask.dataframe 中。所有文件都是从pd.DataFrame 的多个实例中生成的,使用df.to_parquet(filename)。所有数据框都有相同的列,但对于某些给定的列可能只包含空值。尝试将所有文​​件加载到 dask.dataframe 时(使用 df = dd.read_parquet('*.parquet') ,我收到以下错误:

Schema in filename.parquet was different.
id: int64
text: string
[...]
some_column: double

vs

id: int64
text: string
[...]
some_column: null

重现我的问题的步骤

import pandas as pd
import dask.dataframe as dd
a = pd.DataFrame(['1', '1'], columns=('value',))
b = pd.DataFrame([None, None], columns=('value',))
a.to_parquet('a.parquet')
b.to_parquet('b.parquet')
df = dd.read_parquet('*.parquet')  # Reads a and b

这给了我以下信息:

ValueError: Schema in path/to/b.parquet was different. 
value: null
__index_level_0__: int64
metadata
--------
b'pandas': b'"index_columns": ["__index_level_0__"], "column_indexes": ["na'
            b'me": null, "field_name": null, "pandas_type": "unicode", "numpy_'
            b'type": "object", "metadata": "encoding": "UTF-8"], "columns":'
            b' ["name": "value", "field_name": "value", "pandas_type": "empty'
            b'", "numpy_type": "object", "metadata": null, "name": null, "fi'
            b'eld_name": "__index_level_0__", "pandas_type": "int64", "numpy_t'
            b'ype": "int64", "metadata": null], "pandas_version": "0.22.0"'

vs

value: string
__index_level_0__: int64
metadata
--------
b'pandas': b'"index_columns": ["__index_level_0__"], "column_indexes": ["na'
            b'me": null, "field_name": null, "pandas_type": "unicode", "numpy_'
            b'type": "object", "metadata": "encoding": "UTF-8"], "columns":'
            b' ["name": "value", "field_name": "value", "pandas_type": "unico'
            b'de", "numpy_type": "object", "metadata": null, "name": null, "'
            b'field_name": "__index_level_0__", "pandas_type": "int64", "numpy'
            b'_type": "int64", "metadata": null], "pandas_version": "0.22.0"'

请注意,在一种情况下我们有"pandas_type": "unicode",在另一种情况下我们有"pandas_type": "empty"

没有为我提供解决方案的相关问题

How to specify logical types when writing Parquet files from PyArrow?

【问题讨论】:

【参考方案1】:

如果你改用fastparquet,你可以实现你想要的聊天

import pandas as pd
import dask.dataframe as dd
a = pd.DataFrame(['1', '1'], columns=('value',))
b = pd.DataFrame([None, None], columns=('value',))
a.to_parquet('a.parquet', object_encoding='int', engine='fastparquet')
b.to_parquet('b.parquet', object_encoding='int', engine='fastparquet')

dd.read_parquet('*.parquet').compute()

给予

   value
0    1.0
1    1.0
0    NaN
1    NaN

【讨论】:

有趣的是,该列的dtype是float64 NaN 实现为 float pandas.pydata.org/pandas-docs/stable/… 有没有使用pyarrow的解决方案?我们遇到了类似的问题并运行了repartition(繁重的过程但有效) 拼花读写最近重构,值得再次尝试

以上是关于保存 pd.DataFrame 时如何强制 parquet dtypes?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 pandas DataFrame 行保存为 JSON 字符串?

强制 pandas .iloc 返回单行数据框?

如何将 Dask.DataFrame 转换为 pd.DataFrame?

在熊猫中保存 csv 时删除索引列

将 pandas 数据框保存到 csv 时,如何保留 columns.name?

将 pandas 数据框保存到 csv 时,如何保留 columns.name?