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

Posted

技术标签:

【中文标题】从结合两个多索引dfs和列索引的元组列表构建dict【英文标题】:Build dict from list of tuples combining two multi index dfs and column index 【发布时间】:2018-07-29 13:34:57 【问题描述】:

我有两个多索引数据框: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 一个元组列表,它结合了(时间点, 均值, 标准)。 所以,结果应该是这样的

'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 时,三元组被排除在外,因此 A,Z 在时间 0,A,Y 在时间 60 B,X 在时间 120。

我怎么去那里?我已经为单行构造了一个元组列表字典的字典:

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)]

现在,我需要在每行 inner 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] 不在 [index] 中'

谢谢!

编辑:我在这个例子中将数字交换为浮点数,因为之前生成的整数与我的真实数据不一致,并且在后续 json 转储中会失败。

【问题讨论】:

这是一种奇怪的格式……每个组的第一列是列名吗? 对不起,我没听懂你的问题??这个例子正是我这里有我的真实数据的原始 df 格式。是的。 我已经制定了以下代码:iter[0]:iter[1]:list(zip(mean.columns, mean.loc[iter], std.loc[iter])) for (iter,row) in mean.iterrows() for (iter,row) in mean.iterrows() 但是,这真的很慢,并且它没有正确地换行,因为它完全迭代第一行和第二行,创建错误的索引级别[0] 和 level[1] dict,彼此不相关。 【参考方案1】:

这是使用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)

【讨论】:

太棒了,这工作得很快。我现在必须研究代码。谢谢。只是一个简短的扩展:我有平均列,其中值是 NaN。我怎么能把这些排除在外?如何调整你的代码? @Rockbar 您能否添加一个示例或创建另一个问题? 我修改了上面的例子。在某些时间点有组合,平均值为 NaN(未给出)。这些三元组应该被排除在外。 @Rockbar 你也可以编辑预期的结果吗? 我这样做了,见上文【参考方案2】:
con = pd.concat([mean, std])
primary = dict()
for i in set(con.index.values):
    if i[0] not in primary.keys():
        primary[i[0]] = dict()
    primary[i[0]][i[1]] = list()
    for x in con.columns:
        primary[i[0]][i[1]].append((x, tuple(con.loc[i[0]].loc[i[1][0].values)))

Here is sample output

【讨论】:

请您检查一下,缩进和最后一个括号有些奇怪。谢谢。 最后一个 .loc 中缺少一个“]”。因此,当前代码是错误的。请纠正。除此之外,还有一个内部元组,太多了;这三个数字应该只有一个三元组。【参考方案3】:

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

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)]

【讨论】:

以上是关于从结合两个多索引dfs和列索引的元组列表构建dict的主要内容,如果未能解决你的问题,请参考以下文章

pandas读取csv数据index_col参数指定作为行索引的数据列索引列表形成复合(多层)行索引使用方括号[]基于列索引名称元组索引列数据(index tuple)

如何在熊猫中使用具有多索引的地图?

将数组列表作为列附加到具有相同列索引的熊猫数据框中

合并两个具有多索引的数据框

pandas使用read_csv函数读取csv数据header参数指定作为列索引的行索引列表形成复合(多层)列索引使用方括号[]基于最外层列索引名称索引列数据

pandas读取csv数据header参数指定作为列索引的行索引列表形成复合(多层)列索引使用iloc基于行索引位置列表筛选dataframe数据中指定位置的多个数据行