扩展大型数据集

Beginner

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

简介

本实验重点介绍如何使用 pandas 将数据分析扩展到更大的数据集。它涵盖了诸如加载更少数据、使用高效数据类型、分块以及利用 Dask 等其他库的方法。需要注意的是,pandas 更适合内存分析,对于非常大的数据集可能不是最佳工具。

虚拟机使用提示

虚拟机启动完成后,点击左上角切换到“笔记本”标签以访问 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")

使用分块

分块是一种将大问题分解为可独立解决的小问题的方法。只要每个块能装入内存,你就可以处理比内存大得多的数据集。

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 提供了类似 pandas 的 API,并且可以并行处理数据。

import dask.dataframe as dd

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

## 使用 Dask 计算值计数
ddf["name"].value_counts().compute()

总结

在本实验中,我们展示了使用 pandas 将数据分析扩展到更大数据集的不同技术。我们生成了一个大型数据集,学习了如何加载更少的数据、使用高效的数据类型以及分块。我们还探索了如何利用像 Dask 这样的其他库来处理大于内存的数据集。在数据分析项目中处理大型数据集时,本实验中学到的技术和概念将很有用。