Замена значений в столбце pandas по количеству повторений
Существует список автомобильных марок:
automobile = ['ford', 'nissan', 'lincoln', 'pontiac', 'hyundai', 'buick', 'chevrolet', 'honda', 'acura', 'cadillac', 'gmc',
'dodge', 'mercedes', 'toyota', 'volkswagen', 'bmw', 'infiniti',
'chrysler', 'kia', 'subaru', 'jeep', 'lexus', 'mazda', 'volvo',
'audi', 'mini', 'mitsubishi', 'saturn']
pp = ['hyundai motor finance','jpmorgan chase bank,n.a.','financial services remarketing (lease)','mercedes-benz financial services','chrysler capital','toyota financial services','jim coleman cadillac infiniti']
cc = pd.DataFrame({'seller': pp})
Необходимо пройтись по названиям автомобильных компаний в столбце cc['seller'] и выяснить, сколько автомобильных марок из списка встречается в названии компании. Если в названии компании встречается два и больше (>=2) названий из списка (больше двух автомобильных марок), то название компании необходимо оставить как есть. Если в названии компании встречается только 1 автомобильная марка из списка, то название компании необходимо поменять на эту марку.
Например: в названии компании 'bmw/jeep resale inc.' присутствует 2 автомобильные марки. Значит название оставляем как есть. Если компания называется 'bmw autos', то название компании необходимо поменять на 'bmw resaler'.
Я попробовал написать цикл на перебор значений со счётчиком: https://pastebin.com/rBrjF03b , но сильно упала производительность и я не уверен в правильности.
Как можно написать такой цикл оптимально и не громоздко?
Ответы (2 шт):
Можно сделать векторизованно:
mask = cc['seller'].str.split(expand=True).isin(automobile).apply(sum, axis=1)==1
cc.loc[mask, "seller"] = cc.loc[mask, "seller"].str.split().str.get(0)+" resale"
теперь сс:
seller
0 hyundai resale
1 jpmorgan chase bank,n.a.
2 financial services remarketing (lease)
3 mercedes-benz financial services
4 chrysler resale
5 toyota resale
6 jim coleman cadillac infiniti
обратите внимание, что mercedes-benz и mercedes считаются за две разные марки.
Если хотите проверять марки. записанные через "-", то можно просто поменять строку:
mask = cc['seller'].str.split("[ -]",expand=True).isin(automobile).apply(sum, axis=1)==1
тогда у вас получится:
seller
0 hyundai resale
1 jpmorgan chase bank,n.a.
2 financial services remarketing (lease)
3 mercedes-benz resale
4 chrysler resale
5 toyota resale
6 jim coleman cadillac infiniti
Решение построено на множествах. Изначально задаем automobile не как список, а как множество. Далее каждую строку разбиваем по пробелам и сравниваем с automobile на предмет пересечения. Где остается один элемент множества - извлекаем и добавляем seller. Потом по индексу вносим во фрейм.
Подход позволяет забрать не первое слово из строки, а совпавшее со множеством слово, даже если оно не первое, как, например, 'audi' в 'first audi finance company'.
automobile = {'ford', 'nissan', 'lincoln', 'pontiac', 'hyundai', 'buick', 'chevrolet', 'honda', 'acura', 'cadillac',
'gmc',
'dodge', 'mercedes', 'toyota', 'volkswagen', 'bmw', 'infiniti',
'chrysler', 'kia', 'subaru', 'jeep', 'lexus', 'mazda', 'volvo',
'audi', 'mini', 'mitsubishi', 'saturn'}
pp = ['hyundai motor finance', 'jpmorgan chase bank,n.a.', 'financial services remarketing (lease)',
'mercedes-benz financial services', 'chrysler capital', 'toyota financial services',
'jim coleman cadillac infiniti','first audi finance company']
cc = pd.DataFrame({'seller': pp})
bb = cc.seller.apply(lambda x: automobile.intersection(x.split()))
ll = bb[bb.transform(len).eq(1)].apply(lambda x: x.pop() + ' resaler')
cc.loc[ll.index,'seller'] = ll
print(cc)
seller
0 hyundai resaler
1 jpmorgan chase bank,n.a.
2 financial services remarketing (lease)
3 mercedes-benz financial services
4 chrysler resaler
5 toyota resaler
6 jim coleman cadillac infiniti
7 audi resaler
