从pandas数据框中删除行

4

我想要删除来自 pandas df 的所有 。具体地,当在 Col A 中的 X 下方的 为空时。因此,如果在 Col A 中的 X 下面的 为空,则我希望删除所有这些 ,直到值为 X 的下面有一个 字符串

import pandas as pd

d = ({
    'A' : ['X','','','X','Foo','','X','Fou','','X','Bar'],           
    'B' : ['Val',1,3,'Val',1,3,'Val',1,3,'Val',1],
    'C' : ['Val',2,4,'Val',2,4,'Val',2,4,'Val',2],
    })

df = pd.DataFrame(data=d)

输出:

      A    B    C
0     X  Val  Val
1          1    2
2          3    4
3     X  Val  Val
4   Foo    1    2
5          3    4
6     X  Val  Val
7   Fou    1    2
8          3    4
9     X  Val  Val
10  Bar    1    2

我已经尝试过:

df = df[~(df['A'] == 'X').shift().fillna(False)]

但是这会删除X后面的所有内容。我只想在X下面一行为空时才删除它。
预期结果:
     A    B    C
0    X  Val  Val
1  Foo    1    2
2         3    4
3    X  Val  Val
4  Fou    1    2
5         4    4
6    X  Val  Val
7  Bar    1    2

我不太确定我理解了吗? - user9394674
如果在“Col A”中的值“X”下面没有值,我想删除所有这些行,直到在值“X”下面有一个值。 - user9394674
@PeterJames123,df的结构总是相同的吗?比如每3行都有一个“X”? - Joe
不好意思,它总是在数据框的开头。但它可能在5-20列之间的任何位置。 - user9394674
我意识到“duplicated”掩码是不必要的,因此解决方案被简化了。 - jezrael
显示剩余2条评论
3个回答

1

使用:

m1 = df['A'] == 'X'
g =  m1.cumsum()
m = (df['A'] == '') | m1

df = df[~m.groupby(g).transform('all')]
print (df)
      A    B    C
3     X  Val  Val
4   Foo    1    2
5          3    4
6     X  Val  Val
7   Fou    1    2
8          3    4
9     X  Val  Val
10  Bar    1    2

Details:

m1 = df['A'] == 'X'
g =  m1.cumsum()
m = (df['A'] == '') | m1

print (pd.concat([df,
                  df['A'] == 'X',
                  m1.cumsum(),
                  (df['A'] == ''), 
                  m,
                  m.groupby(g).transform('all'),
                  ~m.groupby(g).transform('all')], axis=1,
       keys=['orig','==X','g','==space','m', 'all', 'inverted all']))

   orig              ==X  g ==space      m    all inverted all
      A    B    C      A  A       A      A      A            A
0     X  Val  Val   True  1   False   True   True        False
1          1    2  False  1    True   True   True        False
2          3    4  False  1    True   True   True        False
3     X  Val  Val   True  2   False   True  False         True
4   Foo    1    2  False  2   False  False  False         True
5          3    4  False  2    True   True  False         True
6     X  Val  Val   True  3   False   True  False         True
7   Fou    1    2  False  3   False  False  False         True
8          3    4  False  3    True   True  False         True
9     X  Val  Val   True  4   False   True  False         True
10  Bar    1    2  False  4   False  False  False         True

说明:

  1. X比较并创建累积总和,以组开始为Xg
  2. 链接2个布尔掩码 - 比较X和空格与m
  3. groupbytransformDataFrameGroupBy.all一起使用,对于仅具有True的组返回True
  4. 最后反转并通过boolean indexing进行过滤

0

这是您的解决方案:

(df['A'] == 'X').shift()
0       NaN
1      True
2     False
3     False
4      True
5     False
6     False
7      True
8     False
9     False
10     True
Name: A, dtype: object
In [15]:

(df['A'] == '')
Out[15]:
0     False
1      True
2      True
3     False
4     False
5      True
6     False
7     False
8      True
9     False
10    False
Name: A, dtype: bool
In [14]:

((df['A'] == '') & (df['A'] == 'X').shift())
Out[14]:
0     False
1      True
2     False
3     False
4     False
5     False
6     False
7     False
8     False
9     False
10    False
Name: A, dtype: bool

结果如下:

df[~((df['A'] == '') & (df['A'] == 'X').shift())]
Out[16]:
A   B   C
0   X   Val Val
2       3   4
3   X   Val Val
4   Foo 1   2
5       3   4
6   X   Val Val
7   Fou 1   2
8       3   4
9   X   Val Val
10  Bar 1   2

编辑: 如果需要,您可以使用while循环完成。 old_size_df = df.size new_size_df = 0

while old_size_df != new_size_df:
    old_size_df = df.size
    df = df[~((df['A'] == '') & (df['A'] == 'X').shift())]
    new_size_df = df.size

    A   B   C
0   X   Val Val
3   X   Val Val
4   Foo 1   2
5       3   4
6   X   Val Val
7   Fou 1   2
8       3   4
9   X   Val Val
10  Bar 1   2

感谢 @ Cezary.Sz。但我需要删除除X后跟随的每一行。所以输出应该从索引3开始向下。索引0,2应被移除,而X下面的行则为空。 - user9394674

0

这里是使用自定义 apply 函数的解决方案:

d = ({
    'A' : ['X','','','X','Foo','','X','Fou','','X','Bar'],           
    'B' : ['Val',1,3,'Val',1,3,'Val',1,3,'Val',1],
    'C' : ['Val',2,4,'Val',2,4,'Val',2,4,'Val',2],
})
df = pd.DataFrame(data=d)

is_x = False
def fill_empty_a(row):
    global is_x
    if row['A'] == '' and is_x:
            row['A'] = None
    else:
            is_x = row['A'] == 'X'
    return row

(df.apply(fill_empty_a, axis=1)
   .dropna()
   .reset_index(drop=True))
#      A    B    C
# 0    X  Val  Val
# 1    X  Val  Val
# 2  Foo    1    2
# 3         3    4
# 4    X  Val  Val
# 5  Fou    1    2
# 6         3    4
# 7    X  Val  Val
# 8  Bar    1    2

是否可以同时删除第一行?它应该包括除非X后跟一个字符串。 - user9394674

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接