#python #regex #csv
#python #регулярное выражение #csv
Вопрос:
У меня есть пример файла Excel в формате CSV:
Receipt Name Address Date Time Items
25007 A ABC pte ltd 4/7/2016 10:40 Cheese, Cookie, Pie
.
.
25008 B CCC pte ltd 4/7/2016 12:40 Cheese, Cookie
Каков простой способ сравнить столбец «Элементы» и найти наиболее распространенный шаблон товаров, которые люди покупают вместе, и отобразить лучшие комбинации?
В этом случае аналогичный шаблон — сыр, печенье.
Комментарии:
1. Каков фактический формат вашего файла?
2. Я думаю, вам нужен более полный пример. Что, если кто-то другой купил сыр и шоколад, а другой купил только сыр? Неясно, что вы ищете…
3. Несколько вопросов: В элементах у вас есть продукты, разделенные запятыми? Вы не знаете все продукты? Наиболее распространенный шаблон может быть в любом порядке?
4. @Darryl Dan, ты ищешь только пары или какие именно критерии?
Ответ №1:
Предположим, что после обработки файла CSV вы обнаружите, что список элементов из файла CSV должен быть:
>>> items=['Cheese,Cookie,Pie', 'Cheese,Cookie,Pie', 'Cake,Cookie,Cheese',
... 'Cheese,Mousetrap,Pie', 'Cheese,Jam','Cheese','Cookie,Cheese,Mousetrap']
Сначала определите все возможные пары:
>>> from itertools import combinations
>>> all_pairs={frozenset(t) for e in items for t in combinations(e.split(','),2)}
Затем вы можете сделать:
from collections import Counter
pair_counts=Counter()
for s in items:
for pair in {frozenset(t) for t in combinations(s.split(','), 2)}:
pair_counts.update({tuple(pair):1})
>>> pair_counts
Counter({('Cheese', 'Cookie'): 4, ('Cheese', 'Pie'): 3, ('Cookie', 'Pie'): 2, ('Cheese', 'Mousetrap'): 2, ('Cookie', 'Mousetrap'): 1, ('Cheese', 'Jam'): 1, ('Mousetrap', 'Pie'): 1, ('Cake', 'Cheese'): 1, ('Cake', 'Cookie'): 1})
Который может быть расширен до более общего случая:
max_n=max(len(e.split(',')) for e in items)
for n in range(max_n, 1, -1):
all_groups={frozenset(t) for e in items for t in combinations(e.split(','),n)}
group_counts=Counter()
for s in items:
for group in {frozenset(t) for t in combinations(s.split(','), n)}:
group_counts.update({tuple(group):1})
print 'group length: {}, most_common: {}'.format(n, group_counts.most_common())
С принтами:
group length: 3, most_common: [(('Cheese', 'Cookie', 'Pie'), 2), (('Cheese', 'Mousetrap', 'Pie'), 1), (('Cheese', 'Cookie', 'Mousetrap'), 1), (('Cake', 'Cheese', 'Cookie'), 1)]
group length: 2, most_common: [(('Cheese', 'Cookie'), 4), (('Cheese', 'Pie'), 3), (('Cookie', 'Pie'), 2), (('Cheese', 'Mousetrap'), 2), (('Cookie', 'Mousetrap'), 1), (('Cheese', 'Jam'), 1), (('Mousetrap', 'Pie'), 1), (('Cake', 'Cheese'), 1), (('Cake', 'Cookie'), 1)]
Ответ №2:
Предполагая, что у вас есть значения, разделенные запятыми, вы можете использовать frozenset пар и использовать счетчик dict для получения подсчетов:
from collections import Counter
import csv
with open("test.csv") as f:
next(f)
counts = Counter(frozenset(tuple(row[-1].split(",")))
for row in csv.reader(f))
print(counts.most_common())
Если вы хотите, чтобы все комбинации или пары соответствовали вашему обновленному вводу:
from collections import Counter
from itertools import combinations
def combs(s):
return combinations(s.split(","), 2)
import csv
with open("test.csv") as f:
next(f)
counts = Counter(frozenset(t)
for row in csv.reader(f)
for t in combs(row[-1]))
# counts -> Counter({frozenset(['Cheese', 'Cookie']): 2, frozenset(['Cheese', 'Pie']): 1, frozenset(['Cookie', 'Pie']): 1})
print(counts.most_common())
Порядок пар не имеет значения, поскольку frozenset([1,2])
и frozenset([2,1])
будет считаться одинаковым.
Если вы хотите рассмотреть все комбинации из 2-n
:
def combs(s):
indiv_items = s.split(",")
return chain.from_iterable(combinations(indiv_items, i) for i in range(2, len(indiv_items) 1))
import csv
with open("test.csv") as f:
next(f)
counts = Counter(frozenset(t)
for row in csv.reader(f)
for t in combs(row[-1]))
print(counts)
print(counts.most_common())
Что для:
Receipt,Name,Address,Date,Time,Items
25007,A,ABC,pte,ltd,4/7/2016,10:40,"Cheese,Cookie,Pie"
25008,B,CCC,pte,ltd,4/7/2016,12:40,"Cheese,Cookie"
25009,B,CCC,pte,ltd,4/7/2016,12:40,"Cookie,Cheese,pizza"
25010,B,CCC,pte,ltd,4/7/2016,12:40,"Pie,Cheese,pizza"
даст вам:
Counter({frozenset(['Cheese', 'Cookie']): 3, frozenset(['Cheese', 'pizza']): 2, frozenset(['Cheese', 'Pie']): 2, frozenset(['Cookie', 'Pie']): 1, frozenset(['Cheese', 'Cookie', 'Pie']): 1, frozenset(['Cookie', 'pizza']): 1, frozenset(['Pie', 'pizza']): 1, frozenset(['Cheese', 'Cookie', 'pizza']): 1, frozenset(['Cheese', 'Pie', 'pizza']): 1})
[(frozenset(['Cheese', 'Cookie']), 3), (frozenset(['Cheese', 'pizza']), 2), (frozenset(['Cheese', 'Pie']), 2), (frozenset(['Cookie', 'Pie']), 1), (frozenset(['Cheese', 'Cookie', 'Pie']), 1), (frozenset(['Cookie', 'pizza']), 1), (frozenset(['Pie', 'pizza']), 1), (frozenset(['Cheese', 'Cookie', 'pizza']), 1), (frozenset(['Cheese', 'Pie', 'pizza']), 1)]
Комментарии:
1. по-видимому, это работает только в том случае, если есть только 2 элемента, но если есть 3 элемента, где 2 из них одинаковы, это не учитывается внутри шаблона.
2. @DarrylDan, конечно, нет, но у вас есть только пары в вашем примере ввода, поэтому ответ основан на этом факте