Python 解码十进制类型的拼花地板最小/最大统计信息
我使用pyarrow创建了一个具有十进制列类型Python 解码十进制类型的拼花地板最小/最大统计信息,python,parquet,pyarrow,Python,Parquet,Pyarrow,我使用pyarrow创建了一个具有十进制列类型pa.decimal128(12,4)的拼花地板文件。读取文件并访问其元数据后,我得到以下输出: <pyarrow._parquet.ColumnChunkMetaData object at 0x7f4752644310> file_offset: 26077 file_path: physical_type: FIXED_LEN_BYTE_ARRAY num_values: 3061 path_in_schema
pa.decimal128(12,4)
的拼花地板文件。读取文件并访问其元数据后,我得到以下输出:
<pyarrow._parquet.ColumnChunkMetaData object at 0x7f4752644310>
file_offset: 26077
file_path:
physical_type: FIXED_LEN_BYTE_ARRAY
num_values: 3061
path_in_schema: Price
is_stats_set: True
statistics:
<pyarrow._parquet.Statistics object at 0x7f4752644360>
has_min_max: True
min: b'\x00\x00\x00\x00\x9b\xdc'
max: b'\x00\x00w5\x93\x9c'
null_count: 0
distinct_count: 0
num_values: 3061
physical_type: FIXED_LEN_BYTE_ARRAY
logical_type: Decimal(precision=12, scale=4)
converted_type (legacy): DECIMAL
compression: SNAPPY
encodings: ('PLAIN_DICTIONARY', 'PLAIN', 'RLE')
has_dictionary_page: True
dictionary_page_offset: 22555
data_page_offset: 23225
total_compressed_size: 3522
total_uncompressed_size: 3980
但却收到了以下错误消息
pyarrow.lib.ArrowNotImplementedError:不支持使用函数cast\u decimal将二进制转换为十进制
统计信息基于物理类型而不是逻辑类型。对于
Decimal(精度=12,刻度=4)
物理类型为FIXED\u LEN\u BYTE\u ARRAY
,即最小值和最大值。不幸的是,为了转换回十进制,您需要知道Arrow是如何编码为固定长度字节数组的
它首先根据精度确定需要多少字节。您不需要对该零件进行反向工程。然后,它转换为big-endian,截断到所需的字节并写入它们。因此,这应该允许您转换回
def pad(b):
# Left pad 0 or 1 based on leading digit (2's complement rules)
if b[-1] & 128 == 0:
return b.ljust(16, b'\x00')
else:
return b.ljust(16, b'\xff')
def to_pyarrow_bytes(b):
# converts from big-endian (parquet's repr) to little endian (arrow's repr)
# and then pads to 16 bytes
return pad(b[::-1])
def decode_stats_decimal(b):
pyarrow_bytes = to_pyarrow_bytes(b)
arr = pa.Array.from_buffers(dtype, 1, [None, pa.py_buffer(pyarrow_bytes)], 0)
return arr[0].as_py()
decode_stats_decimal(statistics.max)
# Decimal('199999.9900')
decode_stats_decimal(statistics.min)
# Decimal('3.9900')
对于小数128,您希望有16个字节,但这里只有6个字节。也许它们被截断了。在这种情况下,请尝试
int.from_bytes(b'\x00\x00\x00\x00\x00\x00\x9b\xdc',big')/1_000)
BTW,这里有一个用于将其解码为更好类型的方法。感谢您的解释。有时我可以看到解码的最小值/最大值与实际列最小值/最大值不同。在这个特定示例中,最小值为0.0,但统计结果为3.99。这似乎是错误的,我能够重现这一点。我在这里总结了错误的最小/最大值:这是编写十进制类型PARQUET-1655时已知的错误。现在应该在主分支上修复此问题,下一个版本(预计2021年4月发布的pyarrow 4.0)将包含此修复。
def pad(b):
# Left pad 0 or 1 based on leading digit (2's complement rules)
if b[-1] & 128 == 0:
return b.ljust(16, b'\x00')
else:
return b.ljust(16, b'\xff')
def to_pyarrow_bytes(b):
# converts from big-endian (parquet's repr) to little endian (arrow's repr)
# and then pads to 16 bytes
return pad(b[::-1])
def decode_stats_decimal(b):
pyarrow_bytes = to_pyarrow_bytes(b)
arr = pa.Array.from_buffers(dtype, 1, [None, pa.py_buffer(pyarrow_bytes)], 0)
return arr[0].as_py()
decode_stats_decimal(statistics.max)
# Decimal('199999.9900')
decode_stats_decimal(statistics.min)
# Decimal('3.9900')