首页 > 解决方案 > 在数据帧切片上并行化 Pandas 的正确方法

问题描述

假设我有一个包含 N 个多值分类列的数据框,并且我想使用 Pandas 尽可能快地对它们进行编码。

这是我到目前为止所取得的成就,但不确定它是否是并行化 Pandas 的最佳方法(我希望尽可能使用矢量化方法):

def encode_single_categorical(input_series):
    encoded_categorical_feature_data_frame = input_series.str.join(
        '|').str.get_dummies().astype(
        pd.np.bool).add_prefix(
        input_series.name + '_')
    return encoded_categorical_feature_data_frame


def encode_multi_valued_categorical_features(input_data_frame, categorical_features):
    with Pool(cpu_count()) as p:
        encoded_categorical_data_frames = p.map(encode_single_categorical,
                                                [input_data_frame[categorical_feature] for
                                                 categorical_feature in categorical_features])
    return pd.concat(encoded_categorical_data_frames, axis=1)

我另外添加了一个测试,但这里的重点是方法。该解决方案在功能上有效,更多的是关于“它是 Pandas 的最佳实践吗?

def test_encode_multi_valued_categorical_features(self):
    categorical_features = ['productCategories', 'productTypes']
    input_data_frame = pd.DataFrame({'querySource': ['source1', pd.np.nan, 'source3'],
                                     'productTypes': [["t1", "t2", "t3"], ["t6", "t4", "t3"], ["t6", "t1"]],
                                     'productBrand': ['brand1', 'brand2', 'brand3'],
                                     'productCategories': [["c1", "c2", "c3"], ["c6", "c4", "c3"], ["c6", "c1"]],
                                     })
    expected_data_frame = pd.DataFrame({'querySource': ['source1', pd.np.nan, 'source3'],
                                        'productBrand': ['brand1', 'brand2', 'brand3'],
                                        'productCategories_c1': [True, False, True],
                                        'productCategories_c2': [True, False, False],
                                        'productCategories_c3': [True, True, False],
                                        'productCategories_c4': [False, True, False],
                                        'productCategories_c6': [False, True, True],
                                        'productTypes_t1': [True, False, True],
                                        'productTypes_t2': [True, False, False],
                                        'productTypes_t3': [True, True, False],
                                        'productTypes_t4': [False, True, False],
                                        'productTypes_t6': [False, True, True],
                                        })

    result = utils.encode_multi_valued_categorical_features3(input_data_frame, categorical_features)
    pd.testing.assert_frame_equal(result, expected_data_frame)

标签: pythonpandasconcurrencyvectorizationdata-science

解决方案


我建议你使用 Pandas 中内置的矢量化方法来完成,它读起来更清晰,应该更快。

下面是一列的示例,您应该能够将其转换为函数并遍历所有相关列。

# get super list of all lists in column 'productCategories'
list_all_cat = input_data_frame['productCategories'].sum()
print(list_all_cat)
> ['c1', 'c2', 'c3', 'c6', 'c4', 'c3', 'c6', 'c1']

# get unique list of productCategories
list_all_cat_unique = list(set(list_all_cat))
print(list_all_cat_unique)
> ['c4', 'c6', 'c2', 'c3', 'c1']

# loop over this unique list
for cat in list_all_cat_unique:
    # new column defaulting to False
    input_data_frame['productCategories_' + cat] = False
    # encode
    input_data_frame.loc[input_data_frame['productCategories'].apply(lambda x: cat in x) , 'productCategories_' + cat] = True
print(input_data_frame['productCategories_c4'])
> 0    False
  1     True
  2    False
  Name: productCategories_c4, dtype: bool

推荐阅读