python - 我可以存储一个 Parquet 文件,其字典列的值中包含混合类型吗?
问题描述
我正在尝试将 Python Pandas DataFrame 存储为 Parquet 文件,但我遇到了一些问题。我的 Pandas DF 的一列包含以下字典:
import pandas as pandas
df = pd.DataFrame({
"ColA": [1, 2, 3],
"ColB": ["X", "Y", "Z"],
"ColC": [
{ "Field": "Value" },
{ "Field": "Value2" },
{ "Field": "Value3" }
]
})
df.to_parquet("test.parquet")
现在,这工作得很好,问题是字典的嵌套值之一与其他值的类型不同。例如:
import pandas as pandas
df = pd.DataFrame({
"ColA": [1, 2, 3],
"ColB": ["X", "Y", "Z"],
"ColC": [
{ "Field": "Value" },
{ "Field": "Value2" },
{ "Field": ["Value3"] }
]
})
df.to_parquet("test.parquet")
这会引发以下错误:
ArrowInvalid: ('cannot mix list and non-list, non-null values', 'Conversion failed for column ColC with type object')
请注意,对于 DF 的最后一行,字典的Field
属性ColC
是一个列表而不是一个字符串。
是否有任何解决方法可以将此 DF 存储为 Parquet 文件?
解决方案
ColC
是一种 UDT(用户定义类型),具有一个名为Field
type 的字段Union of String, List of String
。
理论上箭头支持它,但在实践中很难弄清楚它的类型ColC
是什么。即使您明确提供数据框的架构,它也不起作用,因为尚不支持这种类型的转换(将联合从熊猫转换为箭头/镶木地板)。
union_type = pa.union(
[pa.field("0",pa.string()), pa.field("1", pa.list_(pa.string()))],
'dense'
)
col_c_type = pa.struct(
[
pa.field('Field', union_type)
]
)
schema=pa.schema(
[
pa.field('ColA', pa.int32()),
pa.field('ColB', pa.string()),
pa.field('ColC', col_c_type),
]
)
df = pd.DataFrame({
"ColA": [1, 2, 3],
"ColB": ["X", "Y", "Z"],
"ColC": [
{ "Field": "Value" },
{ "Field": "Value2" },
{ "Field": ["Value3"] }
]
})
pa.Table.from_pandas(df, schema)
这会给你这个错误:
('Sequence converter for type union[dense]<0: string=0, 1: list<item: string>=1> not implemented', 'Conversion failed for column ColC with type object'
即使您手动创建箭头表,它也无法将其转换为镶木地板(同样,不支持联合)。
import io
import pyarrow.parquet as pq
col_a = pa.array([1, 2, 3], pa.int32())
col_b = pa.array(["X", "Y", "Z"], pa.string())
xs = pa.array(["Value", "Value2", None], type=pa.string())
ys = pa.array([None, None, ["value3"]], type=pa.list_(pa.string()))
types = pa.array([0, 0, 1], type=pa.int8())
col_c = pa.UnionArray.from_sparse(types, [xs, ys])
table = pa.Table.from_arrays(
[col_a, col_b, col_c],
schema=pa.schema([
pa.field('ColA', col_a.type),
pa.field('ColB', col_b.type),
pa.field('ColC', col_c.type),
])
)
with io.BytesIO() as buffer:
pq.write_table(table, buffer)
Unhandled type for Arrow to Parquet schema conversion: sparse_union<0: string=0, 1: list<item: string>=1>
我认为你现在唯一的选择是使用一个结构,其中字段的字符串值和字符串值列表具有不同的名称。
df = pd.DataFrame({
"ColA": [1, 2, 3],
"ColB": ["X", "Y", "Z"],
"ColC": [
{ "Field1": "Value" },
{ "Field1": "Value2" },
{ "Field2": ["Value3"] }
]
})
df.to_parquet('/tmp/hello')
推荐阅读
- powershell - 搜索 ADAccount 未返回 EmployeeID/EmployeeNumber
- javascript - 如何让我的服务器获取 js 文件而不是再次获取 html?
- mysql - 从单个数据源并行运行代码
- javascript - 如何从内部函数中获取值
- powershell - 使用 PowerShell 总结平均信息
- jsf - ckeditor tabSpaces在项目符号列表java中不起作用
- pyspark - 如何为同一回答多次取值,并且需要为每个值创建一列
- angular - ngb-datepicker 在角度材料输入(matInput)中不起作用
- sql - 是否有与 oracle add_months() 等效的 XQuery
- jupyter-notebook - 无法以 root 身份启动笔记本