Python 如何基于单个列上的多个StringMethods高效、惯用地过滤PandasDF的行?

Python 如何基于单个列上的多个StringMethods高效、惯用地过滤PandasDF的行?,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个熊猫数据框df,有很多列,其中一列是: col --- abc:kk__LL-z12-1234-5678-kk__z def:kk_A_LL-z12-1234-5678-kk_ss_z abc:kk_AAA_LL-z12-5678-5678-keek_st_z abc:kk_AA_LL-xx-xxs-4rt-z12-2345-5678-ek__x ... 我正在尝试获取col以abc:开头的所有记录,并且在'1234'和'2345'之间有第一个-num-(包括使用字符串搜索;-num-

我有一个熊猫数据框
df
,有很多列,其中一列是:

col
---
abc:kk__LL-z12-1234-5678-kk__z
def:kk_A_LL-z12-1234-5678-kk_ss_z
abc:kk_AAA_LL-z12-5678-5678-keek_st_z
abc:kk_AA_LL-xx-xxs-4rt-z12-2345-5678-ek__x
...
我正在尝试获取
col
abc:
开头的所有记录,并且在
'1234'
'2345'
之间有第一个
-num-
(包括使用字符串搜索;
-num-
部分正好是4位数字)

在上述情况下,我会返回

col
---
abc:kk__LL-z12-1234-5678-kk__z
abc:kk_AA_LL-z12-2345-5678-ek__x
...
我目前(我认为)的解决方案如下:

df = df[df['col'].str.startswith('abc:')]
df = df[df['col'].str.extract('.*-(\d+)-(\d+)-.*')[0].ge('1234')]
df = df[df['col'].str.extract('.*-(\d+)-(\d+)-.*')[0].le('2345')]

在熊猫身上,有什么更惯用、更有效的方法可以做到这一点

复杂的字符串操作不如数值计算有效。因此,以下方法可能更有效:

m1 = df['col'].str.startswith('abc')
m2 = pd.to_numeric(df['col'].str.split('-').str[2]).between(1234, 2345)

dfn = df[m1&m2]

                                col
0    abc:kk__LL-z12-1234-5678-kk__z
3  abc:kk_AA_LL-z12-2345-5678-ek__x

一种方法是使用regexp和apply函数。我发现在一个单独的函数中使用regexp比在表达式中拥挤要容易得多

import pandas as pd
import re

def filter_rows(string):
    z = re.match(r"abc:.*-(\d+)-(\d+)-.*", string)

    if z:
        return 1234 <= (int(z.groups()[0])) <= 2345
    else:
        return False

regex上的另一个游戏:

 #string starts with abc,greedy search, 
 #then look for either 1234, or 2345,   
#search on for 4 digit number and whatever else after

 pattern = r'(^abc.*(?<=1234-|2345-)\d{4}.*)'

 df.col.str.extract(pattern).dropna()

                          0
0   abc:kk__LL-z12-1234-5678-kk__z
3   abc:kk_AA_LL-z12-2345-5678-ek__x
#字符串以abc开头,贪婪搜索,
#然后查找1234或2345,
#在上搜索4位数字以及之后的任何内容

图案=r'(^abc)*(?谢谢!!!啊;我应该把这个例子做得更好一点。在第一个数字值之前可能有一个不确定的字母数字值,比如
-z12-x9-xx1
,因此是regex组。但是,你关于使用
来表示数字的更大观点被采纳了。当然,我会,
timeit
,但是你知道它是什么时候出现的吗最好使用
m1&m2
而不是基于通过
m1
进行过滤来计算
m2
。在我的情况下,
m1
应该是相当有选择性的(<10%的行)
 #string starts with abc,greedy search, 
 #then look for either 1234, or 2345,   
#search on for 4 digit number and whatever else after

 pattern = r'(^abc.*(?<=1234-|2345-)\d{4}.*)'

 df.col.str.extract(pattern).dropna()

                          0
0   abc:kk__LL-z12-1234-5678-kk__z
3   abc:kk_AA_LL-z12-2345-5678-ek__x