pandas 搞乱多级索引 parquet 浮动精度
pandas mess up multi level index parquet float accuracy
我有一些数据具有多级索引和列。我的目标是将数据存储为 float32 而不是 double/float64 到镶木地板文件中,以节省磁盘 space。我不关心单元格值的准确性,但我确实希望索引和列本身(此处为 number
级别)保持为 float64 并保持准确。
然而,在下面的例子中,它把 7080.39
弄乱了,变成了 7080.39013671875
。我知道它可能是怎么发生的,但想不出解决它的方法。
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
df = pd.DataFrame({"col1": [1.0, 2.0, 3.0], "col2": [2.3, 2.4, 2.5], "col3": [3.1, 3.2, 3.3]})
df.index = pd.MultiIndex.from_tuples([('a', '2021-01-01', 100), ('a', '2021-01-01', 200), ('a', '2021-01-01', 7080.39)], names=('name', 'date', 'number'))
df.columns = pd.MultiIndex.from_tuples([('a', '2021-01-01', 100), ('a', '2021-01-01', 200), ('a', '2021-01-01', 7080.39)], names=('name', 'date', 'number'))
# write to parquet as float64/double
table = pa.Table.from_pandas(df)
pq.write_table(table, 'double.parquet')
# cast to float32 and write to parquet
schema = pa.schema([pa.field(field.name, pa.float32() if field.type == pa.float64() else field.type) for field in table.schema], metadata=table.schema.metadata)
table = table.cast(schema)
pq.write_table(table, 'float.parquet')
# now I read the data in, but as you can see, the "number" level in df2 index & column is messed up. I didn't change the type of it, but 7080.39 becomes 7080.39013671875, which is the float32 representation of 7080.39
df1 = pd.read_parquet('double.parquet')
df2 = pd.read_parquet('float.parquet')
df1.index
#MultiIndex([('a', '2021-01-01', 100.0),
# ('a', '2021-01-01', 200.0),
# ('a', '2021-01-01', 7080.39)],
# names=['name', 'date', 'number'])
df2.index
#MultiIndex([('a', '2021-01-01', 100.0),
# ('a', '2021-01-01', 200.0),
# ('a', '2021-01-01', 7080.39013671875)],
# names=['name', 'date', 'number'])
这真的很烦人,因为我需要将这个 DataFrame 与许多其他复杂的东西连接起来,而这个 7080.39013671875 找不到匹配项。
关于如何修复它有什么建议吗? (不是如何将 7080.39013671875
转换回 7080.39
而是如何首先防止这种情况发生,因为我不想改变我的索引类型)
如果你这样做 print(table.schema)
你可以看到它来自:
('a', '2021-01-01', '100.0'): double
('a', '2021-01-01', '200.0'): double
('a', '2021-01-01', '7080.39'): double
name: string
date: string
number: double
至(投后):
('a', '2021-01-01', '100.0'): float
('a', '2021-01-01', '200.0'): float
('a', '2021-01-01', '7080.39'): float
name: string
date: string
number: float
您只需确保索引列未从 double/float64 转换为 float/float32。这里有一个 hacky 的方法来做到这一点:
schema = pa.schema([pa.field(field.name, pa.float32() if field.type == pa.float64() and '(' not in field.name else field.type) for field in table.schema], metadata=table.schema.metadata)
table = table.cast(schema)
这给你:
('a', '2021-01-01', '100.0'): double
('a', '2021-01-01', '200.0'): double
('a', '2021-01-01', '7080.39'): double
name: string
date: string
number: float
我有一些数据具有多级索引和列。我的目标是将数据存储为 float32 而不是 double/float64 到镶木地板文件中,以节省磁盘 space。我不关心单元格值的准确性,但我确实希望索引和列本身(此处为 number
级别)保持为 float64 并保持准确。
然而,在下面的例子中,它把 7080.39
弄乱了,变成了 7080.39013671875
。我知道它可能是怎么发生的,但想不出解决它的方法。
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
df = pd.DataFrame({"col1": [1.0, 2.0, 3.0], "col2": [2.3, 2.4, 2.5], "col3": [3.1, 3.2, 3.3]})
df.index = pd.MultiIndex.from_tuples([('a', '2021-01-01', 100), ('a', '2021-01-01', 200), ('a', '2021-01-01', 7080.39)], names=('name', 'date', 'number'))
df.columns = pd.MultiIndex.from_tuples([('a', '2021-01-01', 100), ('a', '2021-01-01', 200), ('a', '2021-01-01', 7080.39)], names=('name', 'date', 'number'))
# write to parquet as float64/double
table = pa.Table.from_pandas(df)
pq.write_table(table, 'double.parquet')
# cast to float32 and write to parquet
schema = pa.schema([pa.field(field.name, pa.float32() if field.type == pa.float64() else field.type) for field in table.schema], metadata=table.schema.metadata)
table = table.cast(schema)
pq.write_table(table, 'float.parquet')
# now I read the data in, but as you can see, the "number" level in df2 index & column is messed up. I didn't change the type of it, but 7080.39 becomes 7080.39013671875, which is the float32 representation of 7080.39
df1 = pd.read_parquet('double.parquet')
df2 = pd.read_parquet('float.parquet')
df1.index
#MultiIndex([('a', '2021-01-01', 100.0),
# ('a', '2021-01-01', 200.0),
# ('a', '2021-01-01', 7080.39)],
# names=['name', 'date', 'number'])
df2.index
#MultiIndex([('a', '2021-01-01', 100.0),
# ('a', '2021-01-01', 200.0),
# ('a', '2021-01-01', 7080.39013671875)],
# names=['name', 'date', 'number'])
这真的很烦人,因为我需要将这个 DataFrame 与许多其他复杂的东西连接起来,而这个 7080.39013671875 找不到匹配项。
关于如何修复它有什么建议吗? (不是如何将 7080.39013671875
转换回 7080.39
而是如何首先防止这种情况发生,因为我不想改变我的索引类型)
如果你这样做 print(table.schema)
你可以看到它来自:
('a', '2021-01-01', '100.0'): double
('a', '2021-01-01', '200.0'): double
('a', '2021-01-01', '7080.39'): double
name: string
date: string
number: double
至(投后):
('a', '2021-01-01', '100.0'): float
('a', '2021-01-01', '200.0'): float
('a', '2021-01-01', '7080.39'): float
name: string
date: string
number: float
您只需确保索引列未从 double/float64 转换为 float/float32。这里有一个 hacky 的方法来做到这一点:
schema = pa.schema([pa.field(field.name, pa.float32() if field.type == pa.float64() and '(' not in field.name else field.type) for field in table.schema], metadata=table.schema.metadata)
table = table.cast(schema)
这给你:
('a', '2021-01-01', '100.0'): double
('a', '2021-01-01', '200.0'): double
('a', '2021-01-01', '7080.39'): double
name: string
date: string
number: float