扩展大型数据集

PandasPandasBeginner
立即练习

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

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

本实验重点介绍如何使用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这样的其他库来处理大于内存的数据集。在数据分析项目中处理大型数据集时,本实验中学到的技术和概念将很有用。