本文根据阿里天池学习赛《快来一块儿挖掘幸福感!》撰写python
加载的是完整版的数据 happiness_train_complete.csv
。算法
import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import seaborn as sns sns.set_style('whitegrid')
# 将 id 列做为 DataFrame 的 index 而且指定 survey_time 为时间序列 data_origin = pd.read_csv('./data/happiness_train_complete.csv', index_col='id', parse_dates=['survey_time'], encoding='gbk')
下面简单输出前5行查看。api
data_origin.head()
happiness | survey_type | province | city | county | survey_time | gender | birth | nationality | religion | ... | neighbor_familiarity | 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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | |||||||||||||||||||||
1 | 4 | 1 | 12 | 32 | 59 | 2015-08-04 14:18:00 | 1 | 1959 | 1 | 1 | ... | 4 | 50 | 60 | 50 | 50 | 30.0 | 30 | 50 | 50 | 50 |
2 | 4 | 2 | 18 | 52 | 85 | 2015-07-21 15:04:00 | 1 | 1992 | 1 | 1 | ... | 3 | 90 | 70 | 70 | 80 | 85.0 | 70 | 90 | 60 | 60 |
3 | 4 | 2 | 29 | 83 | 126 | 2015-07-21 13:24:00 | 2 | 1967 | 1 | 0 | ... | 4 | 90 | 80 | 75 | 79 | 80.0 | 90 | 90 | 90 | 75 |
4 | 5 | 2 | 10 | 28 | 51 | 2015-07-25 17:33:00 | 2 | 1943 | 1 | 1 | ... | 3 | 100 | 90 | 70 | 80 | 80.0 | 90 | 90 | 80 | 80 |
5 | 4 | 1 | 7 | 18 | 36 | 2015-08-10 09:50:00 | 2 | 1994 | 1 | 1 | ... | 2 | 50 | 50 | 50 | 50 | 50.0 | 50 | 50 | 50 | 50 |
5 rows × 139 columnsapp
查看数据的详细信息,共8000条记录,139个特征。框架
第二列为特证名、第三列为非空记录个数、第四列为特征的数据格式。机器学习
data_origin.info(verbose=True, null_counts=True)
<class 'pandas.core.frame.DataFrame'> Int64Index: 8000 entries, 1 to 8000 Data columns (total 139 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 happiness 8000 non-null int64 1 survey_type 8000 non-null int64 2 province 8000 non-null int64 3 city 8000 non-null int64 4 county 8000 non-null int64 5 survey_time 8000 non-null datetime64[ns] 6 gender 8000 non-null int64 7 birth 8000 non-null int64 8 nationality 8000 non-null int64 9 religion 8000 non-null int64 10 religion_freq 8000 non-null int64 11 edu 8000 non-null int64 12 edu_other 3 non-null object 13 edu_status 6880 non-null float64 14 edu_yr 6028 non-null float64 15 income 8000 non-null int64 16 political 8000 non-null int64 17 join_party 824 non-null float64 18 floor_area 8000 non-null float64 19 property_0 8000 non-null int64 20 property_1 8000 non-null int64 21 property_2 8000 non-null int64 22 property_3 8000 non-null int64 23 property_4 8000 non-null int64 24 property_5 8000 non-null int64 25 property_6 8000 non-null int64 26 property_7 8000 non-null int64 27 property_8 8000 non-null int64 28 property_other 66 non-null object 29 height_cm 8000 non-null int64 30 weight_jin 8000 non-null int64 31 health 8000 non-null int64 32 health_problem 8000 non-null int64 33 depression 8000 non-null int64 34 hukou 8000 non-null int64 35 hukou_loc 7996 non-null float64 36 media_1 8000 non-null int64 37 media_2 8000 non-null int64 38 media_3 8000 non-null int64 39 media_4 8000 non-null int64 40 media_5 8000 non-null int64 41 media_6 8000 non-null int64 42 leisure_1 8000 non-null int64 43 leisure_2 8000 non-null int64 44 leisure_3 8000 non-null int64 45 leisure_4 8000 non-null int64 46 leisure_5 8000 non-null int64 47 leisure_6 8000 non-null int64 48 leisure_7 8000 non-null int64 49 leisure_8 8000 non-null int64 50 leisure_9 8000 non-null int64 51 leisure_10 8000 non-null int64 52 leisure_11 8000 non-null int64 53 leisure_12 8000 non-null int64 54 socialize 8000 non-null int64 55 relax 8000 non-null int64 56 learn 8000 non-null int64 57 social_neighbor 7204 non-null float64 58 social_friend 7204 non-null float64 59 socia_outing 8000 non-null int64 60 equity 8000 non-null int64 61 class 8000 non-null int64 62 class_10_before 8000 non-null int64 63 class_10_after 8000 non-null int64 64 class_14 8000 non-null int64 65 work_exper 8000 non-null int64 66 work_status 2951 non-null float64 67 work_yr 2951 non-null float64 68 work_type 2951 non-null float64 69 work_manage 2951 non-null float64 70 insur_1 8000 non-null int64 71 insur_2 8000 non-null int64 72 insur_3 8000 non-null int64 73 insur_4 8000 non-null int64 74 family_income 7999 non-null float64 75 family_m 8000 non-null int64 76 family_status 8000 non-null int64 77 house 8000 non-null int64 78 car 8000 non-null int64 79 invest_0 8000 non-null int64 80 invest_1 8000 non-null int64 81 invest_2 8000 non-null int64 82 invest_3 8000 non-null int64 83 invest_4 8000 non-null int64 84 invest_5 8000 non-null int64 85 invest_6 8000 non-null int64 86 invest_7 8000 non-null int64 87 invest_8 8000 non-null int64 88 invest_other 29 non-null object 89 son 8000 non-null int64 90 daughter 8000 non-null int64 91 minor_child 6934 non-null float64 92 marital 8000 non-null int64 93 marital_1st 7172 non-null float64 94 s_birth 6282 non-null float64 95 marital_now 6230 non-null float64 96 s_edu 6282 non-null float64 97 s_political 6282 non-null float64 98 s_hukou 6282 non-null float64 99 s_income 6282 non-null float64 100 s_work_exper 6282 non-null float64 101 s_work_status 2565 non-null float64 102 s_work_type 2565 non-null float64 103 f_birth 8000 non-null int64 104 f_edu 8000 non-null int64 105 f_political 8000 non-null int64 106 f_work_14 8000 non-null int64 107 m_birth 8000 non-null int64 108 m_edu 8000 non-null int64 109 m_political 8000 non-null int64 110 m_work_14 8000 non-null int64 111 status_peer 8000 non-null int64 112 status_3_before 8000 non-null int64 113 view 8000 non-null int64 114 inc_ability 8000 non-null int64 115 inc_exp 8000 non-null float64 116 trust_1 8000 non-null int64 117 trust_2 8000 non-null int64 118 trust_3 8000 non-null int64 119 trust_4 8000 non-null int64 120 trust_5 8000 non-null int64 121 trust_6 8000 non-null int64 122 trust_7 8000 non-null int64 123 trust_8 8000 non-null int64 124 trust_9 8000 non-null int64 125 trust_10 8000 non-null int64 126 trust_11 8000 non-null int64 127 trust_12 8000 non-null int64 128 trust_13 8000 non-null int64 129 neighbor_familiarity 8000 non-null int64 130 public_service_1 8000 non-null int64 131 public_service_2 8000 non-null int64 132 public_service_3 8000 non-null int64 133 public_service_4 8000 non-null int64 134 public_service_5 8000 non-null float64 135 public_service_6 8000 non-null int64 136 public_service_7 8000 non-null int64 137 public_service_8 8000 non-null int64 138 public_service_9 8000 non-null int64 dtypes: datetime64[ns](1), float64(25), int64(110), object(3) memory usage: 8.5+ MB
查看数据整体统计量。分布式
data_origin.describe()
happiness | survey_type | province | city | county | gender | birth | nationality | religion | religion_freq | ... | neighbor_familiarity | 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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 8000.000000 | 8000.000000 | 8000.000000 | 8000.000000 | 8000.000000 | 8000.00000 | 8000.000000 | 8000.00000 | 8000.000000 | 8000.000000 | ... | 8000.000000 | 8000.000000 | 8000.000000 | 8000.000000 | 8000.000000 | 8000.000000 | 8000.000000 | 8000.00000 | 8000.000000 | 8000.000000 |
mean | 3.850125 | 1.405500 | 15.155375 | 42.564750 | 70.619000 | 1.53000 | 1964.707625 | 1.37350 | 0.772250 | 1.427250 | ... | 3.722250 | 70.809500 | 68.170000 | 62.737625 | 66.320125 | 62.794187 | 67.064000 | 66.09625 | 65.626750 | 67.153750 |
std | 0.938228 | 0.491019 | 8.917100 | 27.187404 | 38.747503 | 0.49913 | 16.842865 | 1.52882 | 1.071459 | 1.408441 | ... | 1.143358 | 21.184742 | 20.549943 | 24.771319 | 22.049437 | 23.463162 | 21.586817 | 23.08568 | 23.827493 | 22.502203 |
min | -8.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.00000 | 1921.000000 | -8.00000 | -8.000000 | -8.000000 | ... | -8.000000 | -3.000000 | -3.000000 | -3.000000 | -3.000000 | -3.000000 | -3.000000 | -3.00000 | -3.000000 | -3.000000 |
25% | 4.000000 | 1.000000 | 7.000000 | 18.000000 | 37.000000 | 1.00000 | 1952.000000 | 1.00000 | 1.000000 | 1.000000 | ... | 3.000000 | 60.000000 | 60.000000 | 50.000000 | 60.000000 | 55.000000 | 60.000000 | 60.00000 | 60.000000 | 60.000000 |
50% | 4.000000 | 1.000000 | 15.000000 | 42.000000 | 73.000000 | 2.00000 | 1965.000000 | 1.00000 | 1.000000 | 1.000000 | ... | 4.000000 | 79.000000 | 70.000000 | 70.000000 | 70.000000 | 70.000000 | 70.000000 | 70.00000 | 70.000000 | 70.000000 |
75% | 4.000000 | 2.000000 | 22.000000 | 65.000000 | 104.000000 | 2.00000 | 1977.000000 | 1.00000 | 1.000000 | 1.000000 | ... | 5.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.00000 | 80.000000 | 80.000000 |
max | 5.000000 | 2.000000 | 31.000000 | 89.000000 | 134.000000 | 2.00000 | 1997.000000 | 8.00000 | 1.000000 | 9.000000 | ... | 5.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.000000 | 100.00000 | 100.000000 | 100.000000 |
8 rows × 135 columns函数
查看子特征的缺失状况,其中oop
required_list
表示特征中的必填项continuous_list
表示特征属性为连续型变量categorical_list
表示分类型变量其他特征均为等级(ordinal)型的分类变量。学习
required_list = ['survey_type', 'province', 'city', 'county', 'survey_time', 'gender', 'birth', 'nationality', 'religion', 'religion_freq', 'edu', 'income', 'political', 'floor_area', 'height_cm', 'weight_jin', 'health', 'health_problem', 'depression', 'hukou', 'socialize', 'relax', 'learn', 'equity', 'class', 'work_exper', 'work_status', 'work_yr', 'work_type', 'work_manage', 'family_income', 'family_m', 'family_status', 'house', 'car', 'marital', 'status_peer', 'status_3_before', 'view', 'inc_ability'] continuous_list = ['birth', 'edu_yr', 'income', 'floor_area', 'height_cm', 'weight_jin', 'work_yr', 'family_income', 'family_m', 'house', 'son', 'daughter', 'minor_child', 'marital_1st', 's_birth', 'marital_now', 's_income', 'f_birth', 'm_birth', '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'] categorical_list = ['survey_type', 'province', 'gender', 'nationality']
查看必填项中缺失值的状况。
data_origin[required_list].isna().sum()[data_origin[required_list].isna().sum() > 0].to_frame().T
work_status | work_yr | work_type | work_manage | family_income | |
---|---|---|---|---|---|
0 | 5049 | 5049 | 5049 | 5049 | 1 |
其中
work_status
表示 目前工做的情况work_yr
表示 一共工做了多少年work_type
表示 目前工做的性质work_manage
表示 目前工做的管理活动状况family_income
表示 去年整年家庭总收入首先分析 work_
开头的四项特征的缺失状况,它们的缺失计数同样,可能说明调查问卷的填写方式,可能被跳过了。
首先检查调查问卷,找到对应的问卷问题,发如今 work_exper
特征中,即 工做经历及情况,根据不一样的工做经历,将上面四个问题跳过。
查看 work_exper
对应的问卷。
能够发现 work_exper
除了 1
分类,其它问题均被跳问;因此将上面四列的缺失记录的 work_exper
输出,查看是否都为非 1
类的记录。
经过下面的输出能够看到,在上面四项特征为缺失值的状况下,其记录对应的 work_exper
的取值大部分不为 1
。
data_origin.loc[data_origin[required_list].isna().sum(axis=1)[data_origin[required_list].isna().sum(axis=1) > 0].index, 'work_exper'].to_frame().plot.hist() pd.value_counts(data_origin.loc[data_origin[required_list].isna().sum(axis=1)[data_origin[required_list].isna().sum(axis=1) > 0].index, 'work_exper'])
5 1968 3 1242 4 1065 2 387 6 380 1 7 Name: work_exper, dtype: int64
进一步查看取值为 1
的记录。
(data_origin[data_origin[required_list].isna().sum(axis=1) > 0])[(data_origin[data_origin[required_list].isna().sum(axis=1) > 0].work_exper == 1)]
happiness | survey_type | province | city | county | survey_time | gender | birth | nationality | religion | ... | neighbor_familiarity | 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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | |||||||||||||||||||||
692 | 4 | 2 | 21 | 64 | 101 | 2015-07-20 11:12:00 | 2 | 1975 | 1 | 1 | ... | 5 | 80 | 70 | 80 | 80 | 80.0 | 80 | 80 | 80 | 80 |
841 | 4 | 2 | 31 | 88 | 133 | 2015-08-17 13:49:00 | 2 | 1971 | 1 | 0 | ... | 4 | 50 | 30 | -2 | -2 | -2.0 | 50 | 50 | 50 | 70 |
1411 | 4 | 2 | 2 | 2 | 9 | 2015-07-23 09:25:00 | 1 | 1967 | 8 | 1 | ... | 4 | 90 | 85 | 80 | 90 | 90.0 | 92 | 93 | 94 | 90 |
3117 | 4 | 1 | 4 | 7 | 18 | 2015-10-03 16:02:00 | 1 | 1980 | 1 | 1 | ... | 2 | 30 | 35 | 30 | 40 | 60.0 | 40 | 30 | 70 | 70 |
4783 | 5 | 2 | 22 | 65 | 103 | 2015-07-08 18:45:00 | 1 | 1955 | 1 | 1 | ... | 5 | 90 | 90 | 90 | 90 | 80.0 | 90 | 80 | 90 | 90 |
5589 | 5 | 2 | 16 | 46 | 78 | 2015-07-29 11:34:00 | 2 | 1964 | 1 | 1 | ... | 3 | 89 | 63 | 67 | 75 | 74.0 | 67 | 65 | 78 | 79 |
7368 | 4 | 2 | 21 | 64 | 101 | 2015-07-19 08:32:00 | 2 | 1963 | 1 | 1 | ... | 5 | 70 | 70 | 70 | 60 | 70.0 | 70 | 60 | 60 | 60 |
7 rows × 139 columns
能够发现 work_exper
为 1
的记录存在7条,故将此删除。
data_origin.drop((data_origin[data_origin[required_list].isna().sum(axis=1) > 0])[(data_origin[data_origin[required_list].isna().sum(axis=1) > 0].work_exper == 1)].index, inplace=True)
由于 family_income
缺失个数只有1条,不影响数据规模,因此直接将其删除。
data_origin.drop(data_origin['family_income'].isna()[data_origin['family_income'].isna()].index, inplace=True)
查看连续型特征的却失状况。
data_origin[continuous_list].isna().sum()[data_origin[continuous_list].isna().sum() > 0].to_frame().T
edu_yr | work_yr | minor_child | marital_1st | s_birth | marital_now | s_income | |
---|---|---|---|---|---|---|---|
0 | 1970 | 5041 | 1066 | 828 | 1718 | 1770 | 1718 |
其中
edu_yr
表示 已经完成的最高学历是哪一年得到的work_yr
表示 第一份非农工做到目前的工做一共工做了多少年minor_child
表示 有几个18周岁如下未成年子女marital_1st
表示 第一次结婚的时间s_birth
表示 目前的配偶或同居伴侣是哪一年出生的martital_now
表示 与目前的配偶是哪一年结婚的s_income
表示 配偶或同居伴侣去年整年的总收入对于 edu_yr
即 已经完成的最高学历是哪一年得到的,查看缺失记录的 edu_status
取值分布状况。
data_origin[data_origin['edu_yr'].isna()]['edu_status'].plot.hist() pd.value_counts(data_origin[data_origin['edu_yr'].isna()]['edu_status'])
2.0 746 3.0 103 4.0 1 1.0 1 Name: edu_status, dtype: int64
查看 edu_yr
缺失的记录的 edu_status
特征后,只有选项 4
即 毕业的记录才应该填写 edu_yr
的毕业年份,因此应该删除记录。
data_origin.drop(data_origin[(data_origin['edu_status'] == 4) & (data_origin['edu_yr'].isna())].index, inplace=True)
data_origin.shape
(7991, 139)
对于 minor_child
特征,能够检查这个特征缺失的记录另外两项特征 son
和 daughter
分别表示儿子、女儿的数量,若是为0,则将 minor_child
也填充为0。
print(data_origin[np.array(data_origin['minor_child'].isna())].loc[:, 'son'].sum()) print(data_origin[np.array(data_origin['minor_child'].isna())].loc[:, 'daughter'].sum()) data_origin[np.array(data_origin['minor_child'].isna())].loc[:, 'son':'daughter']
0 0
son | daughter | |
---|---|---|
id | ||
2 | 0 | 0 |
5 | 0 | 0 |
9 | 0 | 0 |
29 | 0 | 0 |
31 | 0 | 0 |
... | ... | ... |
7967 | 0 | 0 |
7972 | 0 | 0 |
7991 | 0 | 0 |
7999 | 0 | 0 |
8000 | 0 | 0 |
1066 rows × 2 columns
能够看对 minor_child
缺失的记录,其儿子和女儿的个数也为0,因此将 minor_child
缺失值填充为0。
data_origin['minor_child'].fillna(0, inplace=True)
对于 marital_1st
的记录的缺失状况,能够查看对应的记录的 marital
的取值是否为 1
表示 未婚。
print(data_origin[np.array(data_origin['marital_1st'].isna())]['marital'].sum() == data_origin[np.array(data_origin['marital_1st'].isna())]['marital'].shape[0]) data_origin[np.array(data_origin['marital_1st'].isna())]['marital'].plot.hist() pd.value_counts(data_origin[np.array(data_origin['marital_1st'].isna())]['marital'])
True 1 828 Name: marital, dtype: int64
能够看到输出结果代表对于 marital_1st
缺失的记录都是未婚人士,因此缺失值正常。
下面查看 s_birth
即 目前的配偶或同居伴侣是哪一年出生的的缺失状况,首先查看缺失的记录的 marital
状态,查看是否知足无配偶或同居伴侣的状况。
data_origin[data_origin['s_birth'].isna()]['marital'].plot.hist() pd.value_counts(data_origin[data_origin['s_birth'].isna()]['marital'])
1 828 7 718 6 171 2 1 Name: marital, dtype: int64
根据输出能够看到,marital
取值为 1
、6
、7
分别表示 未婚、离婚和丧偶,因此 s_birth
缺失属于正常;并且取值为 2
表示同居的缺失记录只有一条,因此直接将其删除便可。
data_origin.drop(data_origin[data_origin['s_birth'].isna()]['marital'][data_origin[data_origin['s_birth'].isna()]['marital'] == 2].index, inplace=True)
对于 marital_now
即 与目前的配偶是哪一年结婚的,首先输出 marital
查看婚姻的状态,是否知足没结婚的条件。
data_origin[data_origin['marital_now'].isna()]['marital'].plot.hist() pd.value_counts(data_origin[data_origin['marital_now'].isna()]['marital'])
1 828 7 718 6 171 2 51 3 1 Name: marital, dtype: int64
根据输出能够获得 1
和 2
表示没有结婚的状况,因此缺失属于正常;
对于 3
、6
、7
分别表示 初婚有配偶、离婚、丧偶;只有 3
属于目前有配偶并结婚的状况,因此应该删除。
data_origin.drop(data_origin[data_origin['marital_now'].isna()].loc[data_origin[data_origin['marital_now'].isna()]['marital'] == 3].index, inplace=True)
data_origin.shape
(7989, 139)
对于 s_income
即 配偶或同居伴侣去年整年的总收入的缺失状况,能够检查对于 marital
查看其是否知足无配偶或伴侣的条件。
data_origin[data_origin['s_income'].isna()]['marital'].plot.hist() pd.value_counts(data_origin[data_origin['s_income'].isna()]['marital'])
1 828 7 718 6 171 Name: marital, dtype: int64
能够看到对于 s_income
的缺失值,其记录对应的婚姻状态都为未婚、离婚或丧偶,因此 s_income
缺失是正常的。
查看分类型(categorical)变量的缺失状况,所有为0,则没有缺失值。
data_origin[categorical_list].isna().sum().to_frame().T
survey_type | province | gender | nationality | |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
查看全部特征的缺失状况。
data_origin.isna().sum()[data_origin.isna().sum() > 0].to_frame().T
edu_other | edu_status | edu_yr | join_party | property_other | hukou_loc | social_neighbor | social_friend | work_status | work_yr | ... | marital_1st | s_birth | marital_now | s_edu | s_political | s_hukou | s_income | s_work_exper | s_work_status | s_work_type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7986 | 1119 | 1969 | 7167 | 7923 | 4 | 795 | 795 | 5038 | 5038 | ... | 828 | 1717 | 1768 | 1717 | 1717 | 1717 | 1717 | 1717 | 5427 | 5427 |
1 rows × 23 columns
首先对于 edu_other
特征,只有在 edu
填写了 14
的状况下才填写,首先检查 edu_other
缺失的记录的 edu
是否为 14
若为 14
则说明 edu_other
不该该为缺失,应该将其删除。
data_origin[data_origin['edu_other'].isna()][data_origin[data_origin['edu_other'].isna()]['edu'] == 14]
happiness | survey_type | province | city | county | survey_time | gender | birth | nationality | religion | ... | neighbor_familiarity | 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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | |||||||||||||||||||||
1242 | 4 | 2 | 3 | 6 | 13 | 2015-09-24 17:58:00 | 1 | 1971 | 1 | 1 | ... | 5 | 100 | 90 | 60 | 80 | 70.0 | 80 | 70 | 60 | 50 |
3651 | 3 | 2 | 3 | 6 | 13 | 2015-09-24 20:25:00 | 1 | 1953 | 1 | 1 | ... | 5 | 100 | 100 | 60 | 50 | 70.0 | 50 | 30 | 70 | 40 |
5330 | 2 | 2 | 3 | 6 | 13 | 2015-09-25 07:57:00 | 1 | 1953 | 1 | 1 | ... | 5 | 100 | 100 | 100 | 100 | 100.0 | 100 | 30 | 100 | 50 |
3 rows × 139 columns
能够看到 edu
为 14
的记录中,有3条记录 edu_other
也为缺失;因此将3条记录删除。
data_origin.drop(data_origin[data_origin['edu_other'].isna()][data_origin[data_origin['edu_other'].isna()]['edu'] == 14].index, inplace=True)
对于 edu_status
的缺失记录,能够先检查记录对应的 edu
是取的何值。
data_origin[data_origin['edu_status'].isna()]['edu'].plot.hist() pd.value_counts(data_origin[data_origin['edu_status'].isna()]['edu'])
1 1052 2 65 3 2 Name: edu, dtype: int64
能够看到对于 edu_status
缺失的记录,其对应的 edu
教育程度为别为没有受过任何教育、私塾、扫盲班和小学;对于取值为 1
和 2
的状况,属于跳问选项,对应的 edu_status
属于缺失是正常的;因此将 edu
取值为 3
的记录删除。
data_origin.drop(data_origin[data_origin['edu_status'].isna()][data_origin[data_origin['edu_status'].isna()]['edu'] == 3].index, inplace=True)
对于 join_party
即 目前政治面貌是党员的入党时间,只有政治面貌不是党员的缺失值才算正确,查看分布状况。
data_origin[data_origin['join_party'].isna()]['political'].plot.hist() pd.value_counts(data_origin[data_origin['join_party'].isna()]['political'])
1 6703 2 402 -8 41 3 11 4 5 Name: political, dtype: int64
根据直方图看到,有5条记录的 partical
的取值是 4
而入党时间没有填写,因此将这5条记录删除。
data_origin.drop(data_origin[data_origin['join_party'].isna()][data_origin[data_origin['join_party'].isna()]['political'] == 4].index, inplace=True)
对于 hukou_loc
即 目前的户口登记地,查看缺失记录的 hukou
登记状况,发现取值都为 7
即 没有户口,因此缺失属于正常。
data_origin[data_origin['hukou_loc'].isna()]['hukou'].to_frame()
hukou | |
---|---|
id | |
589 | 7 |
3657 | 7 |
3799 | 7 |
7811 | 7 |
对于 social_neighbor
和 social_friend
即与与其余朋友进行社交娱乐活动的频繁程度和有多少个晚上是由于出去度假或者探访亲友而没有在家过夜,首先查看缺失记录的 socialize
的分布状况。
data_origin[data_origin['social_neighbor'].isna()]['socialize'].plot.hist() pd.value_counts(data_origin[data_origin['social_neighbor'].isna()]['socialize'])
1 793 Name: socialize, dtype: int64
能够发现全部的 social_neighbor
和 social_friend
缺失记录的 socialize
即 是否常常在空闲时间作社交的事情所有均为 1
即 从不社交,因此两个特征的缺失值可使用 1
填充。
data_origin['social_neighbor'].fillna(1, inplace=True) data_origin['social_friend'].fillna(1, inplace=True)
对于 s_edu
到 s_work_exper
的特征,缺失值的记录数都同样,因此存在可能这几项特征的缺失记录都来自同一批问卷对象。
首先查看 s_edu
的缺失记录的 marital
的分布状况。
data_origin[data_origin['s_edu'].isna()]['marital'].plot.hist() pd.value_counts(data_origin[data_origin['s_edu'].isna()]['marital'])
1 827 7 717 6 171 Name: marital, dtype: int64
能够发现 s_edu
缺失的记录的婚姻状况所有均为未婚、离婚或丧偶,均属于没有配偶或同居伴侣的状况,因此属于正常的缺失。
对于 s_political
到 s_work_exper
所有均属于上述状况。
对于 s_work_status
即 配偶或同居伴侣目前的工做情况,首先查看调查问卷。
能够得知只有 s_work_exper
填写了 1
的状况下才应该填写 s_work_status
和 s_work_type
其它选项均须要跳过,因此属于正常缺失值。
下面查看 s_work_status
缺失记录的 s_work_exper
的分布状况。
data_origin[data_origin['s_work_status'].isna()]['s_work_exper'].plot.hist() pd.value_counts(data_origin[data_origin['s_work_status'].isna()]['s_work_exper'])
5.0 1424 3.0 1017 4.0 823 6.0 221 2.0 217 1.0 1 Name: s_work_exper, dtype: int64
查看得知 s_work_exper
选 1
的记录只有1条,直接删除便可。
data_origin.drop(data_origin[data_origin['s_work_status'].isna()][data_origin[data_origin['s_work_status'].isna()]['s_work_exper'] == 1].index, inplace=True)
在调查问卷中,每一个选项通用含义,其 -1
表示不适用;-2
表示不知道;-3
表示拒绝回答;-8
表示没法回答。
在这里将全部的特征的负数使用每个特征的中位数进行填充。
data_origin.shape
(7978, 139)
no_ne_rows_index = (data_origin.drop(['survey_time', 'edu_other', 'property_other', 'invest_other'], axis=1) < 0).sum(axis=1)[(data_origin.drop(['survey_time', 'edu_other', 'property_other', 'invest_other'], axis=1) < 0).sum(axis=1) == 0].index
for column, content in data_origin.items(): if pd.api.types.is_numeric_dtype(content): data_origin[column] = data_origin[column].apply(lambda x : pd.Series(data_origin.loc[no_ne_rows_index, :][column].unique()).median() if(x < 0 and x != np.nan) else x)
将全部的负数填充完成后,再将 NaN
数值所有使用统一的一个值 -1
填充。
data_origin.fillna(-1, inplace=True)
至此,全部特征的缺失值已经所有处理完毕。
在全部的特征中,有3个特征分别是 edu_other
、property_other
、invest_other
是字符串数据,须要将其转换成序号编码(Ordinal Encoding)。
首先查看 edu_other
的填写状况。
data_origin[data_origin['edu_other'] != -1]['edu_other'].to_frame()
edu_other | |
---|---|
id | |
1170 | 夜校 |
2513 | 夜校 |
4926 | 夜校 |
能够看到 edu_other
的填写状况全都是夜校,将字符串转换成序号编码。
data_origin['edu_other'] = data_origin['edu_other'].astype('category').values.codes + 1
查看 property_other
即 房子产权归属谁,首先检查调查问卷的填写状况。
data_origin[data_origin['property_other'] != -1]['property_other'].to_frame()
property_other | |
---|---|
id | |
76 | 无产权 |
92 | 已购买,但未过户 |
99 | 家庭共同全部 |
132 | 待办 |
455 | 没有产权 |
... | ... |
7376 | 家人共有 |
7746 | 全家人共有 |
7776 | 兄弟共有 |
7821 | 未分家,全家全部 |
7917 | 家人共有 |
66 rows × 1 columns
根据填写状况来看,其中有不少填写信息都是一个意思,例如 家庭共同全部
和 全家全部
是同一个意思,可是在python处理中只能一个个的手动处理。
#data_origin.loc[[8009, 9212, 9759, 10517], 'property_other'] = '多人拥有' #data_origin.loc[[8014, 8056, 10264], 'property_other'] = '未过户' #data_origin.loc[[8471, 8825, 9597, 9810, 9842, 9967, 10069, 10166, 10203, 10469], 'property_other'] = '全家拥有' #data_origin.loc[[8553, 8596, 9605, 10421, 10814], 'property_other'] = '无产权'
data_origin.loc[[76, 132, 455, 495, 1415, 2511, 2792, 2956, 3647, 4147, 4193, 4589, 5023, 5382, 5492, 6102, 6272, 6339, 6507, 7184, 7239], 'property_other'] = '无产权' data_origin.loc[[92, 1888, 2703, 3381, 5654], 'property_other'] = '未过户' data_origin.loc[[99, 619, 2728, 3062, 3222, 3251, 3696, 5283, 6191, 7295, 7376, 7746, 7821, 7917], 'property_other'] = '全家拥有' data_origin.loc[[1597, 4993, 5398, 5899, 7240, 7776], 'property_other'] = '多人拥有' data_origin.loc[[6469, 6891], 'property_other'] = '小产权'
将字符串编码为整数型的序号(ordinal)类型。
data_origin['property_other'] = data_origin['property_other'].astype('category').values.codes + 1
查看 invest_other
即 从事的投资活动的填写状况。
pd.DataFrame(data_origin[data_origin['invest_other'] != -1]['invest_other'].unique())
0 | |
---|---|
0 | 理财产品 |
1 | 民间借贷 |
2 | 银行理财 |
3 | 储蓄存款 |
4 | 理财 |
5 | 银行存款利息 |
6 | 活期储蓄 |
7 | 投资服务业、家具业 |
8 | 银行存款 |
9 | 我的融资 |
10 | 租房 |
11 | 老人家不清楚 |
12 | 家中有部分土地承包出去 |
13 | 没有 |
14 | 高利贷 |
15 | 彩票 |
16 | 本身没有,儿女不清楚 |
17 | 网上理财 |
18 | 统筹 |
19 | 福利车票 |
20 | 其余理财产品 |
21 | 商业万能保险 |
22 | 投资开发区 |
23 | 字画、茶壶 |
一样地,将其转换成整数类型的序号(ordinal)编码。
data_origin['invest_other'] = data_origin['invest_other'].astype('category').values.codes + 1
data_nona = data_origin.copy()
画出箱型图分析特征的异常值。
并删除离群记录。
sns.boxplot(x=data_nona['house'])
<AxesSubplot:xlabel='house'>
data_nona.drop(data_nona[data_nona['house'] > 25].index, inplace=True)
sns.boxplot(x=data_nona['family_m'])
<AxesSubplot:xlabel='family_m'>
data_nona.drop(data_nona[data_nona['family_m'] > 40].index, inplace=True)
sns.boxplot(x=data_nona['inc_exp'])
<AxesSubplot:xlabel='inc_exp'>
data_nona.drop(data_nona[data_nona['inc_exp'] > 0.6e8].index, inplace=True)
查看调查时间的月份分布状况,由于调查问卷都是在2015年填写,只须要查看月份的离群点。
由图可知调查问卷是从6月开始的,记录中2月的问卷属于异常数据,应该删除。
sns.boxplot(x=data_nona['survey_time'].dt.month)
<AxesSubplot:xlabel='survey_time'>
data_nona.drop(data_nona[data_nona['survey_time'].dt.month < 6].index, inplace=True)
特征构造也可称为特征交叉、特征组合、数据变换。
离散化除了一些计算方面等等好处,还能够引入非线性特性,也能够很方便的作cross-feature。离散特征的增长和减小都很容易,易于模型的快速迭代。此外,噪声很大的环境中,离散化能够下降特征中包含的噪声,提高特征的表达能力。
pd.DataFrame(continuous_list)
0 | |
---|---|
0 | birth |
1 | edu_yr |
2 | income |
3 | floor_area |
4 | height_cm |
5 | weight_jin |
6 | work_yr |
7 | family_income |
8 | family_m |
9 | house |
10 | son |
11 | daughter |
12 | minor_child |
13 | marital_1st |
14 | s_birth |
15 | marital_now |
16 | s_income |
17 | f_birth |
18 | m_birth |
19 | inc_exp |
20 | public_service_1 |
21 | public_service_2 |
22 | public_service_3 |
23 | public_service_4 |
24 | public_service_5 |
25 | public_service_6 |
26 | public_service_7 |
27 | public_service_8 |
28 | public_service_9 |
将连续型变量所有进行分箱,而后对每一个区间进行编码,生成新的离散的特征。
for column in continuous_list: cut = pd.qcut(data_nona[column], q=5, duplicates='drop') cat = cut.values codes = cat.codes data_nona[column + '_discrete'] = codes
for column, content in data_nona.items(): if pd.api.types.is_numeric_dtype(content): data_nona[column] = content.astype('int')
将连续变量离散化后,生成之后缀 _discrete
的新特征,因此将原来的连续变量的特征删除掉。
data_nona.to_csv('./data/happiness_train_complete_analysis.csv')
data_nona.drop(continuous_list, axis=1, inplace=True)
data_nona.to_csv('./data/happiness_train_complete_nona.csv')
import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import seaborn as sns
data = pd.read_csv('./data/happiness_train_complete_analysis.csv', index_col='id', parse_dates=['survey_time'])
data.head()
happiness | survey_type | province | city | county | survey_time | gender | birth | nationality | religion | ... | inc_exp_discrete | public_service_1_discrete | public_service_2_discrete | public_service_3_discrete | public_service_4_discrete | public_service_5_discrete | public_service_6_discrete | public_service_7_discrete | public_service_8_discrete | public_service_9_discrete | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | |||||||||||||||||||||
1 | 4 | 1 | 12 | 32 | 59 | 2015-08-04 14:18:00 | 1 | 1959 | 1 | 1 | ... | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 4 | 2 | 18 | 52 | 85 | 2015-07-21 15:04:00 | 1 | 1992 | 1 | 1 | ... | 2 | 4 | 1 | 2 | 3 | 4 | 1 | 4 | 0 | 0 |
3 | 4 | 2 | 29 | 83 | 126 | 2015-07-21 13:24:00 | 2 | 1967 | 1 | 0 | ... | 3 | 4 | 2 | 3 | 3 | 3 | 4 | 4 | 4 | 2 |
4 | 5 | 2 | 10 | 28 | 51 | 2015-07-25 17:33:00 | 2 | 1943 | 1 | 1 | ... | 0 | 4 | 3 | 2 | 3 | 3 | 4 | 4 | 3 | 2 |
5 | 4 | 1 | 7 | 18 | 36 | 2015-08-10 09:50:00 | 2 | 1994 | 1 | 1 | ... | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 rows × 168 columns
data.describe()
happiness | survey_type | province | city | county | gender | birth | nationality | religion | religion_freq | ... | inc_exp_discrete | public_service_1_discrete | public_service_2_discrete | public_service_3_discrete | public_service_4_discrete | public_service_5_discrete | public_service_6_discrete | public_service_7_discrete | public_service_8_discrete | public_service_9_discrete | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | ... | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 | 7968.000000 |
mean | 3.866466 | 1.405120 | 15.158258 | 42.572164 | 70.631903 | 1.530748 | 1964.710216 | 1.399724 | 0.880271 | 1.452560 | ... | 1.725653 | 1.665537 | 1.272214 | 1.841365 | 1.613328 | 1.848519 | 1.643449 | 1.651732 | 1.654869 | 1.302962 |
std | 0.818844 | 0.490946 | 8.915876 | 27.183764 | 38.736751 | 0.499085 | 16.845155 | 1.466409 | 0.324665 | 1.358444 | ... | 1.338535 | 1.420309 | 1.108440 | 1.342524 | 1.499494 | 1.297290 | 1.533445 | 1.544477 | 1.511468 | 1.078601 |
min | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1921.000000 | 1.000000 | 0.000000 | 1.000000 | ... | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
25% | 4.000000 | 1.000000 | 7.000000 | 18.000000 | 37.000000 | 1.000000 | 1952.000000 | 1.000000 | 1.000000 | 1.000000 | ... | 1.000000 | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
50% | 4.000000 | 1.000000 | 15.000000 | 42.000000 | 73.000000 | 2.000000 | 1965.000000 | 1.000000 | 1.000000 | 1.000000 | ... | 1.000000 | 2.000000 | 1.000000 | 2.000000 | 1.000000 | 2.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
75% | 4.000000 | 2.000000 | 22.000000 | 65.000000 | 104.000000 | 2.000000 | 1977.000000 | 1.000000 | 1.000000 | 1.000000 | ... | 3.000000 | 2.000000 | 2.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 2.000000 |
max | 5.000000 | 2.000000 | 31.000000 | 89.000000 | 134.000000 | 2.000000 | 1997.000000 | 8.000000 | 1.000000 | 9.000000 | ... | 4.000000 | 4.000000 | 3.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000 | 3.000000 |
8 rows × 167 columns
data.info(verbose=True, null_counts=True)
<class 'pandas.core.frame.DataFrame'> Int64Index: 7968 entries, 1 to 8000 Data columns (total 168 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 happiness 7968 non-null int64 1 survey_type 7968 non-null int64 2 province 7968 non-null int64 3 city 7968 non-null int64 4 county 7968 non-null int64 5 survey_time 7968 non-null datetime64[ns] 6 gender 7968 non-null int64 7 birth 7968 non-null int64 8 nationality 7968 non-null int64 9 religion 7968 non-null int64 10 religion_freq 7968 non-null int64 11 edu 7968 non-null int64 12 edu_other 7968 non-null int64 13 edu_status 7968 non-null int64 14 edu_yr 7968 non-null int64 15 income 7968 non-null int64 16 political 7968 non-null int64 17 join_party 7968 non-null int64 18 floor_area 7968 non-null int64 19 property_0 7968 non-null int64 20 property_1 7968 non-null int64 21 property_2 7968 non-null int64 22 property_3 7968 non-null int64 23 property_4 7968 non-null int64 24 property_5 7968 non-null int64 25 property_6 7968 non-null int64 26 property_7 7968 non-null int64 27 property_8 7968 non-null int64 28 property_other 7968 non-null int64 29 height_cm 7968 non-null int64 30 weight_jin 7968 non-null int64 31 health 7968 non-null int64 32 health_problem 7968 non-null int64 33 depression 7968 non-null int64 34 hukou 7968 non-null int64 35 hukou_loc 7968 non-null int64 36 media_1 7968 non-null int64 37 media_2 7968 non-null int64 38 media_3 7968 non-null int64 39 media_4 7968 non-null int64 40 media_5 7968 non-null int64 41 media_6 7968 non-null int64 42 leisure_1 7968 non-null int64 43 leisure_2 7968 non-null int64 44 leisure_3 7968 non-null int64 45 leisure_4 7968 non-null int64 46 leisure_5 7968 non-null int64 47 leisure_6 7968 non-null int64 48 leisure_7 7968 non-null int64 49 leisure_8 7968 non-null int64 50 leisure_9 7968 non-null int64 51 leisure_10 7968 non-null int64 52 leisure_11 7968 non-null int64 53 leisure_12 7968 non-null int64 54 socialize 7968 non-null int64 55 relax 7968 non-null int64 56 learn 7968 non-null int64 57 social_neighbor 7968 non-null int64 58 social_friend 7968 non-null int64 59 socia_outing 7968 non-null int64 60 equity 7968 non-null int64 61 class 7968 non-null int64 62 class_10_before 7968 non-null int64 63 class_10_after 7968 non-null int64 64 class_14 7968 non-null int64 65 work_exper 7968 non-null int64 66 work_status 7968 non-null int64 67 work_yr 7968 non-null int64 68 work_type 7968 non-null int64 69 work_manage 7968 non-null int64 70 insur_1 7968 non-null int64 71 insur_2 7968 non-null int64 72 insur_3 7968 non-null int64 73 insur_4 7968 non-null int64 74 family_income 7968 non-null int64 75 family_m 7968 non-null int64 76 family_status 7968 non-null int64 77 house 7968 non-null int64 78 car 7968 non-null int64 79 invest_0 7968 non-null int64 80 invest_1 7968 non-null int64 81 invest_2 7968 non-null int64 82 invest_3 7968 non-null int64 83 invest_4 7968 non-null int64 84 invest_5 7968 non-null int64 85 invest_6 7968 non-null int64 86 invest_7 7968 non-null int64 87 invest_8 7968 non-null int64 88 invest_other 7968 non-null int64 89 son 7968 non-null int64 90 daughter 7968 non-null int64 91 minor_child 7968 non-null int64 92 marital 7968 non-null int64 93 marital_1st 7968 non-null int64 94 s_birth 7968 non-null int64 95 marital_now 7968 non-null int64 96 s_edu 7968 non-null int64 97 s_political 7968 non-null int64 98 s_hukou 7968 non-null int64 99 s_income 7968 non-null int64 100 s_work_exper 7968 non-null int64 101 s_work_status 7968 non-null int64 102 s_work_type 7968 non-null int64 103 f_birth 7968 non-null int64 104 f_edu 7968 non-null int64 105 f_political 7968 non-null int64 106 f_work_14 7968 non-null int64 107 m_birth 7968 non-null int64 108 m_edu 7968 non-null int64 109 m_political 7968 non-null int64 110 m_work_14 7968 non-null int64 111 status_peer 7968 non-null int64 112 status_3_before 7968 non-null int64 113 view 7968 non-null int64 114 inc_ability 7968 non-null int64 115 inc_exp 7968 non-null int64 116 trust_1 7968 non-null int64 117 trust_2 7968 non-null int64 118 trust_3 7968 non-null int64 119 trust_4 7968 non-null int64 120 trust_5 7968 non-null int64 121 trust_6 7968 non-null int64 122 trust_7 7968 non-null int64 123 trust_8 7968 non-null int64 124 trust_9 7968 non-null int64 125 trust_10 7968 non-null int64 126 trust_11 7968 non-null int64 127 trust_12 7968 non-null int64 128 trust_13 7968 non-null int64 129 neighbor_familiarity 7968 non-null int64 130 public_service_1 7968 non-null int64 131 public_service_2 7968 non-null int64 132 public_service_3 7968 non-null int64 133 public_service_4 7968 non-null int64 134 public_service_5 7968 non-null int64 135 public_service_6 7968 non-null int64 136 public_service_7 7968 non-null int64 137 public_service_8 7968 non-null int64 138 public_service_9 7968 non-null int64 139 birth_discrete 7968 non-null int64 140 edu_yr_discrete 7968 non-null int64 141 income_discrete 7968 non-null int64 142 floor_area_discrete 7968 non-null int64 143 height_cm_discrete 7968 non-null int64 144 weight_jin_discrete 7968 non-null int64 145 work_yr_discrete 7968 non-null int64 146 family_income_discrete 7968 non-null int64 147 family_m_discrete 7968 non-null int64 148 house_discrete 7968 non-null int64 149 son_discrete 7968 non-null int64 150 daughter_discrete 7968 non-null int64 151 minor_child_discrete 7968 non-null int64 152 marital_1st_discrete 7968 non-null int64 153 s_birth_discrete 7968 non-null int64 154 marital_now_discrete 7968 non-null int64 155 s_income_discrete 7968 non-null int64 156 f_birth_discrete 7968 non-null int64 157 m_birth_discrete 7968 non-null int64 158 inc_exp_discrete 7968 non-null int64 159 public_service_1_discrete 7968 non-null int64 160 public_service_2_discrete 7968 non-null int64 161 public_service_3_discrete 7968 non-null int64 162 public_service_4_discrete 7968 non-null int64 163 public_service_5_discrete 7968 non-null int64 164 public_service_6_discrete 7968 non-null int64 165 public_service_7_discrete 7968 non-null int64 166 public_service_8_discrete 7968 non-null int64 167 public_service_9_discrete 7968 non-null int64 dtypes: datetime64[ns](1), int64(167) memory usage: 10.3 MB
首先,查看 happiness
幸福程度的分布,能够发现多数人都属于 比较幸福
的程度。
sns.set_theme(style="darkgrid") sns.displot(data, x="happiness", facet_kws=dict(margin_titles=True))
<seaborn.axisgrid.FacetGrid at 0x25128009850>
查看每一个人的收入和幸福度的散点图,经过散点图能够看出随着收入的提升,大多数点都落在了较高的幸福程度上;即便如此,也会发现存在一些收入很是高的人也处在一个说不上幸福不幸福的程度。
sns.set_theme(style="whitegrid") f, ax = plt.subplots() sns.despine(f, left=True, bottom=True) sns.scatterplot(x="happiness", y="income", size="income", palette="ch:r=-.2,d=.3_r", data=data, ax=ax)
<AxesSubplot:xlabel='happiness', ylabel='income'>
查看性别男女的幸福程度的分布直方图,在性别特征上没有过多的类别不平衡状况。
sns.set_theme(style="darkgrid") sns.displot( data, x="happiness", col="gender", facet_kws=dict(margin_titles=True) )
<seaborn.axisgrid.FacetGrid at 0x25128b8e1f0>
经过直线图,能够看出,随着 edu
受到的教育的提升,幸福程度也随之提高。
sns.set_theme(style="ticks") palette = sns.color_palette("rocket_r") sns.relplot( data=data, x="edu", y="happiness", kind="line", size_order=["T1", "T2"], palette=palette, facet_kws=dict(sharex=False) )
<seaborn.axisgrid.FacetGrid at 0x251284bdeb0>
查看每一个幸福程度的出生日期,能够看出,不一样幸福程度的年代的人分布都是大同小异的。
sns.set_theme(style="ticks", palette="pastel") sns.boxplot(x="happiness", y="birth", data=data) sns.despine(offset=10, trim=True)
将记录分为是否信仰宗教信仰,查看幸福度和健康情况的分裂小提琴图,也能够看出一个趋势,幸福度高的人大多数都分布在较高的健康情况上,并且也能够看出一个现象,随着健康情况和幸福度的提升,信仰宗教信仰的人数也慢慢增长。
sns.set_theme(style="whitegrid") sns.violinplot(data=data, x="happiness", y="health", hue="religion", split=True, inner="quart", linewidth=1) sns.despine(left=True)
绘制一个多变量分布直方图,能够看出大多数比较幸福的人,房产的数量也不会大幅增长。
import seaborn as sns sns.set_theme(style="ticks") g = sns.JointGrid(data=data, x="happiness", y="house", marginal_ticks=True) # Set a log scaling on the y axis g.ax_joint.set(yscale="linear") # Create an inset legend for the histogram colorbar cax = g.fig.add_axes([.15, .55, .02, .2]) # Add the joint and marginal histogram plots g.plot_joint( sns.histplot, discrete=(True, False), cmap="light:#03012d", pmax=.8, cbar=True, cbar_ax=cax ) g.plot_marginals(sns.histplot, element="step", color="#03012d")
<seaborn.axisgrid.JointGrid at 0x251288fee20>
绘制幸福度和住房建筑面积的核密度估计图,能够看出一样的现象,多数比较幸福的人的房屋建筑面积也不会集中在很高的一个水平,可是也会有一个随着房屋建筑面积的增长幸福度也增长的现象。
sns.set_theme(style="ticks") g = sns.jointplot( data=data[data['floor_area'] < 600], x="happiness", y="floor_area", kind="kde", )
查看各个特征的热力图,能够根据图中的颜色深度看出两两特征之间的相关性的高低。
sns.set_theme(style="whitegrid") corr_list = ['survey_type', 'province', 'city', 'county', 'survey_time', 'gender', 'birth', 'nationality', 'religion', 'religion_freq', 'edu', 'income', 'political', 'floor_area', 'height_cm', 'weight_jin', 'health', 'health_problem', 'depression', 'hukou', 'socialize', 'relax', 'learn', 'equity', 'class', 'work_exper', 'work_status', 'work_yr', 'work_type', 'work_manage', 'family_income', 'family_m', 'family_status', 'house', 'car', 'marital', 'status_peer', 'status_3_before', 'view', 'inc_ability'] df = data corr_mat = data[corr_list].corr().stack().reset_index(name="correlation") g = sns.relplot( data=corr_mat, x="level_0", y="level_1", hue="correlation", size="correlation", palette="vlag", hue_norm=(-1, 1), edgecolor=".7", height=10, sizes=(50, 250), size_norm=(-.2, .8), ) g.set(xlabel="", ylabel="", aspect="equal") g.despine(left=True, bottom=True) g.ax.margins(.02) for label in g.ax.get_xticklabels(): label.set_rotation(90) for artist in g.legend.legendHandles: artist.set_edgecolor(".7")
查看全国省会城市的幸福人数的占比条形图,经过图中能够看出,湖北省调查人数最多但幸福人数不算高;河南省和山东省的幸福人数的占比很是之高;即便内蒙古自治区的调查人数最少,可是幸福人数的占比倒是很是高的。
sns.set_theme(style="whitegrid") province_total = data['province'].groupby(data['province']).count().sort_values(ascending=False).to_frame() province_total.columns = ['total'] happiness_involved = [] for index in province_total.index: happiness_involved.append((data[data['province'] == index][data[data['province'] == index]['happiness'] > 3].shape[0])) happiness_involved = pd.DataFrame(happiness_involved, index=province_total.index) happiness_involved.columns = ['involved'] province_total['province'] = province_total.index.map({ 1 : 'Shanghai', 2 : 'Yunnan', 3 : 'Neimeng', 4 : 'Beijing', 5 : 'Jilin', 6 : 'Sichuan', 7 : 'Tianjin', 8 : 'Ningxia', 9 : 'Anhui', 10 : 'Shandong', 11 : 'Shanxi', 12 : 'Guangdong', 13 : 'Guangxi', 14 : 'Xinjiang', 15 : 'Jiangsu', 16 : 'Jiangxi', 17 : 'Hebei', 18 : 'Henan', 19 : 'Zhejiang', 20 : 'Hainan', 21 : 'Hubei', 22 : 'Hunan', 23 : 'Gansu', 24 : 'Fujian', 25 : 'XIzang', 26 : 'Guizhou', 27 : 'Liangning', 28 : 'Chongqing', 29 : 'Shaanxi', 30 : 'Qinghai', 31 : 'Heilongjiang'}) happiness_involved['province'] = province_total['province'] f, ax = plt.subplots(figsize=(6, 15)) sns.set_color_codes("pastel") sns.barplot(x="total", y="province", data=province_total, label="Total", color="b") sns.set_color_codes("muted") sns.barplot(x="involved", y="province", data=happiness_involved, label="Alcohol-involved", color="b") ax.legend(ncol=2, loc="lower right", frameon=True) ax.set(ylabel="", xlabel="Happiness of every province") sns.despine(left=True, bottom=True)
查看调查对象认为的当今社会的公平度中的幸福人数占比的直方图,多数调查对象认为当今社会是出于一个比较公平的,但仍有近半数人认为不算太公平。
sns.set_theme(style="ticks") f, ax = plt.subplots(figsize=(7, 5)) sns.despine(f) sns.histplot( data, hue='happiness', x="equity", multiple="stack", palette="light:m_r", edgecolor=".3", linewidth=.5 )
<AxesSubplot:xlabel='equity', ylabel='Count'>
根据多变量的散点图,幸福度高的人的都均匀地分布在了不一样身高、体重的地方;体形没有太大地影响幸福度。
sns.set_theme(style="white") sns.relplot(x="height_cm", y="weight_jin", hue="happiness", size="health", alpha=.5, palette="muted", data=data)
<seaborn.axisgrid.FacetGrid at 0x2512b5a2ca0>
绘制一个带有偏差带的直线图,横轴表示幸福度的提高,纵轴表示期待的年收入的提高,能够看出,在幸福度比较低的人期待的年收入一般会很高并带有很是大的偏差,随着幸福度的提高每一个人期待的年收入也没有变得更高,而且随之偏差带也变小了。
sns.set_theme(style="ticks") palette = sns.color_palette("rocket_r") sns.relplot( data=data, x="happiness", y="inc_exp", kind="line", palette=palette, aspect=.75, facet_kws=dict(sharex=False) )
<seaborn.axisgrid.FacetGrid at 0x2512b5e8d90>
XGBoost 是一个具备高效、灵活和可移植性的通过优化的分布式 梯度提高 库。它的实现是基于机器学习算法梯度提高框架。XGBoost 提供了并行的提高树(例如GBDT、GBM)以一个很是快速而且精准的方法解决了许多的数据科学问题。相同的代码能够运行在主流的分布式环境(如Hadoop、SGE、MPI)而且能够处理数十亿的样本。
XGBoost表明了极端梯度提高(Extreme Gradient Boosting)。
首先了解XGBoost的模型选择:集成决策树。树的集成模型是由CART(classification and regression trees)的集合组成。下面一张图简单说明了一个CART分出某我的是否喜欢玩电脑游戏的例子。
将每一个家庭成员分到不一样的叶子结点上,并赋给他们一个分数,每个叶结点对应了一个分数。CART与决策树是略有不一样的,决策树中每一个叶结点只包含了一个决策值。在CART上,真实的分数是与叶结点关联的,能够给出比分类更丰富的解释。这也容许了更具备原则、更一致性的优化方法。
一般,在实践中一个单独的树是不够强大的。实际上使用的是集成模型,将多个树的预测结果汇总到一块儿。
上图中是一个由两棵树集成在一块儿的例子。每个树的预测分数被加到一块儿获得最终的分数。一个重要的因素是两棵树努力补足彼此。能够写出模型:
其中,\(K\) 是树的数量,\(f\) 是一个在函数空间 \(\mathcal{F}\) 的函数,而且 \(\mathcal{F}\) 是一个全部可能的CART的集合。可被优化的目标函数为:
随机森林和提高树实际上都是相同的模型;不一样之处是如何去训练它们。若是须要一个用来预测的集成树,只须要写出一个并其能够工做在随机森林和提高树上。
正如同全部的监督学习同样,想要训练树就要先定义目标函数并优化它。
一个目标函数要老是包含训练的损失度和正则化项。
树须要训练的参数有 \(f_i\) 每个都包含了树的结构和叶结点的得分。训练树的结构是比传统的能够直接采用梯度的优化问题更难。一次性训练并学习到全部的树是很是棘手的。相反地,能够采起一个附加的策略,修正已经学习到的,同时增长一课新树。能够写出在第 \(t\) 步的预测值 \(\hat{y}_i^\left(t\right )\)
在每一步须要什么的树,增长一棵树,优化目标函数。
若是考虑使用均方偏差(MSE)做为损失函数,目标函数将会变成:
MSE的形式是很是优雅的,其中有一个一阶项(一般称做残差)和一个二阶项。对于其它的损失函数(例如logistic的损失函数)而言,是没有那么轻易就能够获得如此优雅的形式。所以,一般会使用泰勒公式损失函数展开到二阶项:
泰勒公式:函数 \(f(x)\) 在开区间 \((a,b)\) 上具备 \((n+1)\) 阶导数,对于任一 \(x\in(a,b)\) 有
其中,\(g_i\) 和 \(h_i\) 被定义为:
移除全部的常量,在第 \(t\) 步的目标函数就成了:
这就成了对于一颗新树的优化目标。一个很是重要的优点就是这个定义的目标函数的值只依赖于 \(g_i\) 和 \(h_i\) 这正是XGBoost支持自定义损失函数。能够优化各类损失函数,包括逻辑回归和成对排名(pairwise ranking),使用 \(g_i\) 和 \(h_i\) 做为输入的彻底相同的求解器求解。
定义树的复杂度 \(\Omega(f)\) 。首先提炼出树的定义 \(f(x)\) 为:
其中 \(w\) 是叶结点上的得分向量,\(q\) 是一个将每个数据点分配到对应的叶结点上的函数,\(T\) 是叶结点的数量。在XGBoost中,定义复杂度为:
有不止一个方法定义复杂度,可是这种方式在实践中能够表现的很好。正则化项是大多数树包都会被忽略的一部分。这是由于传统的树学习的对待仅仅强调改善杂质,模型的复杂度的控制留给了启发式。经过正式的定义它,能够更好的理解模型并使模型的表现更具备泛化能力。
经过对树模型的目标函数的推导,能够获得在第 \(t\) 步的树的目标值:
其中 \(I_j=\{i|q(x_i)=j\}\) 是第 \(i\) 个数据点被分配到第 \(j\) 个叶结点上的下标集合。改变了其累加的索引,由于被分配到相同的叶结点上的数据点获得的分数是统一的。进一步压缩表达令 \(G_j=\sum_{i\in I_j}g_i\) 和 \(H_j=\sum_{i\in I_j}h_i\)
其中,\(w_j\) 是彼此独立的,式子 \(G_jw_j+\frac{1}{2}(H_j+\lambda)w_j^2\) 是二次的,而且对于给定的结构 \(q(x)\) 最好的 \(w_j\) 和能够获得的最佳的目标规约为:
此公式衡量了一棵树的结构 \(q(x)\) 有多好。
基本上,对于一颗给定的树结构,将统计量 \(g_i\) 和 \(h_i\) 推到它们所属的叶结点上,并将它们累加到一块儿,使用公式计算衡量这棵树多好。这个分数相似于决策树中的不纯度度量(impurity measure),区别之处在于它还将模型复杂度考虑在内。
如今已经有了衡量一棵树好坏的指标,一个典型的想法是枚举全部可能的树并从中挑出最好的一个。实际上这是很是棘手的,因此应该尝试一次优化树的一个级别。具体来讲,是将一个子结点分割成两个叶结点,得分增益为:
这个公式能够被分解为几个部分,一部分是在新左子结点的得分,第二部分是在新右子结点上的得分,第三部分是原先叶结点上的得分,第四部分是在新叶结点上的正则化项。能够看到很是重要的因素是,若是增益小于 \(\gamma\) 更好的选择是不去分割出一个新分支。这就是基本的树模型的剪枝(pruning)技术。
对于实际中的数据,一般想要搜索一个最优的分割点。一个高效率的作法是,将全部的实例(记录)排好序,以下图示。
从左到右扫描计算全部分割方案的结构分数是很是高效的,而且能够快速地找出最优的分割点。
加性数训练的限制
由于将全部可能的树结构枚举出来是很是棘手的,因此每次增长一个分割点(split)。这个方法在大多数状况下运行的很好,可是有一些边缘案例致使这个方法失效。对于退化模型的训练结果,每次仅仅考虑一个特征维度。参考Can Gradient Boosting Learn Simple Arithmetic?
import pandas as pd import numpy as np import matplotlib.pyplot as plt
train = pd.read_csv('./data/happiness_train_complete_nona.csv', index_col='id', parse_dates=['survey_time']) test = pd.read_csv('./data/happiness_test_complete_nona.csv', index_col='id', parse_dates=['survey_time']) submit = pd.read_csv('./data/happiness_submit.csv', index_col='id')
from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error X = train.drop(['happiness', 'survey_time'], axis=1) y = train['happiness'] X_train, X_test, y_train, y_test = train_test_split(X, y)
from xgboost import XGBRegressor from xgboost import plot_importance model = XGBRegressor(gamma=0.1, learning_rate=0.1) model.fit(X_train, y_train) mean_squared_error(y_test, model.predict(X_test))
0.4596381608913307
predict = pd.DataFrame({'happiness' : model.predict(test.drop('survey_time', axis=1))}, index=test.index)
submit.loc[predict.index, 'happiness'] = predict['happiness']
submit.to_csv('./data/predict.csv')