Filtering/Querying Pandas 多个 grouping/agg 后的 DataFrame

Filtering/Querying Pandas DataFrame after multiple grouping/agg

我有一个首先分组的数据框,计算按库存(1-真,0-假)和制造类型(K-Kit,M-制造,P-购买)分组的 QuoteLine 项目。最后,我对 ALL 项目是 NonStock/Kit and/or Stock/['M' 的报价感兴趣,'P'] :

grouped = df.groupby(['QuoteNum', 'typecode', 'stock']).agg({"QuoteLine": "count"})

我明白了:

                                 QuoteLine-count
QuoteNum    typecode    stock   
10001          K          0         1
10003          M          0         1
10005          M          0         3
                          1         1
10006          M          1         1
...           ...        ...       ...
26961          P          1         1
26962          P          1         1
26963          P          1         2
26964          K          0         1   
               M          1         2

如果我拆开它两次:

grouped = df.groupby(['QuoteNum', 'typecode', 'stock']).agg({"QuoteLine": "count"}).unstack().unstack()

# I get
    QuoteLine-count
stock           0                       1
typecode    K       M       P       K       M       P
QuoteNum                        
10001       1.0     NaN     NaN     NaN     NaN     NaN
10003       NaN     1.0     NaN     NaN     NaN     NaN
10005       NaN     3.0     NaN     NaN     1.0     NaN
10006       NaN     NaN     NaN     NaN     1.0     NaN
10007       2.0     NaN     NaN     NaN     NaN     NaN
...         ...     ...     ...     ...     ...     ...
26959       NaN     NaN     NaN     NaN     NaN     1.0
26961       NaN     1.0     NaN     NaN     NaN     1.0
26962       NaN     NaN     NaN     NaN     NaN     1.0
26963       NaN     NaN     NaN     NaN     NaN     2.0
26964      1.0      NaN     NaN     NaN     2.0     NaN

现在我需要过滤掉所有记录,这就是我需要帮助的地方

    # pseudo-code
    (stock == 0 and typecode in ['M','P']) -> values are NOT NaN (don't want those)
    and 
    (stock == 1 and typecode='K') -> values are NOT NaN (don't want those either)

so I'm left with these records:
Basically: Columns "0/M, 0/P, 1/K" must be all NaNs and other columns have at least one non NaN value
    QuoteLine-count
stock           0                       1
typecode    K       M       P       K       M       P
QuoteNum                        
10001       1.0     NaN     NaN     NaN     NaN     NaN
10006       NaN     NaN     NaN     NaN     1.0     NaN
10007       2.0     NaN     NaN     NaN     NaN     NaN
...         ...     ...     ...     ...     ...     ...
26959       NaN     NaN     NaN     NaN     NaN     1.0
26962       NaN     NaN     NaN     NaN     NaN     1.0
26963       NaN     NaN     NaN     NaN     NaN     2.0
26964      1.0      NaN     NaN     NaN     2.0     NaN

IIUC,使用布尔掩码将符合您条件的行设置为 NaN 然后取消堆叠所需的级别:

# Shortcut (for readability)
lvl_vals = grouped.index.get_level_values

m1 = (lvl_vals('typecode') == 'K') & (lvl_vals('stock') == 0)
m2 = (lvl_vals('typecode').isin(['M', 'P'])) & (lvl_vals('stock') == 1)
grouped[m1|m2] = np.nan
out = grouped.unstack(level=['stock', 'typecode']) \
             .loc[lambda x: x.isna().all(axis=1)]

输出结果:

>>> out
         QuoteLine-count            
stock                  0       1    
typecode               K   M   M   P
QuoteNum                            
10001                NaN NaN NaN NaN
10006                NaN NaN NaN NaN
26961                NaN NaN NaN NaN
26962                NaN NaN NaN NaN
26963                NaN NaN NaN NaN
26964                NaN NaN NaN NaN

可以通过 as_index==False 获得所需的值,但我不确定它们是否符合所需的格式。

grouped = df.groupby(['QuoteNum', 'typecode', 'stock'], as_index=False).agg({"QuoteLine": "count"})

grouped[((grouped["stock"]==0) & (grouped["typecode"].isin(["M" ,"P"]))) | ((grouped["stock"]==1) & (grouped["typecode"].isin(["K"])))]