将稀疏的 pandas 数据帧保存到不同的文件类型

Cof*_*g13 9 python sparse-matrix dataframe pandas

我正在处理来自一个来源的 IoT 数据,该来源从传感器读数中发送大量 GB 的稀疏数据。为了制作快照进行分析,我尝试将它们导出到一个小文件,并稍后将其作为稀疏熊猫数据帧读取,以保持较低的内存使用量。

随着 pandas v1.0 的出现,事情发生了很多变化,但我陷入了困境:-(

下面是我的测试工作流程

  1. 创建一些具有不同数据类型的虚拟稀疏 IoT 数据(int、float、字符串作为类别、字符串、日期)
  2. 将它们转换为 panda 数据框(工作正常)
  3. 保存它们(以查找稀疏数据的差异)-->错误
  4. 将 panda 帧转换为稀疏数据帧 --> v1.0 之前出现错误
  5. 保存它们(以查找稀疏数据的差异)-->错误

问题:

  • 请问谁知道哪里出了问题以及如何解决
  • 我以新的熊猫方式获取稀疏数据帧的方法是否正确?

多谢

首先,创建一些稀疏输入数据

import datetime
import sys
import time
import random
import pandas as pd
from IPython.display import display, HTML

input_data = list()

# create the input for a sparse matrix with different dtypes
columns = list(map(chr, range(ord('F'), ord('Z') - 1)))
category = ['Category A', 'Category B', 'Category C']
random.seed('dsgsdf')
chunk_size = 100 * 1000  # for testing bigger or smaller data sets
for row in range(1 * chunk_size):
    r = dict()
    r['A'] = row
    if random.randint(0, 9) >= 3:
        r['B'] = str(datetime.datetime.now())  # make the datetime conversion a bit harder
    if random.randint(0, 9) >= 5:
        r['C'] = category[random.randint(0, len(category) - 1)]
    if random.randint(0, 9) >= 9:
        r['D'] = random.randint(0,1000)
    if random.randint(0, 9) >= 9:
        r['E'] = pd.util.testing.rands(4) # random string = no category
    r[columns[random.randint(0, len(columns) - 1)]] = float(random.randint(0, 1000)/2)
    input_data.append(r)
Run Code Online (Sandbox Code Playgroud)

转换为密集的 pandas 数据框

dense_df = pd.DataFrame(input_data)
dense_df = dense_df.reindex(sorted(dense_df.columns), axis=1) # sort by column name
dense_df['B'] = pd.to_datetime(dense_df['B'], format='%Y-%m-%d %H:%M:%S.%f')
dense_df['C'] = dense_df['C'].astype('category') # strings as category
dense_df = dense_df.convert_dtypes() # without this line the export works, but with the line lower memory usage
Run Code Online (Sandbox Code Playgroud)

以不同的格式将密集矩阵保存到磁盘。这不起作用,使用 .convert_dtypes() 行

dense_df.to_hdf("data/dense-data-c0.h5", key='my',complevel=0,mode='w',format='table')
dense_df.to_hdf("data/dense-data-c9.h5", key='my',complevel=9,mode='w',format='table')
dense_df.to_pickle("data/dense-data.pkl.zip")
dense_df.to_parquet("data/dense-data.parquet.gzip",compression="gzip",allow_truncated_timestamps=True)
dense_df.to_parquet("data/dense-data.parquet",allow_truncated_timestamps=True)
dense_df.to_pickle("data/dense-data.pkl")
dense_df.to_json("data/dense-data.json")
Run Code Online (Sandbox Code Playgroud)

转换为稀疏矩阵以节省内存使用。这在 pandas v1.0 之前有效

import numpy as np
start = time.time()
sparse_df = dense_df.copy()

# define some sparse dtypes
dtype_float = pd.SparseDtype('float')
dtype_int = pd.SparseDtype('int')
dtype_str = pd.SparseDtype('string')
dtype_datetime = pd.SparseDtype('datetime64')
sparse_df['B'] = sparse_df['B'].astype(dtype_datetime)
sparse_df['E'] = sparse_df['E'].astype(dtype_str)
sparse_df['D'] = sparse_df['D'].astype(dtype_int)
Run Code Online (Sandbox Code Playgroud)

以不同的格式将密集矩阵保存到磁盘。这不起作用

sparse_df.to_hdf("data/sparse-data-c0.h5", key='my',complevel=0,mode='w',format='table')
sparse_df.to_hdf("data/sparse-data-c9.h5", key='my',complevel=9,mode='w',format='table')
sparse_df.to_pickle("data/sparse-data.pkl.zip")
sparse_df.to_parquet("data/sparse-data.parquet.gzip",compression="gzip",allow_truncated_timestamps=True)
sparse_df.to_parquet("data/sparse-data.parquet",allow_truncated_timestamps=True)
sparse_df.to_pickle("data/sparse-data.pkl")
sparse_df.to_json("data/sparse-data.json")
Run Code Online (Sandbox Code Playgroud)

小智 0

  1. 跳过使用 .convert_dtypes():有时,在保存为某些文件格式(例如 HDF5 和 Parquet)时,此方法可能会引起麻烦。因此,尝试在不转换数据类型的情况下保存数据帧。您可以在保存之前手动将列转换为稀疏数据类型。
  2. 考虑使用 Dask 来处理繁重的工作:Dask 对于​​处理大数据集非常方便。它可以将任务拆分到多个核心或机器上,这可以实时节省时间。虽然它可能无法解决您所有的保存问题,但它对于在保存之前准备数据非常有用。

您可以尝试以下 Dask 快速技巧:

import dask.dataframe as dd 
# Pandas DataFrame to a Dask DataFrame
dask_df = dd.from_pandas(sparse_df, npartitions=...)
# Save Dask DataFrame
dask_df.to_parquet("data/sparse-data-dask.parquet", compression="gzip")
Run Code Online (Sandbox Code Playgroud)

尝试一下,如果您需要更多帮助,请告诉我!