Обработка миллионов строк в Python - PullRequest
0 голосов
/ 13 марта 2019

Я бы хотел предвосхитить этот вопрос тем фактом, что я провел исследование сложности времени Python и структур данных, доступных для ускорения процесса.

Однако я изо всех сил пытаюсь придумать эффективный способчтобы проверить набор значений по 2,5 миллиона строк файла.Одним из решений, которое я до сих пор рассматривал, было использование списочных представлений.

В настоящее время я пытаюсь справиться с этим следующим образом:

def getTotalVolumeByCounty(fileName, counties):

values = []

with open(fileName) as csvFile:
    csvReader = csv.reader(csvFile)

    headers = next(csvReader)

    for row in csvReader:

        i = 0
        while i < len(counties):
            if row[9] == counties[i]:
                values[i] += int(row[22])
                break
return values

«Традиционный» способ, если выбудут.Сравнение каждого значения из одного списка с текущим значением в другом списке.Очевидно, что это не выгодно с точки зрения сложности времени.

Как уже говорилось ранее, я думал об использовании списочных представлений - но как это на самом деле экономит время?Является ли понимание списка моей единственной альтернативой текущей попытке?

Ответы [ 3 ]

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

2,5 миллиона строк - это не много в наши дни, но ваш не совсем рабочий код умножает каждую проверку строки на количество округов с точки зрения работы, и это сделает ее очень медленной.Если мы используем промежуточный словарь ваших округов, мы можем сделать это намного быстрее, как это:

def get_total_volume_by_county(file_name, counties):
    county_volume_map = {county: 0 for county in counties}

    with open(file_name) as csv:
        csv_reader = csv.reader(csv)

        headers = next(csv_reader)

        for row in csv_reader:
            county_volume_map[row[9]] += row[22]

    return county_volume_map

Если вы действительно просто хотите получить список томов, вы можете преобразовать его обратно в конце, но карту округак объему, вероятно, более полезным.

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

Основываясь на ветке комментариев к OP, я добавлю предложение сюда.

При работе с большими объемами данных обычно более эффективно сначала каким-либо образом сортировать данные, а затем использовать что-то вроде двоичного поиска для поиска блоков данных.

Например, вы упоминаете, что хотите сравнить элементы в одном списке с элементами во втором списке. Для этого я буду считать, что размер первого списка (список А) маленький, а второй (список Б) большой.

Если элементы в списке B упорядочены по некоторому ключу, например, по названию округа (при условии, что все округа имеют уникальное имя), вы можете использовать Алгоритм двоичного поиска , чтобы найти случайный (по существу) элемент в блоке записей для округа, а затем, в зависимости от количества записей для любого данного округа, вы либо сделаете 2 цикла, чтобы найти верхнюю и нижнюю границу, либо другой бинарный поиск, либо аналогичный для другого ключа, по которому список будет Приказ должен быть указан после оригинального ключа (например, общего объема), в результате чего у вас будет список только тех элементов, которые соответствуют определенной вами метрике.

Если данные еще не отсортированы, вероятно, стоило бы их отсортировать, поскольку сложность по времени для Heapsort или Quicksort в худшем случае O (nlogn), а в двоичном поиске - в худшем случае O (logn). Временная сложность зацикливания ваших списков, вероятно, была бы порядка O (kn ^ k) или чего-то еще, что, если бы вы строили график, было бы во много раз хуже.

Что касается последней части вашего вопроса, то понимание списка - это просто синтаксический сахар и ничего особенного не делает.

tldr; сортируйте данные по некоторому уникальному идентификатору, я рекомендую использовать Heapsort , так как он на месте, универсальный, так как вы можете предоставить функцию сравнения, и она будет работать с этим, и вы, вероятно, можете найти итеративную реализацию в Python. Затем используйте бинарный поиск для эффективного поиска предметов.

Надеюсь, это поможет!

0 голосов
/ 13 марта 2019

Исходя полностью из названия вашей функции и ее подписи, я собираюсь предположить, что вы просто пытаетесь сгруппировать общий объем продаж по стране, где countries - это список стран, которые вас интересуют.дюйма Самый простой способ в Python - это использовать dict отсчетов.Группировка идиоматически выполняется с dict объектами.В этом случае ваш dict также будет использоваться в качестве «набора», потому что мы инициализируем dict с 0 для каждой страны.Затем просто проверьте, находится ли страна в поле ввода, прежде чем увеличивать соответствующее значение.

def get_total_volume_by_country(file_name, counties):
    volume_by_country = dict.fromkeys(countries, 0)
    with open(file_name) as csv_file:
        csv_reader = csv.reader(csv_file)
        headers = next(csv_reader)

        for row in csv_reader:
            country = row[9] # presumably country name
            if country in volume_by_country:
                volume_by_country[country] += int(row[22]) # volume presumably
    return volume_by_country
...