使用regex和dictionary向dataframe添加列

2024-06-16 10:34:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我有这样的数据:

foo = pd.DataFrame({'id': ['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10'], 
                    'amount': [10, 30, 40, 15, 20, 12, 55, 45, 60, 75], 
                    'description': [u'LYFT SAN FRANCISCO CA', u'XYZ STARBUCKS MINNEAPOLIS MN', u'HOLIDAY BEMIDJI MN', 
                                    u'MCDONALDS MADISON WI', u'ABC SUPERAMERICA MI', u'SUBWAY ROCHESTER MN', 
                                    u'NNT BURGER KING WI', u'UBER TRIP CA', u'superamerica CA', u'AMAZON NY']})

foo公司:

    id       amount description
    A1        10    LYFT SAN FRANCISCO CA
    A2        30    XYZ STARBUCKS MINNEAPOLIS MN
    A3        40    HOLIDAY BEMIDJI MN
    A4        15    MCDONALDS MADISON WI
    A5        20    ABC SUPERAMERICA MI
    A6        12    SUBWAY ROCHESTER MN
    A7        55    NNT BURGER KING WI
    A8        45    UBER TRIP CA
    A9        60    superamerica CA
    A10       75    AMAZON NY

我想创建一个新列,根据description列中的关键字匹配对每个记录进行分类。你知道吗

我使用了来自thisanswer的帮助,按照以下方式进行:

import re    
dict1 = {
    "LYFT" : "cab_ride",
    "UBER" : "cab_ride",
    "STARBUCKS" : "Food",
    "MCDONALDS" : "Food",
    "SUBWAY" : "Food",
    "BURGER KING" : "Food",
    "HOLIDAY" : "Gas",
    "SUPERAMERICA": "Gas"
        }

def get_category_from_desc(x):
    try:
        return next(dict1[k] for k in dict1 if re.search(k, x, re.IGNORECASE))
    except:
        return "Other"

foo['category'] = foo.description.map(get_category_from_desc)

这是可行的,但我想问一下,这是否是解决这个问题的最佳方法。因为我有一个更大的关键字集,可以表示一个类别,我必须创建一个巨大的字典:

dict1 = {
        "STARBUCKS" : "Food",
        "MCDONALDS" : "Food",
        "SUBWAY" : "Food",
        "BURGER KING" : "Food",
             .
             .
             .
        # ~50 more keys for "Food"

        "HOLIDAY" : "Gas",
        "SUPERAMERICA": "Gas",
             .
             .
             .
        # ~20 more keys for "Gas"

        "WALMART" : "grocery",
        "COSTCO": "grocery",
             .
             .
        # ..... ~30 more keys for "grocery"
             .
             .
        # ~ Many more categories with a large number of keys for each
}

编辑:我还想知道是否有一种方法不需要我像上面所示那样创建一个庞大的字典。我可以用更小的数据结构来实现这一点吗,比如:

dict2 = {
    "cab_ride" : ["LYFT", "UBER"], #....
    "food" : ["STARBUCKS", "MCDONALDS", "SUBWAY", "BURGER KING"], #....
    "gas" : ["HOLIDAY", "SUPERAMERICA"] #....
        }

Tags: forfoofooddescriptioncaburgersubwaygas
2条回答

可以将.str访问器与extract一起使用,并在字典键上使用join编译正则表达式。你知道吗

foo = pd.DataFrame({'id': ['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10'], 
                    'amount': [10, 30, 40, 15, 20, 12, 55, 45, 60, 75], 
                    'description': [u'LYFT SAN FRANCISCO CA', u'XYZ STARBUCKS MINNEAPOLIS MN', u'HOLIDAY BEMIDJI MN', 
                                    u'MCDONALDS MADISON WI', u'ABC SUPERAMERICA MI', u'SUBWAY ROCHESTER MN', 
                                    u'NNT BURGER KING WI', u'UBER TRIP CA', u'superamerica CA', u'AMAZON NY']})


dict1 = {
    "LYFT" : "cab_ride",
    "UBER" : "cab_ride",
    "STARBUCKS" : "Food",
    "MCDONALDS" : "Food",
    "SUBWAY" : "Food",
    "BURGER KING" : "Food",
    "HOLIDAY" : "Gas",
    "SUPERAMERICA": "Gas"
        }

regstr = '(' + '|'.join(dict1.keys()) + ')'
foo['category'] = foo['description'].str.extract(regstr).squeeze().map(dict1).fillna('Other')
print(foo)

输出:

    id  amount                   description  category
0   A1      10         LYFT SAN FRANCISCO CA  cab_ride
1   A2      30  XYZ STARBUCKS MINNEAPOLIS MN      Food
2   A3      40            HOLIDAY BEMIDJI MN       Gas
3   A4      15          MCDONALDS MADISON WI      Food
4   A5      20           ABC SUPERAMERICA MI       Gas
5   A6      12           SUBWAY ROCHESTER MN      Food
6   A7      55            NNT BURGER KING WI      Food
7   A8      45                  UBER TRIP CA  cab_ride
8   A9      60               superamerica CA     Other
9  A10      75                     AMAZON NY     Other

我认为使用df.replace和基于regex的替换可以很容易地实现这一点。然后可以使用df.where来处理“其他”情况。你知道吗

dict2 = {rf'.*{k}.*': v for k, v in dict1.items()}

cats = foo['description'].replace(dict2, regex=True)
cats.where(cats != foo['description'], 'Other')

0    cab_ride
1        Food
2         Gas
3        Food
4         Gas
5        Food
6        Food
7    cab_ride
8       Other
9       Other
Name: description, dtype: object

另一个选项是将str.extractmap一起使用:

from collections import defaultdict

dict2 = defaultdict(lambda: 'Other')
dict2.update(dict1)

foo['description'].str.extract(rf"({'|'.join(dict1)})", expand=False).map(dict2)

0    cab_ride
1        Food
2         Gas
3        Food
4         Gas
5        Food
6        Food
7    cab_ride
8       Other
9       Other
Name: description, dtype: object

相关问题 更多 >