Pandas - 写实木复合地板并将列保持为十进制

Posted

技术标签:

【中文标题】Pandas - 写实木复合地板并将列保持为十进制【英文标题】:Pandas - Write parquet and keep column as Decimal 【发布时间】:2019-06-27 02:01:56 【问题描述】:

我正在尝试将 parquet 文件写入 s3 以运行 Copy into Redshift/Parquet 文件正在正确写入,但尝试复制时出现错误:Column type: DECIMAL(10,2), Parquet schema: optional doubl

错误消息很清楚,但我不确定如何强制将列设为Decimal 类型。

有可能吗?写 parquet 时保持列 value 为十进制?

from datetime import datetime
import pandas as pd
import decimal as D
import numpy as np

data = [
    
        "name": "ted",
        "timestamp": datetime.now().isoformat(),
        "actual_data": "2019-06-28 00:00:00",
        "age": 34,
        "value": 0.10
    ,
    
        "name": "barney",
        "timestamp": datetime.now().isoformat(),
        "actual_data": "2019-06-28 10:00:00",
        "age": 35,        
    
]


df = pd.DataFrame.from_dict(data,)
df['age'] = df['age'].astype(int)
df['value'] = df['value'].fillna(0)
df['value'] = df['value'].astype(np.float, 2)

# df_merged["id"] = df_merged["id"].astype(int)

print(df)

df.to_parquet(f"s3://awesome-parquet-test/data.parquet", index=False)

【问题讨论】:

【参考方案1】:

要将列作为十进制值写入 Parquet,它们需要以十进制开头。

您的数据框中的值(此处为示例简化了一点)是浮点数,因此它们被写为浮点数:

>>> df = pd.DataFrame('value': [0.1, 0.0])
>>> df
   value
0    0.1
1    0.0
>>> df['value'].dtype
dtype('float64')
>>> df.to_parquet("test_data.parquet", index=False)
>>> pq.read_metadata("test_data.parquet").schema
<pyarrow._parquet.ParquetSchema object at 0x7f07248334a8>
value: DOUBLE

但是当我们第一次在 Python 中将浮点数转换为小数时,我们实际上可以将小数写入 Parquet:

>>> import decimal
>>> df['value_decimal'] = df['value'].astype(str).map(decimal.Decimal)
>>> df['value_decimal'].values
array([Decimal('0.1'), Decimal('0.0')], dtype=object)

>>> df.to_parquet("test_data.parquet", index=False)
>>> pq.read_metadata("test_data.parquet").schema
<pyarrow._parquet.ParquetSchema object at 0x7f073ae52898>
value: DOUBLE
value_decimal: FIXED_LEN_BYTE_ARRAY DECIMAL

对于Python中的小数转换:我首先转换成字符串的原因是因为否则小数会使用浮点的全精度(导致超过10个小数)

【讨论】:

df['value_decimal'] = df['value'].astype(str).map(decimal.Decimal) 行中如何指定像 Decimal(18) 这样的精度。谢谢! getcontext().prec = &lt;precision&gt; df['value_decimal'] = df['value'].astype(str).map(decimal.Decimal) 谢谢!我用它来解决其他问题:***.com/questions/61421702/… 我不喜欢字符串步骤,所以我选择了df['value_decimal'] = df['value'].map(decimal.Decimal).map(lambda x: round(x,2)) 这也解决了指定精度问题。

以上是关于Pandas - 写实木复合地板并将列保持为十进制的主要内容,如果未能解决你的问题,请参考以下文章

pandas把dataframe的数据列转化为索引列实战:单列转化为索引多列转化为复合索引

Pandas转置重置十进制舍入

pandas读取csv数据参数指定作为行索引的数据列索引列表形成复合(多层)行索引使用set_index函数把数据列转化为行索引(keys参数指定需要被转化的数据列)

pandas读取csv数据参数指定作为行索引的数据列索引列表形成复合(多层)行索引使用set_index函数把数据列转化为行索引(keys参数指定需要被转化的数据列)

Pandas中xs()函数索引复合索引数据的不同切面数据(索引复合索引中需要的数据):索引列复合索引中的一个切面索引行复合索引中的一个切面

pandas读取csv数据header参数指定作为列索引的行索引列表形成复合(多层)列索引使用reset_index函数把行索引重置为列数据(level参数设置将原行索引中的指定层转化为列数据)