簡體   English   中英

熊貓SparseSeries可以將值存儲在float16 dtype中嗎?

[英]Can pandas SparseSeries store values in the float16 dtype?

我之所以要在稀疏的熊貓容器中使用較小的數據類型,是為了減少內存使用量。 這與處理最初使用bool(例如,來自to_dummies )或較小數字dtype(例如int8)的數據有關,這些數據在稀疏容器中都轉換為float64。

DataFrame創建

提供的示例使用適度的20k x 145數據幀。 實際上,我正在按1e6 x 5e3的順序處理數據幀。

In []: bool_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 19849 entries, 0 to 19848
Columns: 145 entries, topic.party_nl.p.pvda to topic.sub_cat_Reizen
dtypes: bool(145)
memory usage: 2.7 MB

In []: bool_df.memory_usage(index=False).sum()
Out[]: 2878105

In []: bool_df.values.itemsize
Out[]: 1

鑒於原始dtype,此數據幀的稀疏版本需要較少的內存,但仍然比所需的內存大得多。

In []: sparse_df = bool_df.to_sparse(fill_value=False)

In []: sparse_df.info()
<class 'pandas.sparse.frame.SparseDataFrame'>
RangeIndex: 19849 entries, 0 to 19848
Columns: 145 entries, topic.party_nl.p.pvda to topic.sub_cat_Reizen
dtypes: float64(145)
memory usage: 1.1 MB

In []: sparse_df.memory_usage(index=False).sum()
Out[]: 1143456

In []: sparse_df.values.itemsize
Out[]: 8

即使此數據相當稀疏,從bool到float64的dtype轉換也會導致非填充值占用8倍的空間。

In []: sparse_df.memory_usage(index=False).describe()
Out[]:
count      145.000000
mean      7885.903448
std      17343.762402
min          8.000000
25%        640.000000
50%       1888.000000
75%       4440.000000
max      84688.000000

考慮到數據的稀疏性,人們希望能夠大幅度減少內存大小:

In []: sparse_df.density
Out[]: 0.04966184346992205

基礎存儲的內存占用量

SparseDataFrame的列是SparseSeries ,它使用SparseArray作為基礎numpy.ndarray存儲的包裝器。 稀疏數據幀使用的字節數(也)可以直接從這些ndarrays計算:

In []: col64_nbytes = [
.....:     sparse_df[col].values.sp_values.nbytes
.....:     for col in sparse_df
.....: ]

In []: sum(col64_nbytes)
Out[]: 1143456

可以將ndarrays轉換為使用較小的float,這使人們可以計算使用例如float16時數據幀需要多少內存。 如人們所料,這將導致數據幀縮小4倍。

In []: col16_nbytes = [
.....:     sparse_df[col].values.sp_values.astype('float16').nbytes
.....:     for col in sparse_df
.....: ]

In []: sum(col16_nbytes)
Out[]: 285864

通過使用更合適的dtype,可以將內存使用率減少到密集版本的10%,而float64稀疏數據幀減少到40%。 對於我的數據,這可能需要20 GB和5 GB的可用內存。

In []: sum(col64_nbytes) / bool_df.memory_usage(index=False).sum()
Out[]: 0.3972947477593764

In []: sum(col16_nbytes) / bool_df.memory_usage(index=False).sum()
Out[]: 0.0993236869398441

問題

不幸的是,稀疏容器的dtype轉換尚未在熊貓中實現:

In []: sparse_df.astype('float16')
---------------------------------------------------
[...]/pandas/sparse/frame.py in astype(self, dtype)
    245
    246     def astype(self, dtype):
--> 247         raise NotImplementedError
    248
    249     def copy(self, deep=True):

NotImplementedError:

如何將SparseSeries中的SparseDataFrame轉換為使用numpy.float16數據類型,或每個項目使用少於64個字節的numpy.float64而不是默認的numpy.float64

SparseArray構造函數可用於轉換其基礎ndarray 要轉換數據幀中的所有稀疏序列,可以遍歷df的序列,轉換其數組,然后用轉換后的版本替換該序列。

import pandas as pd
import numpy as np

def convert_sparse_series_dtype(sparse_series, dtype):
    dtype = np.dtype(dtype)
    if 'float' not in str(dtype):
        raise TypeError('Sparse containers only support float dtypes')

    sparse_array = sparse_series.values
    converted_sp_array = pd.SparseArray(sparse_array, dtype=dtype)

    converted_sp_series = pd.SparseSeries(converted_sp_array)
    return converted_sp_series


def convert_sparse_columns_dtype(sparse_dataframe, dtype):
    for col_name in sparse_dataframe:
        if isinstance(sparse_dataframe[col_name], pd.SparseSeries):
            sparse_dataframe.loc[:, col_name] = convert_sparse_series_dtype(
                 sparse_dataframe[col_name], dtype
            )

這達到了減少稀疏數據幀的內存占用的既定目的:

In []: sparse_df.info()
<class 'pandas.sparse.frame.SparseDataFrame'>
RangeIndex: 19849 entries, 0 to 19848
Columns: 145 entries, topic.party_nl.p.pvda to topic.sub_cat_Reizen
dtypes: float64(145)
memory usage: 1.1 MB

In []: convert_sparse_columns_dtype(sparse_df, 'float16')

In []: sparse_df.info()
<class 'pandas.sparse.frame.SparseDataFrame'>
RangeIndex: 19849 entries, 0 to 19848
Columns: 145 entries, topic.party_nl.p.pvda to topic.sub_cat_Reizen
dtypes: float16(145)
memory usage: 279.2 KB

In []: bool_df.equals(sparse_df.to_dense().astype('bool'))
Out[]: True

但是,這是一個糟糕的解決方案,因為轉換后的數據幀在與其他數據幀交互時會表現出不可預測的行為。 例如,當將轉換后的稀疏數據幀與其他數據幀連接在一起時,所有包含的序列都變為密集序列。 對於未轉換的稀疏數據幀,情況並非如此。 它們在結果數據框中保持稀疏序列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM