美文网首页
2018-08-20

2018-08-20

作者: 阿呆酱的算法工程师之路 | 来源:发表于2018-08-20 11:02 被阅读52次

    大数据处理、特征工程、模型选择

    1.小内存电脑如何处理大数据

    数据加载

    对于非常大的数据,直接全部加载到内存是不可能的了,比如阿里的数据解压后10个G,这是数据都是原始数据,里面包含用户个人信息、商铺信息、广告信息、用户的搜索行为数据(其实原始文件就是这几个表拼接成的一个大表)。既然不能全部加载到内存对数据进行处理,那么我们自然可以选择分而治之的想法,将这个大表拆分成几个小表,然后分别对用户、商铺、广告和搜索行为进行特征提取,以及其他数据预处理的过程。我使用了下面的代码将大表拆分:

    user_feat = ['user_id','user_gender_id','user_age_level','user_occupation_id','user_star_level']
    reader = pd.read_csv("./data/round2_train.txt", sep="\s+",iterator=True)
    chunks = []
    loop = True
    while loop:
        try:
            chunk = reader.get_chunk(500000)[user_feat]
            chunks.append(chunk)
        except StopIteration:
            loop = False
            print("Iteration is stopped")
    df_user = pd.concat(chunks,axis=0, ignore_index=True)
    
    df_user = pd.concat(chunks,axis=0, ignore_index=True)
    df_user = pd.concat([df_user, test[user_feat]],axis=0)
    df_user.drop_duplicates(subset='user_id',keep='first',inplace=True)
    df_user.to_csv('./data/user_file.csv',index=False)
    print('user_file', df_user.shape)
    
    del df_user
    gc.collect()
    

    整个表有非常多列,非常多行,我们使用pandas的iterator=True属性迭代的读取数据块,单独将用户属性列user_feat抽取出来,每次读取500000行。这样最后我们将所有用户数据进行去重处理,然后保存。这样几千万行的用户数据就剩下几十万行了。

    其他几个小表也这样操作拆分。另外,在进行数据分析的时候,我发现店铺数据它是随着时间变化有变化的,比如同一个店铺,在不同的日子,它的shop_review_num_level, shop_review_positive_rate,shop_star_level,shop_score_service, shop_score_delivery,shop_score_description几个属性的值是变化的,所以对于店铺表进行拆分时,我们需要将日期也拆出来,去重的时候也要根据日期去重,这样才不至于丢失一些信息(其实这个发现也有助于后面的特征工程)。

    这样,在后期我们就可以分别提取特征,然后将特征文件进行拼接,训练了。

    腾讯赛

    在腾讯赛中,广告信息、用户信息、训练数据都是分开的,另外光用户数据就有16G大,全部加载到内存进行 merge操作是不可能的了,因此,我在初赛和复赛期间都是将所有数据划分成好多小份来处理、训练的(当然这也一定程度上影响了模型的性能)。怎么划分呢,因为赛题是相似用户拓展,目的是对于某个广告,根据点击过这些广告的人去的特征取找相似特征的人群。因此我选择了将所有数据按照广告的种子包(一个广告id对应一个种子包)来划分,这样最后4700多万的用户数量被分散到20几个小文件之后变成了5000多万用户(有重复的,这么多重复的用户在复赛竟然可以构造一个强特征)。按种子包拆分用户文件的代码如下:

    seed = pd.DataFrame(data['aid'].value_counts())
    seed['aid1'] = seed.index
    seed.columns = ['num','aid1']
    
    seed = seed.reset_index(drop=True)
    num_cut = []
    n = 1
    num = 0
    for i in range(seed.shape[0]):
        num += seed.loc[i,'num']
        if num > 3500000:
            num = seed.loc[i,'num']
            n += 1
        num_cut.append(n)
        
    seed['num_cut'] = num_cut
    
    aid_group = {}
    group = seed.num_cut.values
    aid = seed.aid1.values
    
    for i in range(len(aid)):
        if group[i] not in aid_group.keys():
            aid_group[group[i]] = [aid[i]]
        else:
            aid_group[group[i]].append(aid[i])
    
    pickle.dump(aid_group,open('./data/aid_group.pkl','wb'))
    
    for aid_id in aid_group.keys():
        aid_list = aid_group[aid_id]
        aid_uid = data.loc[data['aid'].isin(aid_list),'uid'].unique()
        pickle.dump(aid_uid,open('./data/aid_uid_%s.pkl' % aid_id, 'wb'))
    

    根据训练集和测试集中的广告id和用户id的对应关系,将同一个广告id对应的所有用户id保存在一起。根据用户数量确定每个文件存多少用户(代码里是350W)。

    写入磁盘

    在构造完特征,对所有文件进行拼接之后,我们可以将生产的整个训练数据保存下来,以供下次进行调参训练,这样就不需要在每次训练之前都花时间来提取特征。但是由于数据量大,提取完的训练文件更大,如何快速的、又省内存的保存到磁盘,也是需要考虑的事情。一般我习惯使用pickle模块将数据保存,但是当数据大小超过2G左右就不管用了, pickle 根本不能成功将数据 dump。而使用 csv 文件来保存的话,pd.to_csv()将数据写入磁盘的时间将非常非常长。。。所以这不是一个好选择。

    这里,我们首先给数据进行瘦身,比如将float64格式改成float16,将int64改成int16或者int8。这样节省不少内存,同时使用pd.to_csv()保存数据时,进行选择使用txt格式,而不用csv格式,这样数据IO速度快很多。

    pd.to_csv('data.txt',index=False)
    

    相关文章

      网友评论

          本文标题:2018-08-20

          本文链接:https://www.haomeiwen.com/subject/bmekiftx.html