我有一个巨大的长格式多索引数据框。只有一个“值”列。 “value”中的某些条目的类型为
pd.Timedelta
。
尝试使用
parquet
将该数据帧另存为 pd.to_parquet
文件时出现错误:
pyarrow.lib.ArrowInvalid: ("Could not convert Timedelta('2903 days 00:00:00') with type Timedelta: tried to convert to double", 'Conversion failed for column value with type object')
如果我将错误消息中的特定值转换为
numpy
,我会得到以下信息:
array([Timedelta('2903 days 00:00:00')], dtype=object)
我设置了一个玩具示例来检查是否可以将
pd.Timedelta
转换为 parquet
。下面的代码工作得很好:
import pandas as pd
idx = pd.MultiIndex.from_tuples(
[("A", "x"), ("A", "y"), ("B", "x"), ("B", "y")],
names=["idx1", "idx2"])
data = {"value": [
pd.Timedelta(days=10),
2.5,
pd.Timedelta(days=20),
5
]}
df = pd.DataFrame(data=data, index=idx)
df.to_parquet("test.parquet")
x = pd.read_parquet("test.parquet")
一个简单的
df.iloc[0, :].to_numpy()
提供与我的真实数据框中完全相同的类型:array([Timedelta('10 days 00:00:00')], dtype=object)
。
我想知道我的原始数据框与我的玩具示例相比可能有什么区别?
这部分错误
'Conversion failed for column value with type object'
表明您的列是浮点数和时间增量的混合体,正如您所期望的那样。
问题来自于这样一个事实:当你有一个大数据框时,pyarrow 会从 pandas 数据框的第一行推断出类型。最有可能在你的情况下它们都是花车。此代码(与您的示例相同但稍作修改)将重现您的错误:
import pandas as pd
float_vals = [2.5 for i in range(10000)]
float_index_val = [("float", i) for i in range(10000)]
float_vals.extend([("A", "x"), ("A", "y"), ("B", "x"), ("B", "y")])
float_vals.extend([
pd.Timedelta(days=2903),
2.5,
pd.Timedelta(days=20),
5
])
idx = pd.MultiIndex.from_tuples(
float_vals,
names=["idx1", "idx2"])
data = {"value": float_vals}
df = pd.DataFrame(data=data, index=idx)
df.to_parquet("test.parquet")
x = pd.read_parquet("test.parquet")
这里的问题是镶木地板中的一列不能有多种类型。在您的示例中,如果您加载保存的镶木地板,您将看到所有内容都已转换为 timedelta。例如
x = pd.read_parquet("test.parquet")
随后是 x.iloc[1, :].to_numpy()
提供此 array([2], dtype='timedelta64[us]')
如果浮点值不代表增量时间,您应该按照注释的建议进行操作并对数据进行逆透视。如果浮点值表示增量时间,您可以在保存之前对其进行转换,或者在保存时传递模式。
df.value = pd.to_timedelta(df.value)
df.to_parquet("test.parquet")
或
df.to_parquet("test.parquet", schema=pa.schema([("value", pa.duration("s"))]))