这至少需要 pandas 0.15.0; (不过 .astype 语法在 0.16.0 中更友好一些,所以最好使用它)。这里是docs for categoricals
进口
In [101]: import pandas as pd
In [102]: import string
In [103]: import numpy as np
In [104]: np.random.seed(1234)
In [105]: pd.set_option('max_rows',10)
创建一个样本集来创建一些数据
In [106]: uniques = np.array(list(string.ascii_letters))
In [107]: len(uniques)
Out[107]: 52
创建一些数据
In [109]: df1 = pd.DataFrame({'A' : uniques.take(np.random.randint(0,len(uniques)/2+5,size=1000000))})
In [110]: df1.head()
Out[110]:
A
0 p
1 t
2 g
3 v
4 m
In [111]: df1.A.nunique()
Out[111]: 31
In [112]: df2 = pd.DataFrame({'A' : uniques.take(np.random.randint(0,len(uniques),size=1000000))})
In [113]: df2.head()
Out[113]:
A
0 I
1 j
2 b
3 A
4 m
In [114]: df2.A.nunique()
Out[114]: 52
所以我们现在有 2 个要分类的帧;第一帧恰好没有完整的类别集。这是故意的;您不必预先知道完整的设置。
将 A 列转换为属于 Categorical 的 B 列
In [116]: df1['B'] = df1['A'].astype('category')
In [118]: i = df1['B'].cat.categories
In [124]: i
Out[124]: Index([u'A', u'B', u'C', u'D', u'E', u'a', u'b', u'c', u'd', u'e', u'f', u'g', u'h', u'i', u'j', u'k', u'l', u'm', u'n', u'o', u'p', u'q', u'r', u's', u't', u'u', u'v', u'w', u'x', u'y', u'z'], dtype='object')
如果我们迭代处理这些帧,我们会使用第一个开始。为了获得每个连续的,我们将对称差与现有集合相加。这使类别保持相同的顺序,因此当我们分解时,我们会得到相同的编号方案。
In [119]: cats = i.tolist() + i.sym_diff(df2['A'].astype('category').cat.categories).tolist()
我们现在已经找回了原来的集合
In [120]: (np.array(sorted(cats)) == sorted(uniques)).all()
Out[120]: True
将下一帧 B 列设置为分类,但我们指定类别,因此在分解时使用相同的值
In [121]: df2['B'] = df2['A'].astype('category',categories=cats)
为了证明这一点,我们从每个代码中选择代码(分解后的映射)。这些代码匹配; df2 有一个附加代码(因为 Z 在第二帧而不是第一帧)。
In [122]: df1[df1['B'].isin(['A','a','z','Z'])].B.cat.codes.unique()
Out[122]: array([30, 0, 5])
In [123]: df2[df2['B'].isin(['A','a','z','Z'])].B.cat.codes.unique()
Out[123]: array([ 0, 30, 5, 51])
然后您可以简单地存储代码来代替对象 dtyped 数据。
请注意,将这些序列化为 HDF5 实际上非常有效,因为分类是本机存储的,请参阅 here
请注意,我们正在创建一种非常节省内存的方式来存储这些数据。注意 [154] 中的内存使用情况,object dtype 实际上越高,字符串越长,因为这只是指针的内存;实际值存储在堆上。而 [155] 是所有已使用的内存。
In [153]: df2.dtypes
Out[153]:
A object
B category
dtype: object
In [154]: df2.A.to_frame().memory_usage()
Out[154]:
A 8000000
dtype: int64
In [155]: df2.B.to_frame().memory_usage()
Out[155]:
B 1000416
dtype: int64