Pandas 或 Dask dataframe,根据缺失的分组变量组合填写值

Pandas or Dask dataframe, fill in values based on missing grouping variable combinations

Dask 与 Pandas 数据帧在这里可能没有区别,除了 Dask 中没有多索引,但我有一个 Dask 数据帧,如:

dd = pd.DataFrame({
    'name': ['a1', 'a1', 'a1', 'a1', 'a2', 'a2', 'a2'],
    'key1': ['A',  'A',  'B',  'B',  'A' , 'A',  'B' ],
    'key2': ['C',  'D',  'C',  'D',  'C',  'D',  'C' ],
    'val1': [0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7 ],
    'val2': [0.9,  0.8,  0.7,  0.6,  0.5,  0.4,  0.3 ],
})
print(dd)

  name key1 key2  val1  val2
0   a1    A    C   0.1   0.9
1   a1    A    D   0.2   0.8
2   a1    B    C   0.3   0.7
3   a1    B    D   0.4   0.6
4   a2    A    C   0.5   0.5
5   a2    A    D   0.6   0.4
6   a2    B    C   0.7   0.3

对于 'name' = 'a2',缺少 'key1' = 'B' 和 'key2' = 'D' 组合。在不使用多索引(Dask 不支持)的情况下,如何在 'val1' 和 'val2' 设置为 NaN 或其他值的情况下填写新行?我也对 Pandas 解决方案感兴趣。

请注意,这是一个示例,必须针对多个缺失的组合键来完成。

预期输出为:

  name key1 key2  val1  val2
0   a1    A    C   0.1   0.9
1   a1    A    D   0.2   0.8
2   a1    B    C   0.3   0.7
3   a1    B    D   0.4   0.6
4   a2    A    C   0.5   0.5
5   a2    A    D   0.6   0.4
6   a2    B    C   0.7   0.3
7   a2    B    D   nan   nan

您可以使用所需的所有键创建一个新数据框,然后合并这两个数据框。

from itertools import product

fixed_keys = product(['a1', 'a2'], ['A', 'B'], ['C', 'D'])
key_frame = pd.DataFrame(fixed_keys, columns=['name', 'key1', 'key2'])

new_frame = pd.merge(key_frame, dd, on=['name', 'key1', 'key2'], how='left')
print(new_frame)

  name key1 key2  val1  val2
0   a1    A    C   0.1   0.9
1   a1    A    D   0.2   0.8
2   a1    B    C   0.3   0.7
3   a1    B    D   0.4   0.6
4   a2    A    C   0.5   0.5
5   a2    A    D   0.6   0.4
6   a2    B    C   0.7   0.3
7   a2    B    D   nan   nan

如果 key_frame 太大,您可以对具有最多唯一值的键应用 groupby。

fixed_keys_sub = product(['A', 'B'], ['C', 'D'])
key_frame_sub = pd.DataFrame(fixed_keys, columns=['key1', 'key2'])

def func(sub):
    sub = pd.merge(key_frame, sub, on=['key1', 'key2'], how='left')
    sub = sub.drop(columns='name')
    return sub

dd.groupby('name').apply(func).reset_index()