Pandas 相似度计算中的有序变量处理
Pandas Ordinal Variable Treatment in Similarity Calculation
我有一个 Pandas 版本 0.15.2 数据框,如下所示,其中有一个序数列 rate
,最初表示为字符串。我的最终目标是找到 df
中不同行的相似性(实际上我有更多的行和更多的序数变量)。
目前,到factorize() while enforcing the ordering I want, I first convert rate
to Categorical,然后对df
进行排序,最后进行因式分解,使Bad
得到最小的整数值,Good
得到最大的整数值。以这种方式,我创建了 factor_rate
列,然后我可以将其用作维度(以及其他维度)来计算相似性/距离。这些在下面的代码中给出。
但是,我觉得这是一种内存效率低且速度慢的 hack。实现此目标最快、内存效率最高的方法是什么?
df = pd.DataFrame({'id' : range(1,9),
'rate' : ['bad', 'bad', 'neutral', 'good',
'neutral', 'good', 'bad', 'neutral'],
'amount' : np.random.randn(8)}, columns= ['id','rate','amount'])
df.rate = pd.Categorical(df.rate, categories=["bad","neutral","good"], ordered=True)
df = df.sort('rate', ascending=True)
df.loc[:,'factor_rate'] = pd.factorize(df.rate)[0]
注1:这个问题和我之前的one有关。
注意 2:我知道 pandas.factorize()
有一个 order
参数现在或即将被弃用,所以我不能直接使用它。
注释 3:我知道 Gower 度量并且在相似性计算中序数变量应该与纯数字变量区别对待,但这不是我的问题的重点.
如果您担心或依赖分类,那么另一种方法是在列表和顺序中定义您的类别,使用它来创建一个字典以将顺序映射到类别并将此字典传递给 map
:
In [560]:
df = pd.DataFrame({'id' : range(1,9),
'rate' : ['bad', 'bad', 'neutral', 'good',
'neutral', 'good', 'bad', 'neutral'],
'amount' : np.random.randn(8)}, columns= ['id','rate','amount'])
cat_list = ["bad","neutral","good"]
cat_dict = dict(zip(cat_list, np.arange(len(cat_list))))
df['factor_rate'] = df['rate'].map(cat_dict)
df
Out[560]:
id rate amount factor_rate
0 1 bad -1.436574 0
1 2 bad 0.210717 0
2 3 neutral -0.896904 1
3 4 good -1.724393 2
4 5 neutral 1.792339 1
5 6 good -1.312713 2
6 7 bad 0.555877 0
7 8 neutral -0.681881 1
按新的 'factor_rate' 列排序产生与当前解决方案相同的输出:
In [562]:
df.sort('factor_rate')
Out[562]:
id rate amount factor_rate
0 1 bad -1.436574 0
1 2 bad 0.210717 0
6 7 bad 0.555877 0
2 3 neutral -0.896904 1
4 5 neutral 1.792339 1
7 8 neutral -0.681881 1
3 4 good -1.724393 2
5 6 good -1.312713 2
编辑
实际上底层编码存储在类别数据类型中:
In [569]:
df = pd.DataFrame({'id' : range(1,9),
'rate' : ['bad', 'bad', 'neutral', 'good',
'neutral', 'good', 'bad', 'neutral'],
'amount' : np.random.randn(8)}, columns= ['id','rate','amount'])
df['rate'] = pd.Categorical(df.rate, categories=["bad","neutral","good"], ordered=True)
df['rate'].cat.codes
Out[569]:
0 0
1 0
2 1
3 2
4 1
5 2
6 0
7 1
dtype: int8
所以我的回答可能没有必要,link到docs目前是空的。
我有一个 Pandas 版本 0.15.2 数据框,如下所示,其中有一个序数列 rate
,最初表示为字符串。我的最终目标是找到 df
中不同行的相似性(实际上我有更多的行和更多的序数变量)。
目前,到factorize() while enforcing the ordering I want, I first convert rate
to Categorical,然后对df
进行排序,最后进行因式分解,使Bad
得到最小的整数值,Good
得到最大的整数值。以这种方式,我创建了 factor_rate
列,然后我可以将其用作维度(以及其他维度)来计算相似性/距离。这些在下面的代码中给出。
但是,我觉得这是一种内存效率低且速度慢的 hack。实现此目标最快、内存效率最高的方法是什么?
df = pd.DataFrame({'id' : range(1,9),
'rate' : ['bad', 'bad', 'neutral', 'good',
'neutral', 'good', 'bad', 'neutral'],
'amount' : np.random.randn(8)}, columns= ['id','rate','amount'])
df.rate = pd.Categorical(df.rate, categories=["bad","neutral","good"], ordered=True)
df = df.sort('rate', ascending=True)
df.loc[:,'factor_rate'] = pd.factorize(df.rate)[0]
注1:这个问题和我之前的one有关。
注意 2:我知道 pandas.factorize()
有一个 order
参数现在或即将被弃用,所以我不能直接使用它。
注释 3:我知道 Gower 度量并且在相似性计算中序数变量应该与纯数字变量区别对待,但这不是我的问题的重点.
如果您担心或依赖分类,那么另一种方法是在列表和顺序中定义您的类别,使用它来创建一个字典以将顺序映射到类别并将此字典传递给 map
:
In [560]:
df = pd.DataFrame({'id' : range(1,9),
'rate' : ['bad', 'bad', 'neutral', 'good',
'neutral', 'good', 'bad', 'neutral'],
'amount' : np.random.randn(8)}, columns= ['id','rate','amount'])
cat_list = ["bad","neutral","good"]
cat_dict = dict(zip(cat_list, np.arange(len(cat_list))))
df['factor_rate'] = df['rate'].map(cat_dict)
df
Out[560]:
id rate amount factor_rate
0 1 bad -1.436574 0
1 2 bad 0.210717 0
2 3 neutral -0.896904 1
3 4 good -1.724393 2
4 5 neutral 1.792339 1
5 6 good -1.312713 2
6 7 bad 0.555877 0
7 8 neutral -0.681881 1
按新的 'factor_rate' 列排序产生与当前解决方案相同的输出:
In [562]:
df.sort('factor_rate')
Out[562]:
id rate amount factor_rate
0 1 bad -1.436574 0
1 2 bad 0.210717 0
6 7 bad 0.555877 0
2 3 neutral -0.896904 1
4 5 neutral 1.792339 1
7 8 neutral -0.681881 1
3 4 good -1.724393 2
5 6 good -1.312713 2
编辑
实际上底层编码存储在类别数据类型中:
In [569]:
df = pd.DataFrame({'id' : range(1,9),
'rate' : ['bad', 'bad', 'neutral', 'good',
'neutral', 'good', 'bad', 'neutral'],
'amount' : np.random.randn(8)}, columns= ['id','rate','amount'])
df['rate'] = pd.Categorical(df.rate, categories=["bad","neutral","good"], ordered=True)
df['rate'].cat.codes
Out[569]:
0 0
1 0
2 1
3 2
4 1
5 2
6 0
7 1
dtype: int8
所以我的回答可能没有必要,link到docs目前是空的。