Как узнать количество похожих адресов для каждого клиента?

1

У меня есть набор данных с двумя столбцами: id клиента и addresses:

id      addresses
1111    asturias 32, benito juarez, CDMX
1111    JOSE MARIA VELASCO, CDMX
1111    asturias 32 DEPT 401, INSURGENTES, CDMX
1111    deportes
1111    asturias 32, benito juarez, MIXCOAC, CDMX
1111    cd. de los deportes
1111    deportes, wisconsin
2222    TORRE REFORMA LATINO, CDMX
2222    PERISUR 2890
2222    WE WORK, CDMX
2222    WEWORK, TORRE REFORMA LATINO, CDMX
2222    PERISUR: 2690, COYOCAN
2222    TORRE REFORMA LATINO

Мне интересно найти количество разных адресов для каждого клиента. Например, для id клиента 1111 существует 3 разных адреса:

  1. [asturias 32, benito juarez, CDMX, asturias 32 DEPT 401, INSURGENTES, CDMX, asturias 32, benito juarez, MIXCOAC, CDMX]

  2. [JOSE MARIA VELASCO, CDMX]

  3. [deportes, cd. de los deportes, deportes, wisconsin]

Я написал код в python, который может показывать только сходство между двумя последовательными строками: строка i и строка i+1 (оценка 0 означает совершенно несходную, а 1 означает полностью аналогичную).

id      addresses                                  score
1111    asturias 32, benito juarez, CDMX             0
1111    JOSE MARIA VELASCO, CDMX                     0
1111    asturias 32 DEPT 401, INSURGENTES, CDMX      0
1111    deportes                                     0
1111    asturias 32, benito juarez, MIXCOAC, CDMX    0
1111    cd. de los deportes                          0.21
1111    deportes, wisconsin                          0
2222    TORRE REFORMA LATINO, CDMX                   0
2222    PERISUR 2890                                 0
2222    WE WORK, CDMX                                0.69
2222    WEWORK, TORRE REFORMA LATINO, CDMX           0
2222    PERISUR: 2690, COYOCAN                       0
2222    TORRE REFORMA LATINO

Если оценка> 0,20, я рассматриваю их два разных адреса. Ниже приведен мой код:

import nltk
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import re
import unicodedata
import unidecode
import string
from sklearn.feature_extraction.text import TfidfVectorizer

data=pd.read_csv('address.csv')
nltk.download('punkt')
stemmer = nltk.stem.porter.PorterStemmer()
remove_punctuation_map = dict((ord(char), None) for char in string.punctuation)

def stem_tokens(tokens):
    return [stemmer.stem(item) for item in tokens]

'''remove punctuation, lowercase, stem'''
def normalize(text):
    return stem_tokens(
        nltk.word_tokenize(text.lower().translate(remove_punctuation_map)))

vectorizer = TfidfVectorizer(tokenizer=normalize, stop_words='english')

def cosine_sim(text1, text2):
    tfidf = vectorizer.fit_transform([text1, text2])
    return ((tfidf * tfidf.T).A)[0, 1]

cnt = np.array(np.arange(0, 5183))
indx = []

for i in cnt:
    print cosine_sim(data['address'][i], data['address'][i + 1])

Но выше код не может сравнивать каждую возможную строку для конкретного id клиента. Мне нужен вывод, как показано ниже:

id     unique address
1111    3
2222    3
3333    2
Теги:
numpy
nlp
scikit-learn
nltk

1 ответ

1
Лучший ответ

Для этой цели вы можете использовать комбинации в itertools. См. Приведенный ниже код.

Обратите внимание, что я использовал CSV файл с разделителями с запятой

Кроме того, вы можете использовать функцию similarity в SPACY чтобы найти сходство между двумя фразами, если хотите. Здесь я использовал ту же функцию, которую вы предоставили.

import nltk
import numpy as np
import pandas as pd
import itertools
import string
from sklearn.feature_extraction.text import TfidfVectorizer


def stem_tokens(tokens):
    return [stemmer.stem(item) for item in tokens]

'''remove punctuation, lowercase, stem'''
def normalize(text):
    return stem_tokens(
        nltk.word_tokenize(text.lower().translate(remove_punctuation_map)))

def cosine_sim(text1, text2):
    tfidf = vectorizer.fit_transform([text1, text2])
    return ((tfidf * tfidf.T).A)[0, 1]

def group_addresses(addresses):
    '''merge the lists if they have an element in common'''
    out = []
    while len(addresses)>0:
        # first, *rest = addresses  # for python 3
        first, rest = addresses[0], addresses[1:]  # for python2
        first = set(first)
        lf = -1
        while len(first)>lf:
            lf = len(first)

            rest2 = []
            for r in rest:
                if len(first.intersection(set(r)))>0:
                    first |= set(r)
                else:
                    rest2.append(r)     
            rest = rest2

        out.append(first)
        addresses = rest
    return out


df=pd.read_csv("address.csv", sep=";")
stemmer = nltk.stem.porter.PorterStemmer()
remove_punctuation_map = dict((ord(char), None) for char in string.punctuation)

vectorizer = TfidfVectorizer(tokenizer=normalize, stop_words='english')

sim_df = pd.DataFrame(columns=['id', 'unique address'])

for customer in set(df['id']):
    customer_addresses = (df.loc[df['id'] == customer]['addresses'])    #Get the addresses of each customer
    all_entries = [[adr] for adr in customer_addresses]    #Make list of lists
    sim_pairs = [list((text1, text2)) for text1, text2 in itertools.combinations(customer_addresses, 2) if cosine_sim(text1, text2) >0.2 ]      # Find all pairs whose similiarty is greater than 0.2
    all_entries.extend(sim_pairs)
    sim_pairs = group_addresses(all_entries)
    print(customer , len(sim_pairs))

Результат выглядит

2222 2
1111 3

Созданные группы

2222
['WE WORK, CDMX', 'WEWORK, TORRE REFORMA LATINO, CDMX', 'TORRE REFORMA LATINO, CDMX', 'TORRE REFORMA LATINO']
['PERISUR 2890', 'PERISUR: 2690, COYOCAN']

1111
['asturias 32 DEPT 401, INSURGENTES, CDMX', 'asturias 32, benito juarez, MIXCOAC, CDMX', 'asturias 32, benito juarez, CDMX']
['JOSE MARIA VELASCO, CDMX']
['deportes, wisconsin', 'cd. de los deportes', 'deportes']
  • 0
    Привет, да, я пытался запустить ваш код, но я получаю сообщение об ошибке: Файл "<ipython-input-14-4e68ec561d81>", строка 25 первая, * rest = address ^ SyntaxError: неверный синтаксис
  • 0
    Хорошо. Я предполагаю, что вы используете Python 2.7, мой код работает на Python 3. Для Python 2 first, *rest = addresses измените строку first, *rest = addresses на first, rest = addresses[0], addresses[1:] . Отредактировал код.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню