如何向下转换整数多索引级别


  1. 我有一个大型MultiIndex系列的字典,其中两个索引级别都是日期时间值。其中一个抽象的简短例子是:
idx_level_0 = pd.date_range('2020-01-01', '2020-04-01', freq = 'M')
idx_level_1 = pd.date_range('2020-04-01', '2020-07-01', freq = 'M')
idx_dates = pd.MultiIndex.from_product([idx_level_0, idx_level_1], names = ['Event_Date', 'Observation_Date'])
ser_info_dated = pd.Series(range(len(idx_level_0) * len(idx_level_1)), index = idx_dates, name = 'Some_Values') / 33
  1. 我需要保存所有数据,所以我选择将每个系列分别导入到通用的HDF5文件中,并将字典键作为hdf键。当我按原样保存时,我的文件卷大约为4 Gb,所以我正在努力使其更薄。此外,我还需要处理整个索引中的所有序列数据,所以我需要一些全局识别方法。我的想法是从所有系列的两个级别共同收集日期(大约有11000个唯一日期(,并将其替换为唯一的数字标识符,以便有机会恢复所有系列的原始索引。但只有当我可以将数值转换为int16类型时,它才有意义。所以我尝试了这样一个序列(在这里我将其简化为单个序列(:
list_levels_dates = sorted(list(set(idx_level_0) | set(idx_level_1)))
dict_to_numbers = dict(zip(list_levels_dates, range(len(list_levels_dates))))
df_info_numbered = ser_info_dated.reset_index().replace({'Event_Date': dict_to_numbers, 'Observation_Date': dict_to_numbers})
df_info_downcasted = df_info_numbered.copy()
df_info_downcasted[['Event_Date', 'Observation_Date']] = df_info_downcasted[['Event_Date', 'Observation_Date']].astype('int16')

它看起来很成功:

print('df_info_downcasted column types:n', df_info_downcasted.dtypes)

显示了这样一个结果:

df_info_downcasted column types:
Event_Date            int16
Observation_Date      int16
Some_Values         float64
  1. 但当我将列移回索引级别时,它再次变为int64:
ser_info_downcasted = df_info_downcasted.set_index(['Event_Date', 'Observation_Date']).squeeze()
print('ser_info_downcasted index level 0 type: ', ser_info_downcasted.index.levels[0].dtype)
print('ser_info_downcasted index level 1 type: ', ser_info_downcasted.index.levels[1].dtype)
ser_info_downcasted index level 0 type:  int64
ser_info_downcasted index level 1 type:  int64
  1. 我尝试了其他操作,但也失败了:
ser_info_astyped = ser_info_downcasted.copy()
ser_info_astyped.index = ser_info_astyped.index.set_levels(ser_info_astyped.index.levels[0].astype('int16'), level = 0)
ser_info_astyped.index = ser_info_astyped.index.set_levels(ser_info_astyped.index.levels[1].astype('int16'), level = 1)
print('ser_info_astyped index level 0 type: ', ser_info_astyped.index.levels[0].dtype)
print('ser_info_astyped index level 1 type: ', ser_info_astyped.index.levels[1].dtype)
ser_info_astyped index level 0 type:  int64
ser_info_astyped index level 1 type:  int64
  1. 所以我非常需要一个如何将整数类型显式转换为较短类型的建议,或者如何缩短系列体积的替代建议。我还试图将所有系列附加到一个巨大的系列中,但这会引发内存错误

TL;DR:Pandas将索引转换为64字节值,最小化文件的最佳机会是使用HDF序列化。

Pandas似乎不支持int16数据类型作为索引。

Int64Index是大熊猫的一个基本指标。这是一个实现有序、可切片集的不可变数组。

pandas.Index.astype进一步强化了这一点。

请注意,任何有符号整数dtype都被视为'int64',任何无符号整数dtype都被处理为'uint64',无论大小如何。

因此,本质上,当设置为索引时,我们的int16值被强制转换为int64。我以前没有使用过HDF5,但我试着看看可以做些什么来最小化文件大小。

查看内存分配

>>> print(ser_info_dated)
... Event_Date  Observation_Date
... 2020-01-31  2020-04-30          0.000000
...             2020-05-31          0.030303
...             2020-06-30          0.060606
... 2020-02-29  2020-04-30          0.090909
...             2020-05-31          0.121212
...             2020-06-30          0.151515
... 2020-03-31  2020-04-30          0.181818
...             2020-05-31          0.212121
...             2020-06-30          0.242424
>>> print(ser_info_dated.memory_usage(index=True, deep=True))
... 478 # memory usage in bytes

>>> print(df_info_downcasted)
...    Event_Date  Observation_Date  Some_Values
... 0           0                 3     0.000000
... 1           0                 4     0.030303
... 2           0                 5     0.060606
... 3           1                 3     0.090909
... 4           1                 4     0.121212
... 5           1                 5     0.151515
... 6           2                 3     0.181818
... 7           2                 4     0.212121
... 8           2                 5     0.242424
>>> print(df_info_downcasted.memory_usage(index=True, deep=True))
... Index               128
... Event_Date           18
... Observation_Date     18
... Some_Values          72
... dtype: int64
>>> print(df_info_downcasted.info())
... <class 'pandas.core.frame.DataFrame'>
... RangeIndex: 9 entries, 0 to 8
... Data columns (total 3 columns):
...  #   Column            Non-Null Count  Dtype  
... ---  ------            --------------  -----  
...  0   Event_Date        9 non-null      int16  
...  1   Observation_Date  9 non-null      int16  
...  2   Some_Values       9 non-null      float64
... dtypes: float64(1), int16(2)
... memory usage: 236.0 bytes

我们可以看到,大部分内存都用在了索引中。当保存为HDF5时,这似乎并不重要。(出于测试目的,我将范围增加为12H(

>>> ser_info_dated.to_hdf("ser.h5", "ser")
>>> print(f"{os.path.getsize('ser.h5')/1000} kb")
... 412.628 kb

>>> down_set_hdf5 = df_info_downcasted.to_hdf("down.h5", "down")
>>> print(f"{os.path.getsize('down.h5')/1000} kb")
... 413.204 kb

我不知道如何保存HDF5文件,但在Pandas中有一个压缩参数complevel,它可能很有用。

>>> ser_hdf5 = ser_info_dated.to_hdf("ser.h5", "ser", complevel=9)
>>> print(f"{os.path.getsize('ser.h5')/1000} kb")
... 155.452 kb

相关内容

  • 没有找到相关文章