根据字符串列表修改数据框行

时间:2020-07-14 18:38:55

标签: python pandas numpy

背景

我有一个数据集,其中包含以下内容:

product_title   price
Women's Pant    20.00
Men's Shirt     30.00
Women's Dress   40.00
Blue 4" Shorts  30.00
Blue Shorts     35.00
Green 2" Shorts 30.00

我根据product_title中指定的字符串创建了一个名为性别的新列,其中包含值Women,Men或Unisex。

输出看起来像这样:

product_title   price   gender
Women's Pant    20.00   women
Men's Shirt     30.00   men
Women's Dress   40.00   women
Blue 4" Shorts  30.00   women
Blue Shorts     35.00   unisex
Green 2" Shorts 30.00   women

方法

我尝试使用if / else语句创建新列:

df['gender'] = ['women' if 'women' in word or 'Blue 4"' in word or 'Green 2"' in word
                else "men" if "men" in word
                else "unisex" 
                for word in df.product_title.str.lower()]

尽管这种方法行得通,但是当我有很多条件来标记女性vs男性vs男女通用时,它变得很长。有没有更清洁的方法可以做到这一点?有没有办法让我传递一个字符串列表,而不用一连串的or条件?

我非常感谢帮助,因为我是python和pandas库的新手。

3 个答案:

答案 0 :(得分:3)

IIUC,

import numpy as np
s = df['product title'].str.lower()
df['gender'] = np.select([s.str.contains('men'), 
                          s.str.contains('women|blue 4 shorts|green 2 shorts')], 
                         ['men', 'women'],
                         default='unisex')

答案 1 :(得分:1)

您可以尝试定义自己的函数并使用apply + lambda表达式运行它:

创建可以根据需要更改的功能:

def sex(str):
    '''
    look for specific values and retun value
    '''
    for words in ['women','Blue 4"','Green 2"']:
      if words in str.lower():
          return 'women'
      elif 'men' in str.lower():
          return 'men'
      else:
          return 'unisex'

并应用于列之后,您需要检查值:

df['gender']=df['product_title'].apply(lambda str: sex(str))

干杯!

编辑3: 在环顾四周并在@anky评论之后检查来自@ansev的numpy方法后,我发现到特定点它可能会更快,用5000行进行测试,并且仍然更快,但是numpy方法开始迎头赶上。因此,这实际上取决于数据集的大小。 将会删除我最初只是在这个小框架上测试的速度方面的任何注释,从我的水平来看,这仍然是一个学习过程。

答案 2 :(得分:1)

这里是str.extractseries.map的另一个想法

d = {'women':['women','blue 4"','green 2"'],'men':['men']}
d1 = {val:k for k,v in d.items() for val in v}
pat = '|'.join(d1.keys())
import re
df['gender'] = (df['product_title'].str.extract('('+pat+')',flags=re.I,expand=False)
                .str.lower().map(d1).fillna('unisex'))

print(df)
           product_title  price  gender
0           Women's Pant   20.0   women
1            Men's Shirt   30.0     men
2          Women's Dress   40.0   women
3         Blue 4" Shorts   30.0   women
4            Blue Shorts   35.0  unisex
5  Green 2" Shorts 30.00    NaN   women