Как я могу эффективно и идиоматически фильтровать строки PandasDF на основе нескольких StringMethods в одном столбце? - PullRequest
2 голосов
/ 31 марта 2020

У меня есть 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: и имеет сначала -num- между '1234' и '2345' (включительно с использованием поиска по строке; части -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')]

Что является более идиоматическим c и эффективный способ сделать это в Pandas?

Ответы [ 3 ]

2 голосов
/ 31 марта 2020

Сложные строковые операции не так эффективны, как числовые c вычисления. Поэтому следующий подход может быть более эффективным:

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
1 голос
/ 31 марта 2020

Еще одна игра на регулярное выражение:

 #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
1 голос
/ 31 марта 2020

Один из способов - использовать регулярное выражение и применить функцию. Мне легче играть с регулярным выражением в отдельной функции, чем собирать выражение pandas.

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

Затем использовать определенную функцию для выбора строк

df.loc[df['col'].apply(filter_rows)]
                                col
0    abc:kk__LL-z12-1234-5678-kk__z
3  abc:kk_AA_LL-z12-2345-5678-ek__x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...