我想使用rank-hot编码而不是one-hot编码来处理pandas数据框。
例如,这里有一个pandas数据框:
df = pd.DataFrame([[1,2],[3,2],[2,2]], columns=['colA', 'colB'])print(df)>> colA colB0 1 21 3 02 2 3
最终应该呈现的形式是:
print(df)>> colA_0 colA_1 colA_2 colA_3 colB_0 colB_1 colB_2 colB_30 1 1 0 0 1 1 1 01 1 1 1 1 1 0 0 02 1 1 1 0 1 1 1 1
这个方法在小数据框上是有效的:
def rankHotEncode(row): newFeatures = {} for i, v in row.iteritems(): for k in range(MULTIPLYFEATURES): newFeatures[i + repr(k)] = 1 if v >= k else 0 return pd.Series(newFeatures)df.apply(rankHotEncode, axis=1)
解决方案不应该硬编码,并且对于大约10万行的数据要高效。我如何改进提供的解决方案以使其更有效,或者有什么最好的方法来实现这一点?
回答:
你可以使用scikit-learn的oneHotEncoder
和numpy.cumsum
。虽然这涉及到一些复制操作,但它相当高效,因为它不是逐行处理矩阵。以下是使用它的示例代码。
from sklearn.preprocessing import OneHotEncoderimport pandas as pdimport numpy as npdf = pd.DataFrame([[1,2],[3,0],[2,3]], columns=['colA', 'colB'])print(df)n_values = df.max().values + 1enc = OneHotEncoder(sparse=False, n_values=n_values, dtype=int)enc.fit(df) encoded_columns = [ '{}_{}'.format(col_name, i) for col_name, n_value in zip(df.columns, n_values) for i in range(n_value)]one_hot = enc.transform(df)rank_hot = np.zeros_like(one_hot)for col_start, col_end in zip(enc.feature_indices_[:-1], enc.feature_indices_[1:]): one_hot_col_reversed = one_hot[:, col_start: col_end][:, ::-1] rank_hot[:, col_start: col_end] = np.cumsum(one_hot_col_reversed, axis=1)[:, ::-1]encoded_df = pd.DataFrame(rank_hot, columns=encoded_columns)
对于你的示例,它的输出是
print(encoded_df)>> colA_0 colA_1 colA_2 colA_3 colB_0 colB_1 colB_2 colB_30 1 1 0 0 1 1 1 01 1 1 1 1 1 0 0 02 1 1 1 0 1 1 1 1