Python 从组合两个多索引dfs和列索引的元组列表构建dict

Python 从组合两个多索引dfs和列索引的元组列表构建dict,python,list,pandas,dictionary,tuples,Python,List,Pandas,Dictionary,Tuples,我有两个多索引数据帧:mean和std arrays = [['A', 'A', 'B', 'B'], ['Z', 'Y', 'X', 'W']] mean=pd.DataFrame(data={0.0:[np.nan,2.0,3.0,4.0], 60.0: [5.0,np.nan,7.0,8.0], 120.0:[9.0,10.0,np.nan,12.0]}, index=pd.MultiIndex.from_arrays(arrays, names=('id', 'co

我有两个多索引数据帧:mean和std

arrays = [['A', 'A', 'B', 'B'], ['Z', 'Y', 'X', 'W']]

mean=pd.DataFrame(data={0.0:[np.nan,2.0,3.0,4.0], 60.0: [5.0,np.nan,7.0,8.0], 120.0:[9.0,10.0,np.nan,12.0]}, 
         index=pd.MultiIndex.from_arrays(arrays, names=('id', 'comp')))
mean.columns.name='Times'

std=pd.DataFrame(data={0.0:[10.0,10.0,10.0,10.0], 60.0: [10.0,10.0,10.0,10.0], 120.0:[10.0,10.0,10.0,10.0]}, 
         index=pd.MultiIndex.from_arrays(arrays, names=('id', 'comp')))
std.columns.name='Times'
我的任务是将它们组合在一个字典中,第一级为“{id:”,第二级为“{comp:”,然后每个comp都有一个元组列表,它组合了(时间点,平均值,std)。因此,结果应该是这样的

{'A': {
     'Z': [(60.0,5.0,10.0),
            (120.0,9.0,10.0)],
      'Y': [(0.0,2.0,10.0),
            (120.0,10.0,10.0)]
       },
  'B': {
     'X': [(0.0,3.0,10.0),
            (60.0,7.0,10.0)],
      'W': [(0.0,4.0,10.0),
            (60.0,8.0,10.0),
            (120.0,12.0,10.0)]
       }
 }
此外,当数据中存在NaN时,三元组被省略,因此在时间0处的值A、Z、在时间60处的值A、Y、在时间120处的值X

我如何到达那里?我已经为一行构建了一个元组列表的dict of dict:

iter=0
{mean.index[iter][0]:{mean.index[iter][1]:list(zip(mean.columns, mean.iloc[iter], std.iloc[iter]))}}
>{'A': {'Z': [(0.0, 1.0, 10.0), (60.0, 5.0, 10.0), (120.0, 9.0, 10.0)]}}
现在,我需要扩展到一个字典,在每行{internal dict}上都有一个循环,并在每行{outer dict}上添加ID。我从iterrows和dic理解开始,但在这里我遇到了问题,我从iterrows()中获得了iter('a','Z')索引,并以迭代方式构建整个dict

{mean.index[iter[1]]:list(zip(mean.columns, mean.loc[iter[1]], std.loc[iter[1]])) for (iter,row) in mean.iterrows()}
创建错误,我将只拥有内部循环

KeyError:'标签[Z]不在[索引]中'

谢谢


EDIT:在本例中,我将数字交换为float,因为在此之前生成的整数与我的实际数据不一致,并且在json转储后会失败。

下面是一个使用
defaultdict
的解决方案:

from collections import defaultdict

mean_as_dict = mean.to_dict(orient='index')
std_as_dict = std.to_dict(orient='index')

mean_clean_sorted = {k: sorted([(i, j) for i, j in v.items()]) for k, v in mean_as_dict.items()}
std_clean_sorted = {k: sorted([(i, j) for i, j in v.items()]) for k, v in std_as_dict.items()}

sol = {k: [j + (std_clean_sorted[k][i][1],) for i, j in enumerate(v) if not np.isnan(j[1])] for k, v in mean_clean_sorted.items()}

solution = defaultdict(dict)

for k, v in sol.items():
    solution[k[0]][k[1]] = v
生成的dict将是
defaultdict
对象,您可以轻松更改为
dict

solution = dict(solution)

我找到了一种非常全面的方法来放置这个嵌套的dict:

mean_dict_items=mean.to_dict(orient='index').items()
{k[0]:{u[1]:list(zip(mean.columns, mean.loc[u], std.loc[u]))
      for u,v in mean_dict_items if (k[0],u[1]) == u} for k,l in mean_dict_items}
创建:

{'A': {'Y': [(0.0, 2.0, 10.0), (60.0, nan, 10.0), (120.0, 10.0, 10.0)],
  'Z': [(0.0, nan, 10.0), (60.0, 5.0, 10.0), (120.0, 9.0, 10.0)]},
 'B': {'W': [(0.0, 4.0, 10.0), (60.0, 8.0, 10.0), (120.0, 12.0, 10.0)],
  'X': [(0.0, 3.0, 10.0), (60.0, 7.0, 10.0), (120.0, nan, 10.0)]}}

这是一种奇怪的格式…每个组的第一列是列名吗?对不起,我不明白你的问题??这个例子正是我这里有真实数据的原始df格式。是的。我已经计算出以下代码:
{iter[0]:{iter[1]:列表(zip(mean.columns,mean.loc[iter],std.loc[iter]),用于(iter,row)在mean.iterrows()}for(iter,row)在mean.iterrows()}
中,这非常慢,而且它没有正确地结束行,因为它完全迭代第一行和第二行,创建了错误的索引级别[0]和级别[1]dict,它们之间没有联系。太棒了,这工作得很快。我现在必须研究代码。谢谢。只是一个简短的扩展:我的mean中有列,其中值为NaN。我怎么能省略这些列?如何调整代码?@Rockbar你能添加一个示例或创建另一个问题吗?我修改了上面的示例。c中有comps某些时间点的平均值为NaN(未给出)。这些三元组应该被忽略。@Rockbar您是否也可以编辑预期的结果?我这样做了,请参见上文。请检查,缩进和最后一个括号有点奇怪。谢谢。有一个“]”最后一个.loc.缺少。因此,当前代码是错误的。请更正。此外,还有一个内部元组,它太多了;三个数字应该只在一个三元组中。
{'A': {'Y': [(0.0, 2.0, 10.0), (60.0, nan, 10.0), (120.0, 10.0, 10.0)],
  'Z': [(0.0, nan, 10.0), (60.0, 5.0, 10.0), (120.0, 9.0, 10.0)]},
 'B': {'W': [(0.0, 4.0, 10.0), (60.0, 8.0, 10.0), (120.0, 12.0, 10.0)],
  'X': [(0.0, 3.0, 10.0), (60.0, 7.0, 10.0), (120.0, nan, 10.0)]}}