pyarrow.lib.ArrowInvalid: ('无法将 X 转换为 Y 类型:在推断 Arrow 数据类型时无法识别 Python 值类型')

新手上路,请多包涵

使用 pyarrow 转换一个 pandas.DataFrame 包含 - - 包含 Player pyarrow.Table

 import pandas as pd
import pyarrow as pa

class Player:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def __repr__(self):
        return f'<{self.name} ({self.age})>'

data = [
    Player('Jack', 21, 'm'),
    Player('Ryan', 18, 'm'),
    Player('Jane', 35, 'f'),
]
df = pd.DataFrame(data, columns=['player'])
print(pa.Table.from_pandas(df))

我们得到错误:

 pyarrow.lib.ArrowInvalid: ('Could not convert <Jack (21)> with type Player: did not recognize Python value type when inferring an Arrow data type', 'Conversion failed for column 0 with type object')

使用遇到同样的错误

df.to_parquet('players.pq')

pyarrow 是否有可能回退到使用 pickle 序列化这些 Python 对象?或者有更好的解决方案吗? pyarrow.Table 最终将使用 Parquet.write_table() 写入磁盘。

  • 使用 Python 3.8.0、熊猫 0.25.3、pyarrow 0.13.0。
  • pandas.DataFrame.to_parquet() 不支持多索引,因此首选使用 pq.write_table(pa.Table.from_dataframe(pandas.DataFrame)) 的解决方案。

谢谢!

原文由 Nyxynyx 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.7k
1 个回答

我的建议是将数据插入到已经序列化的 DataFrame 中。

最佳选择 - 使用数据类(python >=3.7)

通过装饰器将 Player 类定义为数据类,并让序列化为您本地完成(到 JSON)。

 import pandas as pd
from dataclasses import dataclass

@dataclass
class PlayerV2:
    name:str
    age:int
    gender:str

    def __repr__(self):
        return f'<{self.name} ({self.age})>'

dataV2 = [
    PlayerV2(name='Jack', age=21, gender='m'),
    PlayerV2(name='Ryan', age=18, gender='m'),
    PlayerV2(name='Jane', age=35, gender='f'),
]

# The serialization is done natively to JSON
df_v2 = pd.DataFrame(data, columns=['player'])
print(df_v2)

# Can still get the objects's attributes by deserializeing the record
json.loads(df_v2["player"][0])['name']

手动序列化对象(python < 3.7)

在 Player 类中定义一个序列化函数,并在创建 Dataframe 之前序列化每个实例。

 import pandas as pd
import json

class Player:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def __repr__(self):
        return f'<{self.name} ({self.age})>'

    # The serialization function for JSON, if for some reason you really need pickle you can use it instead
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__)

# Serialize the objects before inserting it into the DataFrame
data = [
    Player('Jack', 21, 'm').toJSON(),
    Player('Ryan', 18, 'm').toJSON(),
    Player('Jane', 35, 'f').toJSON(),
]
df = pd.DataFrame(data, columns=['player'])

# You can see all the data inserted as a serialized json into the column player
print(df)

# Can still get the objects's attributes by deserializeing the record
json.loads(df["player"][0])['name']

原文由 Nimrod Carmel 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题