Pandas:压扁DataFrame中的dict值



我现在经常遇到这个问题:我有一个嵌套的dict(通常来自API/JSON负载(,需要将其展开以用作表格数据。

示例:

invoices = [
{
'id': 1,
'currency': 'GBP',
'lines': [
{'line_id': 1, 'product': 'pencils', 'quantity': 100, 'price': 20},
{'line_id': 2, 'product': 'erasers', 'quantity': 50, 'price': 10}
]
},
{
'id': 2,
'currency': 'USD',
'lines': [
{'line_id': 1, 'product': 'TV', 'quantity': 2, 'price': 800}
]
}
]

pd.DataFrame(invoices)给了我一个有两行的DataFrame,即每张发票一行。我可以将其扩展为每行DataFrame作为pd.DataFrame(invoices).explode('lines'),但在lines列中有dict。如何将这些dict关键帧拆分/分解为DataFrame列?

对我之前的回答进行了改进。这个保留了识别列:

df = pd.DataFrame(invoices).explode('lines')
df.apply(lambda x: x[['id','currency']].append(pd.Series(x['lines'])), axis=1)

提供:

id currency  line_id  product  quantity  price
0   1      GBP        1  pencils       100     20
0   1      GBP        2  erasers        50     10
1   2      USD        1       TV         2    800

事实证明,最新版本的panda允许自定义访问者,您可以使用它来实现这一点:

# create per-line dataframe, as in the question
df = pd.DataFrame(invoices).explode('lines')
pd.concat([
df.drop(columns=['lines']),  # remove nested column
df['lines'].dict.explode()   # add flattened columns
], axis=1)

为了能够做到这一点,您首先需要定义.dict访问器:

@pd.api.extensions.register_series_accessor('dict')
class DictAccessor:
def __init__(self, pandas_obj):
self._obj = pandas_obj

def __getitem__(self, key):
return self._obj.apply(curried.get(key))

def explode(self):
return self._obj.apply(pd.Series)

此访问器还允许您访问dict中的各个密钥,例如:

df = pd.DataFrame(invoices).explode('lines')
# total quantity across all invoices
df['lines'].dict['quantity'].sum()
# total cost per invoice
df.groupby('id').apply(lambda group: group['lines'].dict['price'].sum())

最新更新