python - Pandas:根据复杂逻辑删除具有特定字符串的行和列

标签 python python-3.x pandas dataframe

下面是我的数据框:

df = pd.DataFrame({'A': ['a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'all', 'all', 'all', 'all', 'all', 'all', 'all', 'all', 'all'],
              'B': ['b1', 'b1', 'b1', 'b2', 'b2', 'b2', 'all', 'all', 'all', 'b1', 'b1', 'b1', 'b2', 'b2', 'b2', 'all', 'all', 'all'],
              'C': ['c1', 'c2', 'all', 'c1', 'c2', 'all', 'c1', 'c2', 'all', 'c1', 'c2', 'all', 'c1', 'c2', 'all', 'c1', 'c2', 'all'],
              'D': ['D1', 'D2', 'all', 'D1', 'D2', 'all', 'D1', 'D2', 'all', 'D1', 'D2', 'all', 'D1', 'D2', 'all', 'D1', 'D2', 'all'],
              'E': ['E1', 'E1', 'E1', 'E2', 'E2', 'E2', 'all', 'all', 'all', 'E1', 'E1', 'E1', 'E2', 'E2', 'E2', 'all', 'all', 'all'],
              'F': [1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9]})

pivot之后,下面是输出:

In [226]: df.pivot(index=['A', 'B', 'C'], columns=['E', 'D'])
Out[226]: 
               F                          (NO)  (NO)           
E             E1   E1  E1    E2   E2  E2   all  all  all      
D             D1   D2  all   D1   D2  all   D1   D2  all
A   B   C                                               
a1  all all  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  9.0 
a1  all c1   NaN  NaN  NaN  NaN  NaN  NaN  7.0  NaN  NaN  -> (NO)
a1  all c2   NaN  NaN  NaN  NaN  NaN  NaN  NaN  8.0  NaN  -> (NO)
a1  b1  all  NaN  NaN  3.0  NaN  NaN  NaN  NaN  NaN  NaN
a1  b1  c1   1.0  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
a1  b1  c2   NaN  2.0  NaN  NaN  NaN  NaN  NaN  NaN  NaN
a1  b2  all  NaN  NaN  NaN  NaN  NaN  6.0  NaN  NaN  NaN
a1  b2  c1   NaN  NaN  NaN  4.0  NaN  NaN  NaN  NaN  NaN
a1  b2  c2   NaN  NaN  NaN  NaN  5.0  NaN  NaN  NaN  NaN
all all all  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  9.0
all all c1   NaN  NaN  NaN  NaN  NaN  NaN  7.0  NaN  NaN  -> (NO)
all all c2   NaN  NaN  NaN  NaN  NaN  NaN  NaN  8.0  NaN  -> (NO)
all b1  all  NaN  NaN  3.0  NaN  NaN  NaN  NaN  NaN  NaN  -> (NO)
all b1  c1   1.0  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  -> (NO)
all b1  c2   NaN  2.0  NaN  NaN  NaN  NaN  NaN  NaN  NaN  -> (NO)
all b2  all  NaN  NaN  NaN  NaN  NaN  6.0  NaN  NaN  NaN  -> (NO)
all b2  c1   NaN  NaN  NaN  4.0  NaN  NaN  NaN  NaN  NaN  -> (NO)
all b2  c2   NaN  NaN  NaN  NaN  5.0  NaN  NaN  NaN  NaN  -> (NO)

我需要删除 (NO) 指出的行和列。

逻辑是:从最里面的索引开始,即C,我需要保留all出现在a中的行和列落后的方式。因此,保留索引为 a1 all alla1 b1 alla1 b2 allall all all 的行因为 all 是以反向方式发生的。

索引为 a1 all c1 的行,a1 all c2all all c1all b1 all,等需要删除,因为 allC 开始向后没有连续性。

同样的逻辑也适用于列。从D开始,需要移除索引为D1 allD2 all的列,其余即可。

预期输出:

In [227]: result_df
Out[227]: 
               F                          
E             E1   E1  E1    E2   E2  E2   all      
D             D1   D2  all   D1   D2  all  all
A   B   C                                     
a1  all all  NaN  NaN  NaN  NaN  NaN  NaN  9.0 
a1  b1  all  NaN  NaN  3.0  NaN  NaN  NaN  NaN
a1  b1  c1   1.0  NaN  NaN  NaN  NaN  NaN  NaN
a1  b1  c2   NaN  2.0  NaN  NaN  NaN  NaN  NaN
a1  b2  all  NaN  NaN  NaN  NaN  NaN  6.0  NaN
a1  b2  c1   NaN  NaN  NaN  4.0  NaN  NaN  NaN
a1  b2  c2   NaN  NaN  NaN  NaN  5.0  NaN  NaN
all all all  NaN  NaN  NaN  NaN  NaN  NaN  9.0

更新新数据:

df = pd.DataFrame({'A': ['a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'a1', 'all', 'all', 'all', 'all', 'all',
                                 'all::1::2', 'all::2', 'all', 'all'],
                           'B': ['b1', 'b1', 'b1', 'b2', 'b2', 'b2', 'all', 'all::3::4', 'all', 'b1', 'b1', 'b1', 'b2', 'b2',
                                 'b2', 'all', 'all', 'all'],
                           'C': ['c1', 'c2', 'all', 'c1', 'c2', 'all', 'c1', 'c2', 'all', 'c1', 'c2', 'all', 'c1', 'c2',
                                 'all', 'c1', 'c2', 'all::5::all'],
                           'D': ['D1', 'D2', 'all', 'D1', 'D2', 'all::3::2', 'D1', 'D2', 'all', 'D1', 'D2', 'all', 'D1', 'D2',
                                 'all', 'D1', 'D2', 'all'],
                           'E': ['E1', 'E1', 'E1', 'E2', 'E2', 'E2', 'all', 'all', 'all', 'E1', 'E1', 'E1', 'E2', 'E2',
                                 'E2', 'all::1::2', 'all', 'all'],
                           'measure_F': [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9]})

透视之后:

In [334]: df
Out[334]: 
                                measure_F                                (NO) (NO)                (NO)         
E                                      E1             E2                 all             E2 all::1::2
D                                      D1   D2  all   D1   D2 all::3::2   D1   D2  all  all        D1
A         B         C                                                                                
a1        all       all               NaN  NaN  NaN  NaN  NaN       NaN  NaN  NaN  9.0  NaN       NaN
                    c1                NaN  NaN  NaN  NaN  NaN       NaN  7.0  NaN  NaN  NaN       NaN  -> (NO)
          all::3::4 c2                NaN  NaN  NaN  NaN  NaN       NaN  NaN  8.0  NaN  NaN       NaN  -> (NO)
          b1        all               NaN  NaN  3.0  NaN  NaN       NaN  NaN  NaN  NaN  NaN       NaN
                    c1                1.0  NaN  NaN  NaN  NaN       NaN  NaN  NaN  NaN  NaN       NaN
                    c2                NaN  2.0  NaN  NaN  NaN       NaN  NaN  NaN  NaN  NaN       NaN
          b2        all               NaN  NaN  NaN  NaN  NaN       6.0  NaN  NaN  NaN  NaN       NaN
                    c1                NaN  NaN  NaN  4.0  NaN       NaN  NaN  NaN  NaN  NaN       NaN
                    c2                NaN  NaN  NaN  NaN  5.0       NaN  NaN  NaN  NaN  NaN       NaN
all       all       all::5::all       NaN  NaN  NaN  NaN  NaN       NaN  NaN  NaN  9.0  NaN       NaN
                    c2                NaN  NaN  NaN  NaN  NaN       NaN  NaN  8.0  NaN  NaN       NaN  -> (NO)
          b1        all               NaN  NaN  3.0  NaN  NaN       NaN  NaN  NaN  NaN  NaN       NaN  -> (NO)
                    c1                1.0  NaN  NaN  NaN  NaN       NaN  NaN  NaN  NaN  NaN       NaN  -> (NO)
                    c2                NaN  2.0  NaN  NaN  NaN       NaN  NaN  NaN  NaN  NaN       NaN  -> (NO)
          b2        c1                NaN  NaN  NaN  4.0  NaN       NaN  NaN  NaN  NaN  NaN       NaN  -> (NO)
                    c2                NaN  NaN  NaN  NaN  5.0       NaN  NaN  NaN  NaN  NaN       NaN  -> (NO)
all::1::2 b2        all               NaN  NaN  NaN  NaN  NaN       NaN  NaN  NaN  NaN  6.0       NaN  -> (NO)
all::2    all       c1                NaN  NaN  NaN  NaN  NaN       NaN  NaN  NaN  NaN  NaN       7.0  -> (NO)

更新 2:

df = pd.DataFrame({'A':['test', 'test', 'test', 'test', 'test'], 'B':['a', 'b', 'c', 'd', 'e'], 'C':['x', 'x', 'all_group', 'y', 'y'], 'D':['abc', 'all_group::1::all_group', 'all_group::1::all_group', 'abc', 'abc'], 'E':[13, 36, 26, 39,40]})

In [599]: df.pivot(index=['A', 'B'], columns=['C', 'D'])
Out[599]: 
           E                                                      
C          x                                       all_group     y
D        abc all_group::1::all_group all_group::1::all_group   abc
A    B                                                            
test a  13.0                     NaN                     NaN   NaN
     b   NaN                    36.0                     NaN   NaN
     c   NaN                     NaN                    26.0   NaN
     d   NaN                     NaN                     NaN  39.0
     e   NaN                     NaN                     NaN  40.0

最佳答案

indexcolumns 创建掩码,帮助程序 DataFrame 最后传递给 DataFrame.loc :

df1 = df.index.to_frame()
m1 = df1.where(df1=='all').bfill(axis=1).count(axis=1).isin([0, df.index.nlevels])
df2 = df.columns.to_frame()
m2 = df2.where(df2=='all').bfill(axis=1).count(axis=1).isin([0, df.columns.nlevels])

df = df.loc[m1, m2]
print (df)    
                F                              
E             E1             E2            all
D             D1   D2  all   D1   D2  all  all
A   B   C                                     
a1  all all  NaN  NaN  NaN  NaN  NaN  NaN  9.0
    b1  all  NaN  NaN  3.0  NaN  NaN  NaN  NaN
        c1   1.0  NaN  NaN  NaN  NaN  NaN  NaN
        c2   NaN  2.0  NaN  NaN  NaN  NaN  NaN
    b2  all  NaN  NaN  NaN  NaN  NaN  6.0  NaN
        c1   NaN  NaN  NaN  4.0  NaN  NaN  NaN
        c2   NaN  NaN  NaN  NaN  5.0  NaN  NaN
all all all  NaN  NaN  NaN  NaN  NaN  NaN  9.0
    b1  all  NaN  NaN  3.0  NaN  NaN  NaN  NaN
    b2  all  NaN  NaN  NaN  NaN  NaN  6.0  NaN
 

详细信息:

使用MultiIndex.to_frame对于 DataFrame:

print (df.index.to_frame())    

               A    B    C
A   B   C                 
a1  all all   a1  all  all
        c1    a1  all   c1
        c2    a1  all   c2
    b1  all   a1   b1  all
        c1    a1   b1   c1
        c2    a1   b1   c2
    b2  all   a1   b2  all
        c1    a1   b2   c1
        c2    a1   b2   c2
all all all  all  all  all
        c1   all  all   c1
        c2   all  all   c2
    b1  all  all   b1  all
        c1   all   b1   c1
        c2   all   b1   c2
    b2  all  all   b2  all
        c1   all   b2   c1
        c2   all   b2   c2

然后用 DataFrame.where 将非 all 替换为缺失值:

print (df1.where(df1=='all'))
               A    B    C
A   B   C                 
a1  all all  NaN  all  all
        c1   NaN  all  NaN
        c2   NaN  all  NaN
    b1  all  NaN  NaN  all
        c1   NaN  NaN  NaN
        c2   NaN  NaN  NaN
    b2  all  NaN  NaN  all
        c1   NaN  NaN  NaN
        c2   NaN  NaN  NaN
all all all  all  all  all
        c1   all  all  NaN
        c2   all  all  NaN
    b1  all  all  NaN  all
        c1   all  NaN  NaN
        c2   all  NaN  NaN
    b2  all  all  NaN  all
        c1   all  NaN  NaN
        c2   all  NaN  NaN

回填不误,这里是all,by bfill:

print (df1.where(df1=='all').bfill(axis=1))
               A    B    C
A   B   C                 
a1  all all  all  all  all
        c1   all  all  NaN
        c2   all  all  NaN
    b1  all  all  all  all
        c1   NaN  NaN  NaN
        c2   NaN  NaN  NaN
    b2  all  all  all  all
        c1   NaN  NaN  NaN
        c2   NaN  NaN  NaN
all all all  all  all  all
        c1   all  all  NaN
        c2   all  all  NaN
    b1  all  all  all  all
        c1   all  NaN  NaN
        c2   all  NaN  NaN
    b2  all  all  all  all
        c1   all  NaN  NaN
        c2   all  NaN  NaN

DataFrame.count 计算非缺失值:

print (df1.where(df1=='all').bfill(axis=1).count(axis=1))
A    B    C  
a1   all  all    3
          c1     2
          c2     2
     b1   all    3
          c1     0
          c2     0
     b2   all    3
          c1     0
          c2     0
all  all  all    3
          c1     2
          c2     2
     b1   all    3
          c1     1
          c2     1
     b2   all    3
          c1     1
          c2     1

测试 0 - 这意味着回填行/列,如果所有 NaN 它与级别数匹配 MultiIndex.nlevels :

print (df1.where(df1=='all').bfill(axis=1).count(axis=1).isin([0, df.index.nlevels]))
 A    B    C  
a1   all  all     True
          c1     False
          c2     False
     b1   all     True
          c1      True
          c2      True
     b2   all     True
          c1      True
          c2      True
all  all  all     True
          c1     False
          c2     False
     b1   all     True
          c1     False
          c2     False
     b2   all     True
          c1     False
          c2     False
dtype: bool

编辑:这里是比较子字符串,然后是 np.triu 创建的辅助数组的掩码的所有值,这些辅助数组仅与 False 的行链接:

f = lambda x: x.str.contains('all')
arr1 = np.triu(np.ones((df.index.nlevels,df.index.nlevels), dtype=bool), False)
arr2 = np.triu(np.ones((df.columns.nlevels,df.columns.nlevels), dtype=bool), False)
print (arr1)
[[ True  True  True]
 [False  True  True]
 [False False  True]]

arr11 = df.index.to_frame().astype(str).apply(f).to_numpy()
arr22 = df.columns.to_frame().astype(str).apply(f).to_numpy()

#https://stackoverflow.com/a/51352806/2901002
m1 = (arr11[:, None] == arr1).all(-1).any(axis=1) | ~arr11.any(axis=1)
m2 = (arr22[:, None] == arr2).all(-1).any(axis=1) | ~arr22.any(axis=1)

df = df.loc[m1, m2]
print (df) 
                    measure_F                                       
E                          E1             E2                 all  E2
D                          D1   D2  all   D1   D2 all::3::2  all all
A   B   C                                                           
a1  all all               NaN  NaN  NaN  NaN  NaN       NaN  9.0 NaN
    b1  all               NaN  NaN  3.0  NaN  NaN       NaN  NaN NaN
        c1                1.0  NaN  NaN  NaN  NaN       NaN  NaN NaN
        c2                NaN  2.0  NaN  NaN  NaN       NaN  NaN NaN
    b2  all               NaN  NaN  NaN  NaN  NaN       6.0  NaN NaN
        c1                NaN  NaN  NaN  4.0  NaN       NaN  NaN NaN
        c2                NaN  NaN  NaN  NaN  5.0       NaN  NaN NaN
all all all::5::all       NaN  NaN  NaN  NaN  NaN       NaN  9.0 NaN

关于python - Pandas:根据复杂逻辑删除具有特定字符串的行和列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64330560/

相关文章:

python - 字符串模式改变

python-3.x - 使用 Gauge 实现 ProgressDialog

python - 按轴 0 中的单列组合 pandas DataFrame

python - 在 python 中基于分钟的日期时间列中每隔 n 分钟采样一次

python - Twisted-Klein 服务器上的 HTTP 基本身份验证

python - 追踪构建 zip 的 id

Python3 : create selective copy of dictionary as a new dictionary

python - 联立线性方程组求解中的 NaN 和奇异矩阵误差

python - Matplotlib 饼图标签与值不匹配

python - 循环浏览 Pandas Series 时获取下一个和上一个条目