Подсчитать количество совпадений строк и суммарных значений - PullRequest
3 голосов
/ 17 января 2020

Трудно описать это в заголовке, но с учетом этих двух фреймов данных:

import pandas as pd
import numpy as np
import re


df1 = pd.DataFrame({
'url': [
  'http://google.com/car', 
  'http://google.com/moto', 
  'http://google.com/moto-bike'
], 'value': [3, 4, 6]})

url                           value
http://google.com/car         3
http://google.com/moto        4
http://google.com/moto-bike   6

df2 = pd.DataFrame({'name': ['car','moto','bus']})

  name
0 car
1 moto
2 bus

Я хочу увидеть, сколько раз имя на df2 появляется на url для df1 и вроде как справились с:

df2['instances'] = pd.Series([df1.url.str.contains(fr'\D{w}\D', regex=True) \
.sum() for w in df2.name.tolist()])

По какой-то причине автомобиль имеет нулевые экземпляры, потому что есть только один.

   name  instances
0   car          0
1  moto          2
2   bus          0

То, что я хотел бы сделать, это сделать есть еще один столбец, который суммирует столбец value всех совпадений df1, поэтому он выглядит следующим образом:

   name  instances  value_total
0   car          1           3
1  moto          2          10
2   bus          0           0

Любая помощь в правильном направлении будет принята с благодарностью, спасибо!

Ответы [ 2 ]

3 голосов
/ 17 января 2020

попробуйте с str.extract, затем объедините и groupby с с именованным агрегированием ( новое в pandas 0,25 + ):

pat = '|'.join(df2['name']) #'car|moto|bus'
m = df2.merge(df1.assign(name=df1['url']
            .str.extract('('+ pat + ')', expand=False)),on='name',how='left')
m = m.groupby('name',sort=False).agg(instances=('value','count')
                 ,value_total=('value','sum')).reset_index()

print(m)

   name  instances  value_total
0   car          1          3.0
1  moto          2         10.0
2   bus          0          0.0
2 голосов
/ 17 января 2020

вот аналогичная версия ответа anky с использованием .loc, groupby & merge

pat = '|'.join(df2['name'])
df1.loc[df1['url'].str.contains(f'({pat})'),'name'] = df1['url'].str.extract(f'({pat})')[0]

vals = (
    df1.groupby("name")
    .agg({"name": "count", "value": "sum"})
    .rename(columns={"name": "instance"})
    .reset_index()
)

new_df = pd.merge(df2,vals,on='name',how='left').fillna(0)

print(new_df)
   name  instance  value
0   car       1.0    3.0
1  moto       2.0   10.0
2   bus       0.0    0.0

, если вам нужно точное совпадение car, то мы можем добавить границы слов:

pat = r'|'.join(np.where(df2['name'].str.contains('car'),
                     r'\b' + df2['name'] + r'\b', df2['name']))
print(df1)
                          url  value 
0       http://google.com/car      3   
1     http://google.com/motor      4  
2  http://google.com/carousel      6  
3       http://google.com/bus      8 

df1.loc[df1['url'].str.contains(f'{pat}'),'name'] = df1['url'].str.extract(f'({pat})')[0]
print(df1)
                          url  value  name
0       http://google.com/car      3   car
1     http://google.com/motor      4  moto
2  http://google.com/carousel      6   NaN
3       http://google.com/bus      8   bus

, если вам нужны точные совпадения для всех, тогда просто добавьте границы слов в шаблон:

pat = '|'.join(r'\b' + df2['name'] + r'\b')
#'\\bcar\\b|\\bmoto\\b|\\bbus\\b'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...