天池新人赛——快来一起挖掘幸福感!

Posted ase265

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了天池新人赛——快来一起挖掘幸福感!相关的知识,希望对你有一定的参考价值。

赛题使用公开数据的问卷调查结果,选取其中多组变量
包括个体变量(性别、年龄、地域、职业、健康、婚姻与政治面貌等等)
家庭变量(父母、配偶、子女、家庭资本等等)
社会态度(公平、信用、公共服务等等)
来预测其对幸福感的评价

前期处理

将提供的训练数据的幸福度标签独立出来,并将除了幸福度标签的训练数据和待测试的数据合并
这样就省去既要处理训练数据又要处理测试数据的冗余,一次解决

df_train = pd.read_csv("happiness_train_complete.csv",encoding="ansi")
df_test = pd.read_csv("happiness_test_complete.csv",encoding="ansi")
y_train = df_train['happiness']
df_train.drop(["happiness"],axis=1,inplace=True)
df_all = pd.concat((df_train,df_test),axis=0)

查看幸福度标签的分布情况:
技术图片

其中-8指无法回答,也就意味着不知道自己是幸福或者还是不幸福
因此,将其当做幸福度的中间值来处理

y_train = y_train.map(lambda x:3 if x==-8 else x)

然后统计各个属性的缺失情况

total = df_all.isnull().sum().sort_values(ascending=False)
percent = (df_all.isnull().sum()/df_all.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total,percent], axis=1, keys=['total', 'percent'])
missing_data[missing_data['percent']>0]

前期处理完成

数据预处理

数据预处理的措施:删除缺失过多的属性;对缺失少的属性进行填充
删除缺失值高达60%的属性:
df_all.drop( [‘edu_other‘,‘invest_other‘,‘property_other‘,‘join_party‘,
‘s_work_type‘,‘s_work_status‘,‘work_status‘,
‘work_yr‘,‘work_manage‘,‘work_type‘,],axis=1,inplace=True)
然后在对缺失值低于60%的值进行填充

#配偶情况
#全部缺失值填充为0 因为这些缺失值是因为没有结婚而导致的
df_all['s_political'].fillna(0,inplace=True)
df_all['s_hukou'].fillna(0,inplace=True)
df_all['s_income'].fillna(0,inplace=True)
df_all['s_birth'].fillna(0,inplace=True)
df_all['s_edu'].fillna(0,inplace=True)     
df_all['s_work_exper'].fillna(0,inplace=True)

#教育情况 
#全部缺失值填充为0 由没有受过教育而导致的
df_all['edu_status'].fillna(0,inplace=True)
df_all['edu_yr'].fillna(0,inplace=True)

#社交情况
#缺失值是由于社交不频繁造成的,全部缺失值填充为7
df_all['social_friend'].fillna(7,inplace=True)
df_all['social_neighbor'].fillna(7,inplace=True)

# 婚姻情况
df_all['marital_now'].fillna(2015,inplace=True) 
df_all['marital_1st'].fillna(2015,inplace=True)

# 家庭收入
#family_income只有一条空记录,用平均值填充
df_all['family_income'].fillna(df_all['family_income'].mean(),inplace=True)

# 户口情况 缺失值是由于没有户口造成的,全部缺失值填充为4
df_all['hukou_loc'].fillna(4,inplace=True)
#孩子情况 全部填充为0,因为没有孩子
df_all['minor_child'].fillna(0,inplace=True)
print(len(df_all))

特征工程

对一些分布不均匀或者相关性较差的属性删除,并同时构造一些新特征
先删除一些特征,这些特征分布及其不均匀且相关性也差
宗教不均匀

sns.countplot(x='religion', data=df_all)
df_all.drop(['religion','religion_freq'],axis=1,inplace=True)

房产不均匀,只保留property_1和property_2

df_all.drop(['property_0','property_3','property_4','property_5',
            'property_6','property_7','property_8'],axis=1,inplace=True)

保险不均匀 全都删除

df_all.drop(['insur_1','insur_2','insur_3','insur_4'],axis=1,inplace=True)

基本没人投资 全部删除

df_all.drop(['invest_0','invest_1','invest_2','invest_3','invest_4',
         'invest_5'],axis=1,inplace=True)

删除父母亲的政治面貌

df_all.drop(['f_political','m_political'],axis=1,inplace=True)

根据现有属性,构造一些新特征,或者对属性进行泛化
对所处阶层的负值进行替换

df_all['class'] = df_all['class'].map(lambda x:5 if x==-8 else x)

按照小学,初中,高中等常见教育等级进行划分
因为所给数据的教育等级粒度太细,故进一步泛化

def edu_split(x):
if x in [1,2,14]:
    return 0
elif x in [3]:
    return 1
elif x in [4]:
    return 2
elif x in [5,7,8]:
    return 3
elif x in [6]:
    return 4
elif x in [9,10]:
    return 5
elif x in [11,12]:
    return 6
elif x in[13]:
    return 7
df_all["edu"]=df_all["edu"].map(edu_split)

因为不同的时间会有不同的感受
故把一天的时间分段

