Python Pandas - 稀疏数据
Pandas - 稀疏数据结构
Section titled “Pandas - 稀疏数据结构”在许多数据集中,很大一部分数据可能由单个常数值组成(通常是 0 或 NaN/缺失值)。使用标准(密集 dense)结构(如 NumPy 数组或常规 Pandas Series/DataFrame)存储这些数据集在内存方面效率较低。
Pandas 提供了专门设计用于提高内存效率的稀疏数据结构(Sparse Data Structures),特别是在数据主要由特定“填充值”(fill value)构成时。稀疏结构不是存储每个值,而是只存储非填充值及其位置。
现代 Pandas 通过 SparseDtype 扩展类型实现稀疏性。通常通过指定此 dtype 来创建稀疏 Series 或 DataFrame。
使用 SparseDtype 创建稀疏数据
Section titled “使用 SparseDtype 创建稀疏数据”您可以通过提供 dtype=pd.SparseDtype(type, fill_value) 来创建一个稀疏 Series。
type:非稀疏值的数据类型(例如float、int、bool)。fill_value:被视为“稀疏”且未显式存储的值。默认值取决于type(例如,float为np.nan,int为0,bool为False)。
import pandas as pdimport numpy as np
# 创建一个包含许多 NaN 的密集 Seriesdense_series = pd.Series(np.random.randn(10))dense_series[2:-2] = np.nan # 使大部分值为 NaNprint("Dense Series:")print(dense_series)print(f"内存使用(密集):{dense_series.memory_usage(deep=True)} bytes")
# 创建稀疏版本sparse_dtype = pd.SparseDtype(float, np.nan) # float 类型,NaN 是填充值sparse_series = dense_series.astype(sparse_dtype)
print("\nSparse Series:")print(sparse_series)print(f"内存使用(稀疏):{sparse_series.memory_usage(deep=True)} bytes")输出(内存使用量可能因系统/版本略有差异):
Dense Series:0 0.5156311 -1.1422572 NaN3 NaN4 NaN5 NaN6 NaN7 NaN8 0.6319749 0.107211dtype: float64Memory usage (dense): 208 bytes
Sparse Series:0 0.5156311 -1.1422572 NaN3 NaN4 NaN5 NaN6 NaN7 NaN8 0.6319749 0.107211dtype: Sparse[float64, nan]Memory usage (sparse): 112 bytes注意,稀疏 Series 打印出来时看起来与密集 Series 相同,但其 dtype 表示它是稀疏的,并且由于未显式存储每个位置的 NaN 值,其内存使用量显着降低。
稀疏属性和方法
Section titled “稀疏属性和方法”.sparse.density 属性显示非填充值所占的比例。
print(f"\n稀疏 Series 的密度:{sparse_series.sparse.density:.2f}")输出:
Density of sparse series: 0.40这表示 40% 的值是非 NaN。
转换回密集格式
Section titled “转换回密集格式”您可以使用 .sparse.to_dense() 或 .astype() 并指定非稀疏 dtype,将稀疏 Series 或 DataFrame 转换回其密集(dense)表示形式。
# 使用 .sparse.to_dense() 转换回密集格式dense_again = sparse_series.sparse.to_dense()
print("\n转换回密集格式:")print(dense_again)print(f"内存使用(再次密集):{dense_again.memory_usage(deep=True)} bytes")输出:
Converted back to dense:0 0.5156311 -1.1422572 NaN3 NaN4 NaN5 NaN6 NaN7 NaN8 0.6319749 0.107211dtype: float64Memory usage (dense again): 208 bytes稀疏 DataFrame 示例
Section titled “稀疏 DataFrame 示例”稀疏性也可以应用于 DataFrame,可以按列应用,也可以在适当情况下应用于整个 DataFrame。
import pandas as pdimport numpy as np
# 创建一个包含许多零的密集 DataFramedense_df = pd.DataFrame(np.random.randint(0, 2, size=(1000, 4)) * np.random.randint(0, 10, size=(1000,4)))dense_df.iloc[10:] = 0 # 使大部分值为零
print(f"内存(密集 DF):{dense_df.memory_usage(deep=True).sum()} bytes")
# 转换为稀疏格式(int dtype, fill_value=0)sparse_df = dense_df.astype(pd.SparseDtype('int', 0))
print(f"内存(稀疏 DF):{sparse_df.memory_usage(deep=True).sum()} bytes")print(f"密度(稀疏 DF):{sparse_df.sparse.density:.4f}")#print("\n稀疏 DataFrame 示例:")#print(sparse_df.head(15)) # 显示头部数据可以看到结构输出(内存/密度可能略有差异):
Memory (dense DF): 32128 bytesMemory (sparse DF): 1560 bytesDensity (sparse DF): 0.0093对于具有高稀疏度的大型数据集,内存节省可能非常可观。
SparseDtype 的填充值
Section titled “SparseDtype 的填充值”SparseDtype 的默认 fill_value 取决于底层数据类型:
float:np.nanint:0bool:Falsedatetime64[ns]:pd.NaT(非时间 Not a Time)timedelta64[ns]:pd.NaT
您可以根据需要显式指定不同的 fill_value,但通常使用默认值。
# 示例:fill_value = 1 的稀疏 Seriess_fill_one = pd.Series([1, 2, 1, 3, 1, 1], dtype=pd.SparseDtype(int, 1))print("\nfill_value=1 的稀疏 Series:")print(s_fill_one)print(f"密度:{s_fill_one.sparse.density:.2f}") # 只有 2 和 3 是非填充值输出:
Sparse series with fill_value=1:0 11 22 13 34 15 1dtype: Sparse[int64, 1]Density: 0.33稀疏数据结构在机器学习(例如,处理表示为词袋或 TF-IDF 矩阵的文本数据)和科学计算等领域特别有用,这些领域中大型稀疏矩阵很常见。