Опубликовано

Как отсортировать огромный файл

У меня есть файл .tsv приличного размера, содержащий документы в следующем формате

ID  DocType NormalizedName  DisplayName Yea
12648   Book    a fancy title   A FaNcY-Title   2005
1867453 Essay   on the history of humans    On the history of humans    2016
...

Этот файл имеет размер около 67 ГБ, в сжатом виде около 22 ГБ. Я хотел бы отсортировать строки файла по идентификатору (около 300 миллионов строк) в порядке возрастания. Идентификатор каждой строки уникален и варьируется от 1 до 2147483647, могут быть пробелы. Взять и загрузить файл целиком в оперативную память не представляется возможным из-за его огромного размера. Возник вопрос как наиболее эффективно отсортировать все строки таблицы.

  1. Читаем файл частями по миллиону строк
import glob

path = "chunk_*.tsv"

chunksize = 1_000_000
fid = 1
lines = []

with open('large_file.tsv', 'r') as f_in:
    f_out = open('chunk_{}.tsv'.format(fid), 'w')
    for line_num, line in enumerate(f_in, 1):
        lines.append(line)
        if not line_num % chunksize:
            lines = sorted(lines, key=lambda k: int(k.split()[0]))
            f_out.writelines(lines)

            print('splitting', fid)
            f_out.close()
            lines = []
            fid += 1
            f_out = open('chunk_{}.tsv'.format(fid), 'w')

    # last chunk
    if lines:
        print('splitting', fid)
        lines = sorted(lines, key=lambda k: int(k.split()[0]))
        f_out.writelines(lines)
        f_out.close()
        lines = []

2. Объединяем отсортированные чанки

from heapq import merge

chunks = []
for filename in glob.glob(path):
    chunks += [open(filename, 'r')]

with open('sorted.tsv', 'w') as f_out:
    f_out.writelines(merge(*chunks, key=lambda k: int(k.split()[0])))

heapq.merge() возвращает генератор, который работает поверх исходных коллекций — поэтому не расходует лишнюю память. И он учитывает, что исходные списки уже отсортированы — поэтому не выполняет лишних действий.

Опубликовано Оставить комментарий

Новые возможности в Python 3.9

Python 3.9 в настоящее время находится на четвертой стадии бета-тестирования (по состоянию на июль 2020 года). Хотя некоторые вещи могут измениться, но теперь совершенно ясно, как будет выглядеть новая версия.

Дженерики встроенных типов в аннотациях

Начиная с версии 3.9 появилась возможность использовать привычные для нас built-in коллекции в качестве аннотаций с указанием типа содержимого этих коллекций. Напомню, что ранее для таких целей использовались объекты ListDict из модуля typing. Вот как это теперь выглядит:

def do_stuff(data: list[int]):
    pass

Вот некоторые коллекции, которые теперь можно обобщить:

  • tuple
  • list
  • dict
  • set
  • frozenset
  • typecollections.deque
  • collections.abc.Coroutine
  • re.Pattern
  • и многое другое

Объединение словарей

До Python 3.9 стандартными способами слияния с dicts были:
1. Метод .update: a.update (b)
2. {** a, ** b}
Теперь появится еще один. | Оператор объединения делает именно то, что должен: Aunion of 2 dicts:

a = {'cars': 5, 'phones': 2}
b = {'cows': 10, 'lizards': 3}
a | b
// {'cars': 5, 'phones': 2, 'cows': 10, 'lizards': 3}

Как и .update или {** a, ** b}, это может привести к потере данных, если в файле dict есть дубликаты ключей. Кроме того, этот оператор одинаково хорошо работает с расширенным назначением:

a = {'cars': 5, 'phones': 2}
b = {'cows': 10, 'lizards': 3}
a |= b
print(a)
// {'cars': 5, 'phones': 2, 'cows': 10, 'lizards': 3}

Удаление суффиксов и префиксов

Новые методы .removesuffix() и .removeprefix() для str делают это:

'SubaruImpreza`.removeprefix('Subaru') // 'Impreza' 
'SubaruImpreza'.removesuffix('Impreza') // 'Subaru'

Новый парсер

В Python 3.9 используется новый парсер. Он основан на PEG (грамматика синтаксического анализа выражения), в отличие от старой, которая использует LL (синтаксический анализатор слева направо). Это было сделано потому, что возможности синтаксического анализатора LL были исчерпаны, и стало все труднее реализовывать новые языковые функции. Скорее всего, вы не заметите никакой разницы — производительность сопоставима, а полная обратная совместимость подтверждена.
Вы должны заботиться об этом, только если ваш код использует модуль синтаксического анализа из стандартной библиотеки. Некоторое время назад она устарела и не будет работать с новым парсером. В качестве обходного пути вы можете переключиться обратно на старый анализатор, используя аргумент -X oldparser или переменную окружения PYTHONOLDPARSER = 1.

Модуль zoneinfo

В Python 3.9 появился новый модуль под названием zoneinfo. Он реализует класс ZoneInfo, который обеспечивает поддержку часовых поясов IANA.