def hour_cut(x):
    if 0<=x<6:
        return 0
    elif  6<=x<8:
        return 1
    elif  8<=x<12:
        return 2
    elif  12<=x<14:
        return 3
    elif  14<=x<18:
        return 4
    elif  18<=x<21:
        return 5
    elif  21<=x<24:
        return 6
df_all["hour_cut"]=df_all["hour"].map(hour_cut)

出生年代划分

def birth_split(x):
    if(x<1920):
        return 0
    if 1920<=x<=1930:
        return 1
    elif  1930<x<=1940:
        return 2
    elif  1940<x<=1950:
        return 3
    elif  1950<x<=1960:
        return 4
    elif  1960<x<=1970:
        return 5
    elif  1970<x<=1980:
        return 6
    elif  1980<x<=1990:
        return 7
    elif  1990<x<=2000:
        return 8
df_all["birth_s"]=df_all["birth"].map(birth_split)

构造新特征 BMI 人体肥胖指数
并对新特征进行分类

def  get_fat(x):
    if(x<0):
        return 1
    elif(x>0 and x<18.5):
        return 1
    elif(x>=18.5 and x<=23.9):
        return 2 
    elif(x>=24 and x<=26.9):
        return 3
    elif(x>26.9 and x<29.9):
        return 4
    else:
        return 5
df_all['bmi]= df_all['weight_jin']/2)/(df_all['height_cm']/100)**2
df_all["fat"] = df_all["bmi"].map(get_fat)

对收入进行分级 按照2015的标准
收入分级

def get_income_class(x):
    if(x<=0):
        return 0
    if 0< x < 2800:
        return  1
    elif 2800<= x <10000:
        return 2
    elif 10000 <= x <27000:
        return 3
    elif 27000<= x <100000:
        return 4
    else : return 5

对省份进行分级

def province_split(x):
    if x in [6,1,12,28,13]:
        return 0
    elif x in [24,29,26,2,8,22,21]:
        return 1
    elif x in [16,31]:
        return 2
    elif x in [9,7,15,11,18,30,27,19]:
        return 3
    elif x in [23,5,10,4,3,17,4]:
        return 4

数据规范化

# 使用z-score方法 对数量值数据进行规范化 
numeric_cols=['height_cm','s_income','house','family_income','family_m'
            ,'son','daughter','minor_child','inc_exp','public_service_1',
            'public_service_2','public_service_3','public_service_4',
            'public_service_5','public_service_6','public_service_7',
            'public_service_8','public_service_9','aver_area','mar_yr']
# 再对标称数据进行规范化
numeric_cols_means=df_all.loc[:,numeric_cols].mean()
numeric_cols_std=df_all.loc[:,numeric_cols].std()
df_numeric=(df_all.loc[:,numeric_cols]-numeric_cols_means)/numeric_cols_std

算法融合

使用lgb和xgbootst进行融合

#lgb的参数设定
param = {'boosting_type': 'gbdt',
    'num_leaves': 20,
    'min_data_in_leaf': 19, 
    'objective':'regression',
    'max_depth':9,
    'learning_rate': 0.01,
    "min_child_samples": 30,
    
    "feature_fraction": 0.91,
    "bagging_freq": 1,
    "bagging_fraction": 0.75,
    "bagging_seed": 11,
    "metric": 'mse',
    "lambda_l1": 0.15,
    "verbosity": -1}

# xgb的参数设定    
xgb_params = {"booster":'gbtree','eta': 0.01, 'max_depth': 5, 'subsample': 0.7, 
          'colsample_bytree': 0.6, 'objective': 'reg:linear', 'eval_metric': 'rmse',
           'silent': True, 'nthread': 8}

#采用stacking 融合lgb和xgb这两个模型
train_stack = np.vstack([oof_lgb,oof_xgb]).transpose()
test_stack = np.vstack([predictions_lgb,predictions_xgb]).transpose()
folds_stack = RepeatedKFold(n_splits=5, n_repeats=2, random_state=2018)
oof_stack = np.zeros(train_stack.shape[0])
predictions = np.zeros(test_stack.shape[0])
for fold_, (trn_idx, val_idx) in enumerate(folds_stack.split(train_stack,y_train)):
    print("fold {}".format(fold_))
    trn_data, trn_y = train_stack[trn_idx], y_train[trn_idx]
    val_data, val_y = train_stack[val_idx], y_train[val_idx]
    
    clf_3 = linear_model.BayesianRidge()
    #clf_3 =linear_model.Ridge()
    clf_3.fit(trn_data, trn_y)
    
    oof_stack[val_idx] = clf_3.predict(val_data)
    predictions += clf_3.predict(test_stack) / 10

结果和代码

技术图片
模型融合后,训练score是0.45887818
线上0.46316
代码见github

以上是关于天池新人赛——快来一起挖掘幸福感!的主要内容,如果未能解决你的问题,请参考以下文章

天池nlp文本分类新人赛 Task.1md

天池新人实战赛之[离线赛]-指数加权平均

天池nlp新人赛_task2:数据预处理改进和一些思路

天池算法赛:数据挖掘经典赛事!DCIC 2020 数字中国创新大赛启动!

阿里云天池 学习赛汇总(教学赛,零基础入门,长期赛)

pandas如何去掉时间列的小时只保留日期