将一个对象列表转换为pandas dataframe

29

如何将对象列表转换为pandas数据帧?

class Person(object):
    def __init__(self):
        self.name = ""
        self.year = 0
        self.salary = 0

例如以下代码可以运行,但我想要一个人类别的列表

import pandas as pd
import numpy as np

data = {'name': ['Alice', 'Bob', 'Charles', 'David', 'Eric'],
    'year': [2017, 2017, 2017, 2017, 2017],
    'salary': [40000, 24000, 31000, 20000, 30000]}

df = pd.DataFrame(data, index = ['Acme', 'Acme', 'Bilbao', 'Bilbao', 'Bilbao'])

print(df)

像这样吗?问题不太清楚,我认为:data = {'persons': [Person() for _ in range(5)]} - Anton vBR
使用列表推导式?data = [{'name': person.name, 'year': person.year, 'salary': person.salary} for person in person_list] - ayhan
抱歉造成困惑。我有一个人对象列表,我想从中创建一个数据框,使得数据框的列是人的属性。我该怎么做? - im281
4个回答

32

这似乎是结合了ayhan的建议和你想要的东西。你可以在Person类中添加一个方法,将其转换为适合Pandas DataFrame构造函数的形式。

class Person(object):
    def __init__(self, name='', year=0, salary=0):
        self.name = name
        self.year = year
        self.salary = salary

    def as_dict(self):
        return {'name': self.name, 'year': self.year, 'salary': self.salary}

person1 = Person('john', 2017, 100)
person2 = Person('smith', 2016, 200)
person3 = Person('roger', 2016, 500)

person_list = [person1, person2, person3]

df = pd.DataFrame([x.as_dict() for x in person_list])

print(df)

    name    salary  year
0   john    100     2017
1   smith   200     2016
2   roger   500     2016

为什么列的顺序不同?应该是: - im281
1
此外,为了完整起见,您可以使用内置的Python vars函数来代替定义as_dict函数:[vars(x) for x in person_list]。 - Ido S
6
as_dict() 基本上和 dict 执行的操作相同,因此 pd.DataFrame([x.__dict__ for x in person_list]) 是另一种选项(在我尝试的 Python 版本中)。 - stijn
@im281 列的顺序与字典构建的顺序无关。字典是一种哈希结构,因此其顺序由其哈希函数实现内部确定。人们不应该期望在表面上看到任何形式的顺序。 - axolotl
1
使用vars(x)代替x.__dict__更符合Pythonic风格,正如这里所指出的那样。 - Anthony Townsend
显示剩余2条评论

5

您可以使用vars从任何列表创建pandas数据框。

import pandas as pd

df = pd.DataFrame([vars(d) for d in data])

这个方法是可行的,因为 vars 返回了列表中所有对象的所有属性。祝使用愉快!


2
首先,您应该修改您的__init__(),因为您的版本只会将任何Person对象的每个属性设置为默认值,并且不允许用户设置它们。
然后,您可以使用zip()函数来创建data字典中值的三元组,然后使用这些三元组来创建Person实例。
import pandas as pd

class Person:
    def __init__(self, name='', year=0, salary=0):
         self.name = name
         self.year = year
         self.salary = salary

data = {'name': ['Alice', 'Bob', 'Charles', 'David', 'Eric'],
        'year': [2017, 2017, 2017, 2017, 2017],
        'salary': [40000, 24000, 31000, 20000, 30000]}

foo = [Person(name, year, salary) for name, year, salary in zip(data['name'], data['year'], data['salary'])]
df = pd.DataFrame(foo, index=['Acme']*2 + ['Bilbao']*3, columns=['Person'])

first_person = df['Person'].iloc[0]
print(first_person.name, first_person.year, first_person.salary)

输出:

Alice 2017 40000

2

这个怎么样?

这将获取所有(第一级)属性并将它们制成一个字典,可以直接加载到 Pandas DataFrame 中,这就是我认为 OP 所寻找的,这避免了更改类的必要。

not attr.starswith("_") 是为了避免将私有属性加载到 Pandas DataFrame 中。

import pandas as pd
class Person(object):
    def __init__(self, name='', year=0, salary=0):
        self.name = name
        self.year = year
        self.salary = salary

person1 = Person('john', 2017, 100)
person2 = Person('smith', 2016, 200)
person3 = Person('roger', 2016, 500)

person_list = [person1, person2, person3]

data = [{attr: getattr(p,attr) for attr in dir(p) if not attr.startswith('_')} for p in person_list ]
df = pd.DataFrame(data)
print(df)

    name  salary  year
0   john     100  2017
1  smith     200  2016
2  roger     500  2016

你应该向你的解决方案中添加更多信息。 - Frank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接