我有一个pandas DataFrame,并且我想从其中删除特定列中字符串长度大于2的行。
根据这个答案,我希望能够这样做:
df[(len(df['column name']) < 2)]
但是我只得到了这个错误:KeyError: u'no item named False'
我错在哪里了?
(注意:我知道我可以使用 df.dropna()
来删除包含任何 NaN
的行,但我不知道如何根据条件表达式删除行。)
df = df.drop(some labels)
df = df.drop(df[<some boolean condition>].index)
例子
要删除所有列中'score'小于50的行:
df = df.drop(df[df.score < 50].index)
就地版本(如评论中所指出)
df.drop(df[df.score < 50].index, inplace=True)
多重条件
(参见 布尔索引)
操作符:
|
表示或,&
表示且,~
表示非。这些操作符必须使用括号进行分组。
要删除所有列中“score”列小于 50 且大于 20 的行
df = df.drop(df[(df.score < 50) & (df.score > 20)].index)
当你执行 len(df['column name'])
时,你得到的只是一个数字,即DataFrame中该列的行数(也就是该列本身的长度)。如果你想将len
应用于列中的每个元素,请使用df['column name'].map(len)
。因此,请尝试:
df[df['column name'].map(len) < 2]
df[[(len(x) < 2) for x in df['列名']]]
,但你的更好。感谢你的帮助! - sjsdf[df['column name'].map(lambda x: str(x)!=".")]
- 4lberto.copy()
,以防您稍后需要编辑此数据帧(例如,分配新列会引发“正在尝试为数据帧的一个切片设置值”的警告)。请注意,这里只是建议,具体情况要根据您的实际需求而定。 - PlasmaBinturong您可以将DataFrame
分配给其过滤版本:
df = df[df.score > 50]
这比drop
更快:
%%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的问题)被引导到这里的人准备的。
假设你想要删除所有带有负值的行。一行代码解决方案如下:
df = df[(df > 0).all(axis=1)]
逐步解释:--
让我们生成一个5x5的随机正态分布数据框
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
假设条件是删除负数。一个满足该条件的布尔数据框:
Let the condition be deleting negatives. A boolean df satisfying the condition:-
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。
(df > 0).all(axis=1)
0 True
1 False
2 True
3 False
4 False
dtype: bool
最后根据条件从数据框中筛选出行
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以实际删除上述的过滤操作:
df = df[(df > 0).all(axis=1)]
这可以轻松地扩展为过滤掉包含NaN(非数字条目)的行:
df = df[(~df.isnull()).all(axis=1)]
对于诸如:删除所有列E为负数的行,也可以进行简化。
df = df[(df.E>0)]
我想用一些分析数据来结束关于为什么@User的drop
方案比基于原始列筛选慢的讨论:
%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:
在pandas中,您可以使用 str.len
来确定边界,并使用布尔结果对其进行筛选。
df[df['column name'].str.len().lt(2)]
text_data = df['name'].tolist()
现在对列表中的每个元素应用一些函数,并将其放入panda系列中:
text_length = pd.Series([func(t) for t in text_data])
在我的情况下,我只是试图获取令牌的数量:
text_length = pd.Series([len(t.split()) for t in text_data])
df = df.assign(text_length = text_length .values)
现在我们可以对新列应用条件,例如:
df = df[df.text_length > 10]
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
reset_index()
)。我通过错误的方式发现了这一点,当时我的数据框中有太多行被删除了。 - Jaytest = df.drop(df[df['col1'].dtype == str].index)
但是却出现了错误KeyError: False
我还尝试了df.drop(df[df.col1.dtype == str].index)
和df.drop(df[type(df.cleaned_norm_email) == str].index)
,但都没有起作用。能否给予建议。谢谢! @User - PyRsquareddf[(df.score < 50) & (df.score > 20)]
。如果您将其反转为df = df[(df.score >= 50) | (df.score <= 20)]
,您将更快地获得答案。 - Roobie Nubydf = df[...
而不是df = df.drop(...
。 - Roobie Nuby