按位置和(嵌套字典中的子键或多维 pandas 数据框架中的索引)删除多个条目的最佳方法是什么?

What is the best way to remove multiple entries by position and (subkeys in nested dictionary or indices in a multidimensional pandas dataframework)?

假设我有一本结构如下的字典:

Dictionary_ABC = {'ABC 1':{'Zyzz': ['Val_1', '1', ..., 'Val_N'], 'ABC 1 X': ['Val_1', Nan, ..., 'Val_N'], 'ABC 1 Y': ['Val_1', Nan, ...,'Val_N'], 'ABC 1 Z': ['Val_1', Nan, ... 'Val_N'], 'Zim': ['Val_1', '1',..., 'Val_N']}, ..., 'ABC M':{'Zyzz': ['Val_1', '1', '2', ..., 'Val_N'], 'ABC M X': ['Val_1', Nan, Nan, ..., 'Val_N'], 'ABC M Y': ['Val_1', Nan, Nan, ...,'Val_N'], 'ABC M Z': ['Val_1', Nan, Nan, ..., 'Val_N'], 'Zim': ['Val_1', '1', '2',..., 'Val_N']}}

在这个 Dictionary_ABC 中,包含名为 ABC_1 到 ABC_M 的键,M 是一个完全任意的数字。在这些密钥中存在子密钥,它们具有随机名称 'Zyzz' 和 'Zim',但它们也有三个非随机子密钥,它们与密钥共享一个命名约定,例如:'ABC 1 X'、'ABC 1 Y'、'ABC 1 Z'。这些子项中的每一个都包含一个值列表,一些包含实际值,另一些包含 NaN 值。目标是把ABC子键中的这些NaN值去掉,把'Zim'和'Zyzz'中相同位置的信息删除,即使它们有值。

因此,在上面的示例中,我的理想输出如下所示:

Dictionary_ABC = {'ABC 1':{'Zyzz': ['Val_1', ..., 'Val_N-1'], 'ABC 1 X': ['Val_1',..., 'Val_N-1'], 'ABC 1 Y': ['Val_1', ...,'Val_N-1'], 'ABC 1 Z': ['Val_1', ... 'Val_N-1'], 'Zim': ['Val_1',..., 'Val_N-1']}, ..., 'ABC M':{'Zyzz': ['Val_1',..., 'Val_N-2'], 'ABC M X': ['Val_1',..., 'Val_N-2'], 'ABC M Y': ['Val_1',...,'Val_N-2'], 'ABC M Z': ['Val_1',..., 'Val_N-2'], 'Zim': ['Val_1',..., 'Val_N-2']}}

为了简单起见,我假设只有一个条目从 'ABC 1' 子键中包含的列表中的相同位置被删除,以及两个条目从列表中包含的相同位置被删除'ABC M' 子键。然而,它可以是任何尺寸。因此,如果我不清楚的话,回顾一下,如果任何 ABC 子键包含 NaN,目标是从给定键的相同位置的子键列表中删除信息。

我试图将这个嵌套字典转换为 Pandas 数据框以对其执行操作。我收到了从 1 到 ψ 的元组行和列,ψ 是这些列的任意数量。因此,如果我使用上面的示例表示信息,它看起来像:

('ABC 1', 'Zyzz')    ['Val_1', '1', ..., 'Val_N']
('ABC 1', 'ABC 1 X') ['Val_1', NaN, ..., 'Val_N']
('ABC 1', 'ABC 1 Y') ['Val_1', NaN, ..., 'Val_N']
('ABC 1', 'ABC 1 Z') ['Val_1', NaN, ..., 'Val_N']
('ABC 1', 'Zim')     ['Val_1', '1', ..., 'Val_N']
        . 
        .
        .
('ABC M', 'Zyzz')    ['Val_1', '1', '2',..., 'Val_N']
('ABC M', 'ABC M X') ['Val_1', Nan, Nan, ...,'Val_N']
('ABC M', 'ABC M Y') ['Val_1', Nan, Nan, ...,'Val_N']
('ABC M', 'ABC M Z') ['Val_1', Nan, Nan, ...,'Val_N']
('ABC M', 'Zim')     ['Val_1', '1', '2',..., 'Val_N']

我尝试使用以下代码索引 NaN 值:

NaN_Index = []
for row in cleaning_dataframe.iterrows():
    current_index = cleaning_dataframe[row].index[cleaning_dataframe[row].apply(np.isnan)]
    NaN_Index.append(current_index)

