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' |
我究竟做错了什么?
(注意:我知道我可以使用
要直接回答这个问题的原始标题"如何根据条件表达式从pandas DataFrame中删除行"(我理解这不一定是OP的问题,但可以帮助其他用户遇到这个问题),一种方法是使用drop方法:
例
要删除列"得分"<50的所有行:
就地版(正如评论中所指出)
<5233>
多种条件
(参见布尔索引)
The operators are:
| foror ,& forand , and~ fornot . These must be
grouped by using parentheses.
删除列"得分"<50和> 20的所有行
当你执行
1 | df[df['column name'].map(len) < 2] |
您可以将
1 | df = df[df.score > 50] |
这比
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的通用解决方案,以提供
假设您要删除具有负值的所有行。一个班轮解决方案是: -
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上面完成的过滤
这可以很容易地扩展为过滤掉包含NaN的行(非数字条目): -
对于以下情况,也可以简化此操作:删除E列为负数的所有行
1 | df = df[(df.E>0)] |
我想结束一些关于为什么@ User的
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) |
列基本上是
在pandas中,您可以使用边界执行
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