Масштабирование больших наборов данных

Beginner

This tutorial is from open-source community. Access the source code

Введение

В этом практическом занятии (лабораторной работе) рассматривается вопрос о том, как масштабировать анализ данных для более крупных наборов данных с использованием библиотеки pandas. Здесь рассматриваются методы, такие как загрузка меньшего объема данных, использование эффективных типов данных, разбиение на части (chunking) и использование других библиотек, таких как Dask. Важно отметить, что pandas лучше всего подходит для аналитики, выполняемой в памяти, и может не быть наилучшим инструментом для очень больших наборов данных.

Советы по виртуальной машине (VM)

После завершения запуска виртуальной машины нажмите в левом верхнем углу, чтобы переключиться на вкладку Notebook и получить доступ к Jupyter Notebook для практики.

Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook полностью загрузится. Валидация операций не может быть автоматизирована из-за ограничений Jupyter Notebook.

Если вы столкнетесь с проблемами во время обучения, не стесняйтесь обращаться к Labby. После занятия оставьте отзыв, и мы оперативно решим проблему для вас.

Генерация набора данных

Первый шаг - сгенерировать большой набор данных для тестирования. Мы создаем набор данных с большим количеством столбцов, который можно сохранить в файле формата parquet. Для этого шага требуются библиотеки pandas и numpy.

import pandas as pd
import numpy as np

def make_timeseries(start="2000-01-01", end="2000-12-31", freq="1D", seed=None):
    ## Функция для генерации временных рядов
    index = pd.date_range(start=start, end=end, freq=freq, name="timestamp")
    n = len(index)
    state = np.random.RandomState(seed)
    columns = {
        "name": state.choice(["Alice", "Bob", "Charlie"], size=n),
        "id": state.poisson(1000, size=n),
        "x": state.rand(n) * 2 - 1,
        "y": state.rand(n) * 2 - 1,
    }
    df = pd.DataFrame(columns, index=index, columns=sorted(columns))
    if df.index[-1] == end:
        df = df.iloc[:-1]
    return df

timeseries = [
    make_timeseries(freq="1T", seed=i).rename(columns=lambda x: f"{x}_{i}")
    for i in range(10)
]
ts_wide = pd.concat(timeseries, axis=1)
ts_wide.to_parquet("timeseries_wide.parquet")

Загрузка меньшего объема данных

Вместо загрузки всех данных мы можем загрузить только нужные нам столбцы. Здесь мы демонстрируем два метода для загрузки меньшего объема данных из файла формата parquet.

## Вариант 1: Загрузить все данные, а затем отфильтровать
columns = ["id_0", "name_0", "x_0", "y_0"]
pd.read_parquet("timeseries_wide.parquet")[columns]

## Вариант 2: Загрузить только запрошенные столбцы
pd.read_parquet("timeseries_wide.parquet", columns=columns)

Использование эффективных типов данных

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

ts = make_timeseries(freq="30S", seed=0)
ts.to_parquet("timeseries.parquet")
ts = pd.read_parquet("timeseries.parquet")

## Преобразование столбца 'name' в тип 'category' для повышения эффективности
ts2 = ts.copy()
ts2["name"] = ts2["name"].astype("category")

## Сокращение числовых столбцов до наименьших типов
ts2["id"] = pd.to_numeric(ts2["id"], downcast="unsigned")
ts2[["x", "y"]] = ts2[["x", "y"]].apply(pd.to_numeric, downcast="float")

Использование разбиения на части (chunking)

Разбиение на части (chunking) - это метод, который позволяет разбить большую задачу на меньшие задачи, которые можно решать независимо. Пока каждая часть помещается в память, вы можете работать с наборами данных, которые намного больше объема памяти.

files = pathlib.Path("data/timeseries/").glob("ts*.parquet")
counts = pd.Series(dtype=int)
for path in files:
    df = pd.read_parquet(path)
    counts = counts.add(df["name"].value_counts(), fill_value=0)
counts.astype(int)

Использование других библиотек

Другие библиотеки, такие как Dask, могут обрабатывать наборы данных, размер которых превышает объем памяти. Dask предоставляет API, похожее на API pandas, и может обрабатывать данные параллельно.

import dask.dataframe as dd

ddf = dd.read_parquet("data/timeseries/ts*.parquet", engine="pyarrow")

## Вычисление частот значений с использованием Dask
ddf["name"].value_counts().compute()

Резюме

В этом практическом занятии (lab) мы продемонстрировали различные методы масштабирования анализа данных для работы с большими наборами данных с использованием pandas. Мы сгенерировали большой набор данных, научились загружать меньшее количество данных, использовать эффективные типы данных и применять разбиение на части (chunking). Мы также рассмотрели, как использовать другие библиотеки, такие как Dask, для обработки наборов данных, размер которых превышает объем памяти. Методы и концепции, изученные в этом практическом занятии, будут полезны при работе с большими наборами данных в проектах по анализу данных.