我们的想法是将这些值插入到一个列表中,然后循环中的 df.drop 函数可以稍后使用该列表来删除聚合错误。我收到这个 KeyError:

KeyError: (('ABC 1', 'Zyzz'), 0 Val_1
1 Val_2
2 Val_3
  .
  .
  .
N+1 Val_N

我的想法是创建一个这样的函数:

for row in df.iterrows():
    for i in NaN_Index:
        DataFrame.drop(labels=row, axis=0, index=i, columns=None, level=None, inplace=False, errors='raise')

排除敷衍,这是执行此操作的最佳方法吗?有没有我可以使用的某种形式的字典理解,不需要我将嵌套字典转换为数据框?有没有更好的方法来实例化此数据框,以便我可以筛选并轻松删除我想要的行或列?非常感谢您的考虑。请随时问我任何问题。

编辑:我还尝试了一个嵌套循环以查看是否可以在相同位置找到要删除的值。

for k in d:
    for sk in d[k]:
        if re.findal("ABC \d+", sk) == re.findall("ABC \d+", k):
           for v in d[k][sk]:
               if all(np.isnan(d[k][sk][v])):
                      print("you've reached this point")

不幸的是,我收到一个类型错误。列表索引必须是整数或切片,而不是 str.

一个想法是从第一个嵌套字典创建一个数据框。因此,例如,对于第一项,它会给出

print(pd.DataFrame(Dictionary_ABC['ABC 1']))
    Zyzz ABC 1 X ABC 1 Y ABC 1 Z    Zim
0  Val_1   Val_1   Val_1   Val_1  Val_1
1      1     NaN     NaN     NaN      1
2  Val_N   Val_N   Val_N   Val_N  Val_N

现在,您可以使用 loc 执行行的选择,如果 allisna 一次 filter 列如 'ABC'

print(pd.DataFrame(Dictionary_ABC['ABC 1'])
        .loc[lambda x: ~x.filter(like='ABC').isna().all(axis=1)])
    Zyzz ABC 1 X ABC 1 Y ABC 1 Z    Zim
0  Val_1   Val_1   Val_1   Val_1  Val_1
2  Val_N   Val_N   Val_N   Val_N  Val_N

你只需要将它打包回 to_dict 面向列表。使用字典理解来创建新字典。从这里开始:

Dictionary_ABC = {
    'ABC 1':{'Zyzz': ['Val_1', '1',  'Val_N'], 
             'ABC 1 X': ['Val_1', np.nan,  'Val_N'], 
             'ABC 1 Y': ['Val_1', np.nan, 'Val_N'], 
             'ABC 1 Z': ['Val_1', np.nan, 'Val_N'], 
             'Zim': ['Val_1', '1', 'Val_N']},  
    'ABC M':{'Zyzz': ['Val_1', '1', '2',  'Val_N'], 
             'ABC M X': ['Val_1', np.nan, np.nan,  'Val_N'],
             'ABC M Y': ['Val_1', np.nan, np.nan, 'Val_N'], 
             'ABC M Z': ['Val_1', np.nan, np.nan,  'Val_N'], 
             'Zim': ['Val_1', '1', '2', 'Val_N']}}

你需要做的:

new_dict = {
    key: (pd.DataFrame(val)
            .loc[lambda x: ~x.filter(like='ABC').isna().all(axis=1)]
            .to_dict(orient='list'))
    for key, val in Dictionary_ABC.items()
}
new_dict
{'ABC 1': {'Zyzz': ['Val_1', 'Val_N'],
  'ABC 1 X': ['Val_1', 'Val_N'],
  'ABC 1 Y': ['Val_1', 'Val_N'],
  'ABC 1 Z': ['Val_1', 'Val_N'],
  'Zim': ['Val_1', 'Val_N']},
 'ABC M': {'Zyzz': ['Val_1', 'Val_N'],
  'ABC M X': ['Val_1', 'Val_N'],
  'ABC M Y': ['Val_1', 'Val_N'],
  'ABC M Z': ['Val_1', 'Val_N'],
  'Zim': ['Val_1', 'Val_N']}}
L1 = list(dictionary.keys())
D = {}

for i in L1:
    D[i] = pd.DataFrame(dictionary[i]).loc[lambda x: ~x.filter(like=i).isna().all(axis=1)].to_dict(orient='list')

感谢@Ben.T,我能够将这个 3d 嵌套字典缩减为 2D 数据框,这样更容易对其执行操作。

编辑:

上面的代码按照承诺创建了一个新的嵌套字典。