机器学习——交叉验证实现多进程并行

一、前言

1、众所周知,python因为其全局解释器锁GIL而无法通过线程实现真正的平行计算,所以我们不用python的多线程
2、我没有用sklearn内置的机器学习库(sklearn或者xgboost可能内置了一些方便的参数,调用就可实现并行)
2、对于我这样的懒人来说,看了multiprocess模块还是嫌麻烦。
3、所以我推荐from concurrent.futures import ProcessPoolExecutor


二、有两个概念需要了解:

IO密集型:读取文件,读取网络套接字频繁。

  • 计算密集型:大量消耗CPU的数学与逻辑运算,也就是我们这里说的并行计算。

似乎IO密集型更适合用异步处理,这里我们不讨论。


三、concurrent.futures模块,可以利用multiprocessing实现真正的平行计算

核心原理是:concurrent.futures会以子进程的形式,平行的运行多个python解释器,从而令python程序可以利用多核CPU来提升执行速度。由于子进程与主解释器相分离,所以他们的全局解释器锁也是相互独立的。每个子进程都能够完整的使用一个CPU内核。


四、首先,你需要写一个能将Dataframe数据处理成可迭代的函数

(不写函数也行,你只要能拿到这个可迭代的数据就行哈哈)

什么叫可迭代的数据呢?——
比如,我处理后返回的结构是[[train_data1, validation_data1], [train_data2, validation_data2], ...],这样我通过map第一次传进的就是一个列表[train_data1, validation_data1], 我只需要for i in data, train=i[0], validation=i[1]就可以取出每次传进来的训练集和验证集了。

最后返回的数据格式是要可以迭代就好,列表,元组,字典都行,我这里用的是列表。

def mkCVData(data):
    """
    数据集划分
    :param data:    一个完整的数据集
    :return:        返回一个列表型的datarfame
    """
    k = 4  # k折
    k_sample_count = data.shape[0] // k  # 每折多少行数据(这里使用整除)

    # 新建一个列表用于装载dataframe
    data_set = []

    # 根据k折,划分数据集
    from tqdm import tqdm
    for fold in tqdm(range(k)):
        print(f"第{fold}折")  # f 代表format

        validation_begin = k_sample_count * fold
        validation_end = k_sample_count * (fold + 1)

        validation_data = data[validation_begin:validation_end]

        # pd.concat 沿着垂直的方向堆叠数据,拼接得到训练集
        train_data = pd.concat([
            data[:validation_begin],
            data[validation_end:]
        ])

        # 重新索引train_data和validation_data
        train_data.index = np.arange(len(train_data))
        validation_data.index = np.arange(len(validation_data))

        data_set.append(([train_data, validation_data]))

    return list(data_set)

五、主函数多进程代码

if __name__ == '__main__':

    # pandas读取
    tmp_data  = pd.read_csv("label.csv", index_col=[0])

    # 打乱数据集
    from sklearn import utils
    tmp_data = utils.shuffle(tmp_data)
    # 数据集划分
    tmp_data = mkCVData(tmp_data)

    # 记录时间和进程池
    start_time = time.time()
    pool = ppExe(max_workers=4)

    # 设置一个交叉验证得分列表
    crossVal_list = []
    crossVal_list.extend(list(pool.map(crossVal, tmp_data)))# 这里是extend还是append取决于你的评估分数是什么结构

    # 记录结束时间,计算过程时间
    end_time = time.time()
    ti = end_time - start_time
    print(f"过程花费时间={ti//60}分{ti%60}秒")

参考博文:
《机器学习并行化(parallel machine learning)》
《python concurrent.futures》
《三行Python代码,可以让你的数据处理快别人4倍》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章