按索引名称过滤数据框行

8

我有一个DataFrame,想要根据索引名称删除元素

               col1  col2
entry_1          10    11
entry_2_test     12    13
entry_3          14    15
entry_4_test     16    17

基本上我想要删除以_test结尾的项目。

我知道如何选择它们:

df.filter(like='_test', axis=0)

               col1  col2
entry_2_test     12    13
entry_4_test     16    17

然后我就可以实际获取这些索引:
df.filter(like='_test', axis=0).index

entry_2_test
entry_4_test

最后,我可以删除那些索引,并使用筛选后的数据框覆盖原始数据框。

df = df.drop(df.filter(like='_test', axis=0).index)
df

               col1  col2
entry_1          10    11
entry_3          14    15

我的问题是,这是否是正确的过滤方式,或者有更有效的专用函数来完成此操作?


7
df = df[~df.index.str.endswith('_test')] 这样做就可以了。 - ALollz
3个回答

6
您可以反转str.endswith的结果:
In[13]:
df.loc[~df.index.str.endswith('_test')]

Out[13]: 
         col1  col2
entry_1    10    11
entry_3    14    15

或者切割最后的5个字符并使用!=进行比较:

In[13]:
df.loc[df.index.str[-5:]!='_test']

Out[18]: 
         col1  col2
entry_1    10    11
entry_3    14    15

仍然可以使用filter方法,通过传递一个正则表达式模式来过滤掉不以'_test'结尾的行:

In[25]:
df.filter(regex='.*[^_test]$', axis=0)

Out[25]: 
         col1  col2
entry_1    10    11
entry_3    14    15

正如@user3483203所指出的那样,最好使用以下正则表达式:

df.filter(regex='.*(?<!_test)$', axis=0)

1
@user3483203 好的,我会做。 - EdChum

3

使用filterregex

df.filter(regex='.*[^_test]$', axis=0)
Out[274]: 
         col1  col2
entry_1    10    11
entry_3    14    15

1
我建议使用df.filter(regex='.*(?<!_test)$', axis=0),因为当前的正则表达式会删除索引为entry_3_este的行。 - user3483203

3
你可以使用列表推导式并将布尔值列表传递给 pd.DataFrame.loc
虽然这似乎是反模式,但实际上更有效率,因为 Pandas 字符串方法并不特别优化。
df2 = pd.concat([df]*10000)

%timeit df2.loc[[i[-5:] == '_test' for i in df2.index]]    # 11.7 ms per loop
%timeit df2.loc[[i.endswith('_test') for i in df2.index]]  # 13.3 ms per loop
%timeit df2[~(df2.index.str[-5:] == '_test')]              # 22.1 ms per loop
%timeit df2[~df2.index.str.endswith('_test')]              # 21.7 ms per loop

1
非常正确,与列表推导式+1相比,str方法的速度令人沮丧。 - EdChum

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