Определите наиболее распространенные комбинации значений в 2 или более столбцах в файле CSV - PullRequest
0 голосов
/ 25 марта 2019

Как найти наиболее распространенные комбинации значений в 2 или более столбцов для строк в файле CSV. Пример:

event,rack,role,dc
network,north,mobile,africa
network,east,mobile,asia
oom,south,desktop,europe
cpu,east,web,northamerica
oom,north,mobile,europe
cpu,south,web,northamerica
cpu,west,web,northamerica

Я попытался создать списки для некоторых возможных комбинаций, которые я просматриваю, а затем с помощью метода most_common () в Collections.Counter найти общие шаблоны. но мне нужен алгоритм для поиска общих записей для любой возможной комбинации из 2 или более столбцов.

Пока мой код:

import csv
from collections import Counter

class Alert:
    def __init__(self, event, rack, role, dc):
        self.event = event
        self.rack = rack
        self.role = role
        self.dc = dc

    def __str__(self):
        return(",".join([self.event, self.rack, self.role, self.dc]))


alerts = []
with open('data.csv', mode='r') as csv_file:
    csv_reader = csv.DictReader(csv_file)

    for row in csv_reader:
        alert = Alert(row['event'], row['rack'], row['role'], row['dc'])
        alerts.append(alert)
dcevent= []
dceventrole = []
dcrole = []
dcrolerack = []

for alert in alerts:
    dcevent.append(alert.dc + '-' + alert.event)
    dceventrole.append(alert.dc+'-'+alert.event+'-'+alert.role)
    dcrole.append(alert.dc+'-'+alert.role)
    dcrolerack.append(alert.dc+'-'+alert.role+'-'+alert.rack)


masterlist = Counter(dcevent).most_common() + Counter(dceventrole).most_common() + Counter(dcrole).most_common() + Counter(dcrolerack).most_common()

for item in sorted(masterlist, key=lambda x: x[1], reverse=True):
    print(item)

Это вывод для упомянутых выше записей:

('northamerica-web-cpu', 3) # there are 3 rows matching the values northamerica,web and cpu
('northamerica-web', 3) # there are 3 rows matching just the values northamerica and web
('northamerica-cpu', 3) # there are 3 rows matching northamerica and cpu
('europe-oom', 2) # there are 2 rows matching europe and oom
('africa-mobile-network', 1)
('asia-mobile-network', 1)
('europe-desktop-oom', 1)
('europe-mobile-oom', 1)
('africa-mobile-north', 1)
('asia-mobile-east', 1)
('europe-desktop-south', 1)
('northamerica-web-east', 1)
('europe-mobile-north', 1)
('northamerica-web-south', 1)
('northamerica-web-west', 1)
('africa-mobile', 1)
('asia-mobile', 1)
('europe-desktop', 1)
('europe-mobile', 1)
('africa-network', 1)
('asia-network', 1)

1 Ответ

1 голос
/ 27 марта 2019

Позвольте мне начать с определения структур данных на месте, так как считывание csv ортогонально реальной проблеме:

lines = [line.split(',') for line in """\
event,rack,role,dc
network,north,mobile,africa
network,east,mobile,asia
oom,south,desktop,europe
cpu,east,web,northamerica
oom,north,mobile,europe
cpu,south,web,northamerica
cpu,west,web,northamerica
""".splitlines()]

for line in lines:
    print line

который печатает:

['event', 'rack', 'role', 'dc']
['network', 'north', 'mobile', 'africa']
['network', 'east', 'mobile', 'asia']
['oom', 'south', 'desktop', 'europe']
['cpu', 'east', 'web', 'northamerica']
['oom', 'north', 'mobile', 'europe']
['cpu', 'south', 'web', 'northamerica']
['cpu', 'west', 'web', 'northamerica']

Теперь давайте создадим все возможные комбинации из 2 или более слов в каждой строке. Существует 11 способов выбора 2, 3 или 4 из 4 (4C2 + 4C3 + 4C4 == 6 + 4 + 1 == 11).

Алгоритм, который я использую для нахождения комбинаций, просматривает двоичные числа из 4 цифр (т.е. 0000, 0001, 0010, 0011, 0100 и т. Д.) И для каждого такого числа создает комбинацию слов в зависимости от того, соответствующая двоичная цифра равна 1. Например, для 0101 выбрано второе и четвертое слово:

def find_combinations(line):
    combinations = []
    for i in range(2**len(line)):
        bits = bin(i)[2:].zfill(len(line))
        if bits.count('1') < 2:  # skip numbers with less than two 1-bits
            continue
        combination = set()
        for bit, word in zip(bits, line):
            if bit == '1':
                combination.add(word)
        combinations.append('-'.join(sorted(combination)))
    return combinations

теперь мы можем перебрать все комбинации и посчитать их частоту:

from collections import defaultdict
counter = defaultdict(int)
for line in lines:
    for c in find_combinations(line):
        counter[c] += 1

и, наконец, мы можем отсортировать (по убыванию) по частоте

for combination_freq in sorted(counter.items(), key=lambda item: item[1], reverse=True):
    print combination_freq

чтобы получить:

('cpu-northamerica', 3)
('northamerica-web', 3)
('cpu-northamerica-web', 3)
('cpu-web', 3)
('mobile-north', 2)
('mobile-network', 2)
('europe-oom', 2)
('east-network', 1)
('asia-east-mobile', 1)
('asia-east-network', 1)
('cpu-south-web', 1)
('east-northamerica-web', 1)
('europe-north', 1)
('cpu-east', 1)
...etc.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...