from zoneinfo import ZoneInfo
from datetime import datetime, timedelta
timestamp = datetime(2020, 7, 15, 11, tzinfo=ZoneInfo("America/Los_Angeles"))

Модуль Graphlib

Еще один новый модуль — на этот раз для работы с графами. Прямо сейчас он реализует только алгоритм топологической сортировки для направленных ациклических графов. Если вы не поняли, что я только что написал, вам, скорее всего, не потребуется новый модуль. Для тех из вас, кто знаком с теорией графов, вот как должен использоваться модуль (взято из документации по Python):

>>> graph = {"D": {"B", "C"}, "C": {"A"}, "B": {"A"}}
>>> ts = TopologicalSorter(graph)
>>> tuple(ts.static_order())
('A', 'C', 'B', 'D')

Обновления в math

В модуле math появилось несколько интересных апдейтов, а именно:

  • функция нахождение наибольшего общего делителя теперь может принимать неограниченное количество аргументов, ранее она принимала только 2 math.gcd(10, 15, 20, 100)
  • появилась функция нахождения наименьшего общего кратного, math.lcm
Опубликовано Оставить комментарий

Шесть лучших финансовых библиотек для Python

Python — востребованный язык в сфере финансов. Но сам по себе он не обладает тем количеством возможностей, которые привносят более 50 встроенных модулей. Например, если вам потребуется рассчитать кривую дисконтирования, то для этого необходимо будет привлечь экспоненциальную и логарифмическую функции, которые предоставляет встроенный математический модуль.

Встроенных модулей будет достаточно для того минимума работы, который ожидается от среднего кванта: анализа данных, моделирования, ретрополяции и установки цены опционов. Для более серьезных и специализированных задач, знание которых могут потребоваться для работы программистом в банке или другом финансовом учреждении, существуют тысячи сторонних библиотек. Ниже мы собрали шесть наиболее функциональных из них, которые смогут значительно расширить ваш арсенал. 

NumPy

NumPy является базовым модулем для выполнения финансовых расчетов с помощью Python. На 2018 год  NumPy входил в семерку наиболее популярных модулей, на данный же момент трудно найти финансиста, который бы с ним не работал. Библиотеки NumPy позволяют манипулировать матрицами и массивами, задействовать функции генератора случайных чисел, необходимые для определенных техник оптимизации вроде бустинга и бэггинга. Стоит отметить, что значительная часть основного кода здесь написана на C, что позволяет сгладить характерную для Python медлительность.

SciPy

SciPy собран из базовых функций NumPy, и крайне удобен в обработке финансовых данных, а также техниках обработки сигнала, линейной алгебре, статистике, интерполяции и оптимизации.

Matplotlib

Помимо обработки данных, не лишней будет возможность детально их изучить, и здесь на помощь приходит Matplotlibownload.htl, модуль визуализации, позволяющий создавать все виды таблиц и графиков в двух или трех измерениях. Не самый простой в освоении модуль, но если вы уже знакомы с Matlab, то проблем не возникнет — интерфейс Matplotlib во многом повторяет его. В любом случае, время, затраченное на освоение этого непростого модуля, всегда оправдывает себя, предоставляя пользователю самый широкий спектр возможностей по визуализации.

Pandas

Pandas, основанный на SciPy и NumPy, является достаточно распространенной библиотекой для работы с данными и их анализом. Pandas отлично показывает себя в управлении временными данными, и является незаменимым инструментов для отслеживания изменений цен с течением времени. Важно отметить, что изначально модуль pandas создавался разработчиками AQR, и лишь впоследствии перешел в открытый доступ.

В сумме NumPy, SciPy, matplotlib и pandas составляют популярный пакет, обычно именуемый просто как NumPy / SciPy. Несмотря на популярность самого пакета, его установка связана со значительными сложностями, и часто рекомендуется устанавливать его посредством Anaconda для последующего запуска в виртуальной среде. Проблема, однако, в том, что помимо NumPy / SciPy Anaconda устанавливает еще более 200 библиотек, что может поставить под вопрос эффективность этого метода.

Scikit-learn

Еще один модуль из состава Anaconda, в 2008 году признанный самым популярным модулем машинного обучения для Python. Классификация, кластеринг и другие популярные техники машинного обучения здесь подаются с визуализацией matplotlib, основной же код базируется на уже упоминавшихся NumPy и SciPy.

QuantLib 

Значительная часть квантов работает в оценке и структурировании, и для них в Python доступна QuantLib, одна из наиболее востребованных библиотек для C++ для операций оценки и расчета финансовых деривативов. Среди преимуществ QuantLib  однозначно выделяется характерная для кода в C++ быстрота, но отсутствие специализированной документации для Python делает освоение этого модуля достаточной непростой задачей. Однако и она оправдывает затраченные усилия, предоставляя быстрый и доступный инструмент для оценки в повседневной деятельности трейдера, где библиотека, написанная исключительно на Python, оказалась бы непростительно медленной.