关于python:基于涉及len(字符串)给出KeyError的条件表达式从pandas DataFrame中删除行

Delete rows from a pandas DataFrame based on a conditional expression involving len(string) giving KeyError

我有一个pandas DataFrame,我想从中删除行,其中特定列中字符串的长度大于2。

我希望能够这样做(根据这个答案):

1
df[(len(df['column name']) < 2)]

但我得到错误:

1
KeyError: u'no item named False'

我究竟做错了什么?

(注意:我知道我可以使用df.dropna()来删除包含任何NaN的行,但我没有看到如何根据条件表达式删除行。)


要直接回答这个问题的原始标题"如何根据条件表达式从pandas DataFrame中删除行"(我理解这不一定是OP的问题,但可以帮助其他用户遇到这个问题),一种方法是使用drop方法:

df = df.drop(some labels)

df = df.drop(df[].index)

要删除列"得分"<50的所有行:

df = df.drop(df[df.score < 50].index)

就地版(正如评论中所指出)

<5233>

多种条件

(参见布尔索引)

The operators are: | for or, & for and, and ~ for not. These must be
grouped by using parentheses.

删除列"得分"<50和> 20的所有行

df = df.drop(df[(df.score < 50) & (df.score > 20)].index)


当你执行len(df['column name'])时,你只得到一个数字,即DataFrame中的行数(即列本身的长度)。如果要将len应用于列中的每个元素,请使用df['column name'].map(len)。所以试试吧

1
df[df['column name'].map(len) < 2]


您可以将DataFrame分配给自身的过滤版本:

1
df = df[df.score > 50]

这比drop快:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test[test.x < 0]
# 54.5 ms ± 2.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test.drop(test[test.x > 0].index, inplace=True)
# 201 ms ± 17.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test.drop(test[test.x > 0].index)
# 194 ms ± 7.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)


我将扩展@ User的通用解决方案,以提供drop免费替代方案。这是根据问题的标题(不是OP的问题)指向这里的人

假设您要删除具有负值的所有行。一个班轮解决方案是: -

1
df = df[(df > 0).all(axis=1)]

一步一步说明: -

让我们生成一个5x5随机正态分布数据帧

1
2
3
4
5
6
7
8
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,5), columns=list('ABCDE'))
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
1 -0.977278  0.950088 -0.151357 -0.103219  0.410599
2  0.144044  1.454274  0.761038  0.121675  0.443863
3  0.333674  1.494079 -0.205158  0.313068 -0.854096
4 -2.552990  0.653619  0.864436 -0.742165  2.269755

让条件删除否定。满足条件的布尔df: -

1
2
3
4
5
6
7
df > 0
      A     B      C      D      E
0   True  True   True   True   True
1  False  True  False  False   True
2   True  True   True   True   True
3   True  True  False   True  False
4  False  True   True  False   True

满足条件的所有行的布尔系列注意如果行中的任何元素未通过该行标记为false的条件

1
2
3
4
5
6
7
(df > 0).all(axis=1)
0     True
1    False
2     True
3    False
4    False
dtype: bool

最后根据条件从数据框中过滤掉行

1
2
3
4
df[(df > 0).all(axis=1)]
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
2  0.144044  1.454274  0.761038  0.121675  0.443863

您可以将其分配回df以实际删除vs上面完成的过滤
df = df[(df > 0).all(axis=1)]

这可以很容易地扩展为过滤掉包含NaN的行(非数字条目): -
df = df[(~df.isnull()).all(axis=1)]

对于以下情况,也可以简化此操作:删除E列为负数的所有行

1
df = df[(df.E>0)]

我想结束一些关于为什么@ User的drop解决方案比基于原始列的过滤慢的分析统计数据: -

1
2
3
4
%timeit df_new = df[(df.E>0)]
345 μs ± 10.5 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit dft.drop(dft[dft.E < 0].index, inplace=True)
890 μs ± 94.9 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

列基本上是Series,即NumPy数组,可以无需任何成本地编入索引。对于那些对基础内存组织如何发挥执行速度感兴趣的人来说,这是加速熊猫的一个很好的链接:


在pandas中,您可以使用边界执行str.len并使用布尔结果对其进行过滤。

1
df[df['column name'].str.len().lt(2)]

如果要根据列值的某些复杂条件丢弃数据帧行,则以上面显示的方式写入数据可能很复杂。我有以下更简单的解决方案,它始终有效。我们假设您要删除带有"标题"的列,以便首先在列表中获取该列。

1
text_data = df['name'].tolist()

现在在列表的每个元素上应用一些函数并将其放入熊猫系列:

1
text_length = pd.Series([func(t) for t in text_data])

在我的情况下,我只是想获取令牌的数量:

1
text_length = pd.Series([len(t.split()) for t in text_data])

现在在数据框中添加一个带有上述系列的额外列:

1
df = df.assign(text_length = text_length .values)

现在我们可以在新列上应用条件,例如:

1
df = df[df.text_length  >  10]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def pass_filter(df, label, length, pass_type):

    text_data = df[label].tolist()

    text_length = pd.Series([len(t.split()) for t in text_data])

    df = df.assign(text_length = text_length .values)

    if pass_type == 'high':
        df = df[df.text_length  >  length]

    if pass_type == 'low':
        df = df[df.text_length  <  length]

    df = df.drop(columns=['text_length'])

    return df


要从pandas数据帧中删除行或n行,可以使用以下命令

1
DataFrame.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')

参考:https://www.toogit.com/tlc/article/how-to-delete-rows-from-pandas-dataframe