Pandas字典的向量化查找

5
这似乎应该是一个常见的用例,但我没有找到任何好的指导。我有一个可行的解决方案,但我更愿意使用向量化查找而不是使用Pandas的apply()函数。
以下是我的示例:
import pandas as pd


example_dict = {
        "category1":{
                "field1": 0.0,
                "filed2": 5.0},
        "category2":{
                "field1": 5.0,
                "field2": 8.0}}

d = {"ids": range(10),
     "category": ["category1" if x % 2 == 0 else "category2" for x in range(10)]}

df = pd.DataFrame(d)
# The operation I am trying to vectorize
df['category_data'] = df.apply(lambda row: example_dict[row['category']], axis=1)

在最后一行,你可以看到我使用了apply()函数来执行字典查找。我的直觉告诉我应该有一种向量化的方法。我可能错了,但我也想知道。我经常遇到需要在字典中查找信息并将其添加为DataFrame列的情况。


2
请注意,为了获得最佳的 Pandas 性能,通常情况下您应避免在 DataFrame 中存储 Python 字典。只使用本机(NumPy)数据类型,如 int64、float64 或字符串。因此,您可能最好使用 field1field2 列,而不是一个 category_data 列,每个列都存储浮点数。如果您需要根据字典中的值选择行,则这可能会带来显着的性能优势。 - unutbu
2个回答

9
通过使用map函数
df['map']=df.category.map(example_dict)
df
Out[839]: 
    category  ids                   category_data  \
0  category1    0  {'field1': 0.0, 'filed2': 5.0}   
1  category2    1  {'field1': 5.0, 'field2': 8.0}   
2  category1    2  {'field1': 0.0, 'filed2': 5.0}   
3  category2    3  {'field1': 5.0, 'field2': 8.0}   
4  category1    4  {'field1': 0.0, 'filed2': 5.0}   
5  category2    5  {'field1': 5.0, 'field2': 8.0}   
6  category1    6  {'field1': 0.0, 'filed2': 5.0}   
7  category2    7  {'field1': 5.0, 'field2': 8.0}   
8  category1    8  {'field1': 0.0, 'filed2': 5.0}   
9  category2    9  {'field1': 5.0, 'field2': 8.0}   
                              map  
0  {'field1': 0.0, 'filed2': 5.0}  
1  {'field1': 5.0, 'field2': 8.0}  
2  {'field1': 0.0, 'filed2': 5.0}  
3  {'field1': 5.0, 'field2': 8.0}  
4  {'field1': 0.0, 'filed2': 5.0}  
5  {'field1': 5.0, 'field2': 8.0}  
6  {'field1': 0.0, 'filed2': 5.0}  
7  {'field1': 5.0, 'field2': 8.0}  
8  {'field1': 0.0, 'filed2': 5.0}  
9  {'field1': 5.0, 'field2': 8.0}  

如果你需要把它们放到不同的列中
pd.DataFrame(df['map'].tolist())
Out[843]: 
   field1  field2  filed2
0     0.0     NaN     5.0
1     5.0     8.0     NaN
2     0.0     NaN     5.0
3     5.0     8.0     NaN
4     0.0     NaN     5.0
5     5.0     8.0     NaN
6     0.0     NaN     5.0
7     5.0     8.0     NaN
8     0.0     NaN     5.0
9     5.0     8.0     NaN

或者
df['map'].apply(pd.Series)
Out[844]: 
   field1  field2  filed2
0     0.0     NaN     5.0
1     5.0     8.0     NaN
2     0.0     NaN     5.0
3     5.0     8.0     NaN
4     0.0     NaN     5.0
5     5.0     8.0     NaN
6     0.0     NaN     5.0
7     5.0     8.0     NaN
8     0.0     NaN     5.0
9     5.0     8.0     NaN

我建议不要使用点符号系列索引。因为如果你把列命名为“map”,就会出现问题。 - Sebastian
有没有一种方法可以获得以下代码的行为?df.apply(lambda row: example_dict.get(row['category'], pd.np.NaN), axis=1) - Sebastian
嗯...你确定这是向量化的吗?我已经尝试了map、lambda和df['id'].apply(function),所有方法似乎都有类似的时间,由jupyter笔记本中的魔法命令测量。 - haneulkim

3

您可以从example_dict创建第二个DataFrame,然后合并这两个数据框。

d2 = pd.DataFrame(example_dict.keys(),columns=
             ['category']).assign(category_data=example_dict.values())

df.merge(d2,on='category',how='left')

    category  ids                     category_data
0  category1    0  {u'filed2': 5.0, u'field1': 0.0}
1  category2    1  {u'field2': 8.0, u'field1': 5.0}
2  category1    2  {u'filed2': 5.0, u'field1': 0.0}
3  category2    3  {u'field2': 8.0, u'field1': 5.0}
4  category1    4  {u'filed2': 5.0, u'field1': 0.0}
5  category2    5  {u'field2': 8.0, u'field1': 5.0}
6  category1    6  {u'filed2': 5.0, u'field1': 0.0}
7  category2    7  {u'field2': 8.0, u'field1': 5.0}
8  category1    8  {u'filed2': 5.0, u'field1': 0.0}
9  category2    9  {u'field2': 8.0, u'field1': 5.0}

将字典值分离到不同的列中

d2 = pd.DataFrame(example_dict).T
df.merge(d2,how='left',left_on='category',right_index=True)

    category  ids  field1  field2  filed2
0  category1    0     0.0     NaN     5.0
1  category2    1     5.0     8.0     NaN
2  category1    2     0.0     NaN     5.0
3  category2    3     5.0     8.0     NaN
4  category1    4     0.0     NaN     5.0
5  category2    5     5.0     8.0     NaN
6  category1    6     0.0     NaN     5.0
7  category2    7     5.0     8.0     NaN
8  category1    8     0.0     NaN     5.0
9  category2    9     5.0     8.0     NaN

我喜欢这个想法,是否可以像@Wen提供的答案那样将数据展平为单独的列?我看到Pandas有用于JSON的规范化功能,但我没有看到任何用于字典的功能。 - Matthew Crews
@MatthewCrews,在数据框构造函数中创建这个甚至更简单,我已经更新了代码以实现此功能。 - DJK

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