使用Pandas合并具有共同元素的两个字典列表

3
所以我有两个字典列表...
list_yearly = [
{'name':'john',
 'total_year': 107
},
{'name':'cathy',
 'total_year':124
},
]

list_monthly =  [
{'name':'john',
 'month':'Jan',
 'total_month': 34
},
{'name':'cathy',
 'month':'Jan',
 'total_month':78
},
{'name':'john',
 'month':'Feb',
 'total_month': 73
},
{'name':'cathy',
 'month':'Feb',
 'total_month':46
},
]

目标是得到一个最终数据集,其外观如下:
{'name':'john',
 'total_year': 107,
 'trend':[{'month':'Jan', 'total_month': 34},{'month':'Feb', 'total_month': 73}]
 },

 {'name':'cathy',
  'total_year':124,
  'trend':[{'month':'Jan', 'total_month': 78},{'month':'Feb', 'total_month': 46}]
  },

由于我的数据集涉及特定年份所有12个月的大量学生,因此我使用Pandas进行数据整理。具体步骤如下:
首先,使用“name”关键字将两个列表合并成一个数据框。
In [5]: df = pd.DataFrame(list_yearly).merge(pd.DataFrame(list_monthly))

In [6]: df
Out[6]:
     name    total_year month  total_month
0   john         107     Jan           34
1   john         107     Feb           73
2  cathy         124     Jan           78
3  cathy         124     Feb           46

然后创建一个字典作为趋势列。
ln [7]: df['trend'] = df.apply(lambda x: [x[['month', 'total_month']].to_dict()], axis=1)

In [8]: df
Out[8]:
    name    total_year month  total_month  \
0   john         107   Jan           34
1   john         107   Feb           73
2  cathy         124   Jan           78
3  cathy         124   Feb           46

                                  trend
0  [{u'total_month': 34, u'month': u'Jan'}]
1  [{u'total_month': 73, u'month': u'Feb'}]
2  [{u'total_month': 78, u'month': u'Jan'}]
3  [{u'total_month': 46, u'month': u'Feb'}]

并且,使用选定列的 to_dict(orient='records') 方法将其转换回字典列表:
In [9]: df[['name', 'total_year', 'trend']].to_dict(orient='records')
Out[9]:
[{'name': 'john',
  'total_year': 107,
  'trend': [{'month': 'Jan', 'total_month': 34}]},
 {'name': 'john',
  'total_year': 107,
  'trend': [{'month': 'Feb', 'total_month': 73}]},
 {'name': 'cathy',
  'total_year': 124,
  'trend': [{'month': 'Jan', 'total_month': 78}]},
 {'name': 'cathy',
  'total_year': 124,
  'trend': [{'month': 'Feb', 'total_month': 46}]}]

很明显,最终的数据集并不是我想要的。我得到的不是包含两个月份的2个字典,而是4个分别包含所有月份的字典。我该怎么解决?我更希望在Pandas内部解决这个问题,而不是再次将最终输出减少到所需状态。
2个回答

1
你应该使用 groupby 来基于 nametotal_year 进行分组,而不是使用 apply(作为第二步),在 groupby 中可以创建所需的列表。例如 -
df = pd.DataFrame(list_yearly).merge(pd.DataFrame(list_monthly))

def func(group):
    result = []
    for idx, row in group.iterrows():
        result.append({'month':row['month'],'total_month':row['total_month']})
    return result

result = df.groupby(['name','total_year']).apply(func).reset_index()
result.columns = ['name','total_year','trend']
result_dict = result.to_dict(orient='records')

演示 -

In [9]: df = pd.DataFrame(list_yearly).merge(pd.DataFrame(list_monthly))

In [10]: df
Out[10]:
    name  total_year month  total_month
0   john         107   Jan           34
1   john         107   Feb           73
2  cathy         124   Jan           78
3  cathy         124   Feb           46

In [13]: def func(group):
   ....:     result = []
   ....:     for idx, row in group.iterrows():
   ....:         result.append({'month':row['month'],'total_month':row['total_month']})
   ....:     return result
   ....:

In [14]:

In [14]: result = df.groupby(['name','total_year']).apply(func).reset_index()

In [15]: result
Out[15]:
    name  total_year                                                  0
0  cathy         124  [{'month': 'Jan', 'total_month': 78}, {'month'...
1   john         107  [{'month': 'Jan', 'total_month': 34}, {'month'...

In [19]: result.columns = ['name','total_year','trend']

In [20]: result
Out[20]:
    name  total_year                                              trend
0  cathy         124  [{'month': 'Jan', 'total_month': 78}, {'month'...
1   john         107  [{'month': 'Jan', 'total_month': 34}, {'month'...

In [21]: result.to_dict(orient='records')
Out[21]:
[{'name': 'cathy',
  'total_year': 124,
  'trend': [{'month': 'Jan', 'total_month': 78},
   {'month': 'Feb', 'total_month': 46}]},
 {'name': 'john',
  'total_year': 107,
  'trend': [{'month': 'Jan', 'total_month': 34},
   {'month': 'Feb', 'total_month': 73}]}]

1
在 pandas 中,尝试使用以下代码:
df1 = pd.DataFrame(list_yearly)
df2 = pd.DataFrame(list_monthly)

df = df1.set_index('name').join(pd.DataFrame(df2.groupby('name').apply(\
     lambda gp: gp.transpose().to_dict().values())))

更新:将字典中的名称移除并转换为字典列表:
df1 = pd.DataFrame(list_yearly)
df2 = pd.DataFrame(list_monthly)

keep_columns = [c for c in df2.columns if not c == 'name']
# within pandas
df = df1.set_index('name').join(pd.DataFrame(df2.groupby('name').apply(\
    lambda gp: gp[keep_columns].transpose().to_dict().values()))) \
    .reset_index()

data = [row.to_dict() for _, row in df.iterrows()]

需要将“0”重命名为“趋势(trend)”。


结果输出是一个数据框。我需要使用相同的字典值将其转换回我想要的状态吗? - Amistad
同时,名称字段在趋势子字典中再次出现..需要将其删除。 - Amistad
我已经进行了编辑。您将得到“趋势”错误的名称;我不知道在lambda内部重命名列的干净方法,但是您可以轻松地将lambda移动到单独的函数中,并在那里重命名分组结果的系列。 - hilberts_drinking_problem

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