通過移動設備行為數據預測性別年齡


1. 通過行為習慣對移動用戶人口屬性(年齡+性別)進行預測。

2. 數據及包含~20萬用戶數據,分成12組,同時提供了用戶行為屬性,如:手機品牌、型號、APP的類型等。

3. 通過logloss評價

 

main.py

  1 # -*- coding: utf-8 -*-
  2 
  3 
  4 import pandas as pd
  5 import os
  6 from pd_tools import split_train_test, get_part_data
  7 import numpy as np
  8 from sklearn.preprocessing import LabelEncoder, OneHotEncoder
  9 from sklearn.preprocessing import StandardScaler
 10 from sklearn.linear_model import LogisticRegression
 11 from sklearn import svm
 12 from sklearn.decomposition import PCA
 13 from ml_tools import get_best_model
 14 from sklearn.metrics import log_loss
 15 from sklearn.feature_selection import VarianceThreshold
 16 
 17 # 數據集變量聲明
 18 dataset_path = './dataset'
 19 gender_age_filename = 'gender_age.csv'
 20 phone_brand_device_model_filename = 'phone_brand_device_model.csv'
 21 events_filename = 'events.csv'
 22 app_events_filename = 'app_events.csv'
 23 app_labels_filename = 'app_labels.csv'
 24 label_categories_filename = 'label_categories.csv'
 25 
 26 train_gender_age_filename = 'gender_age_train.csv'
 27 test_gender_age_filename = 'gender_age_test.csv'
 28 
 29 is_first_run = False
 30 
 31 
 32 def run_main():
 33     """
 34         主函數
 35     """
 36     if is_first_run:
 37         # 1. 分割數據集
 38         print('分割數據集')
 39         all_gender_age = pd.read_csv(os.path.join(dataset_path, gender_age_filename))
 40         df_train, df_test = split_train_test(all_gender_age)
 41         # 查看訓練集測試集基本信息
 42         print('訓練集中各類的數據個數:', df_train.groupby('group').size())
 43         print('測試集中各類的數據個數:', df_test.groupby('group').size())
 44 
 45         # 保存分割的數據集
 46         df_train.to_csv(os.path.join(dataset_path, train_gender_age_filename),
 47                         index=False)
 48         df_test.to_csv(os.path.join(dataset_path, test_gender_age_filename),
 49                        index=False)
 50 
 51     # 2. 加載數據
 52     print('加載數據')
 53     # 加載數據
 54     gender_age_train = pd.read_csv(os.path.join(dataset_path, train_gender_age_filename),
 55                                    index_col='device_id')
 56     gender_age_test = pd.read_csv(os.path.join(dataset_path, test_gender_age_filename),
 57                                   index_col='device_id')
 58 
 59     # 選取部分數據用於實驗
 60     percent = 0.1
 61     gender_age_train = get_part_data(gender_age_train, percent=percent)
 62     gender_age_test = get_part_data(gender_age_test, percent=percent)
 63 
 64     phone_brand_device_model = pd.read_csv(os.path.join(dataset_path, phone_brand_device_model_filename))
 65     # 去掉重復數據
 66     phone_brand_device_model = phone_brand_device_model.drop_duplicates('device_id').set_index('device_id')
 67 
 68     events = pd.read_csv(os.path.join(dataset_path, events_filename),
 69                          usecols=['device_id', 'event_id'], index_col='event_id')
 70     app_events = pd.read_csv(os.path.join(dataset_path, app_events_filename),
 71                              usecols=['event_id', 'app_id'])
 72     # app_labels = pd.read_csv(os.path.join(dataset_path, app_labels_filename))
 73 
 74     # 3. 特征工程
 75     # 3.1 手機品牌特征
 76     # 使用LabelEncoder將類別轉換為數字
 77     brand_label_encoder = LabelEncoder()
 78     brand_label_encoder.fit(phone_brand_device_model['phone_brand'].values)
 79     phone_brand_device_model['brand_label_code'] = \
 80         brand_label_encoder.transform(phone_brand_device_model['phone_brand'].values)
 81     gender_age_train['brand_label_code'] = phone_brand_device_model['brand_label_code']
 82     gender_age_test['brand_label_code'] = phone_brand_device_model['brand_label_code']
 83 
 84     # 使用OneHotEncoder將數字轉換為OneHot碼
 85     brand_onehot_encoder = OneHotEncoder()
 86     brand_onehot_encoder.fit(phone_brand_device_model['brand_label_code'].values.reshape(-1, 1))
 87     tr_brand_feat = brand_onehot_encoder.transform(gender_age_train['brand_label_code'].values.reshape(-1, 1))
 88     te_brand_feat = brand_onehot_encoder.transform(gender_age_test['brand_label_code'].values.reshape(-1, 1))
 89 
 90     print('[手機品牌]特征維度:', tr_brand_feat.shape[1])
 91 
 92     # 3.2 手機型號特征
 93     # 合並手機品牌與型號字符串
 94     phone_brand_device_model['brand_model'] = \
 95         phone_brand_device_model['phone_brand'].str.cat(phone_brand_device_model['device_model'])
 96 
 97     # 使用LabelEncoder將類別轉換為數字
 98     model_label_encoder = LabelEncoder()
 99     model_label_encoder.fit(phone_brand_device_model['brand_model'].values)
100     phone_brand_device_model['brand_model_label_code'] = \
101         model_label_encoder.transform(phone_brand_device_model['brand_model'].values)
102     gender_age_train['brand_model_label_code'] = phone_brand_device_model['brand_model_label_code']
103     gender_age_test['brand_model_label_code'] = phone_brand_device_model['brand_model_label_code']
104 
105     # 使用OneHotEncoder將數字轉換為OneHot碼
106     model_onehot_encoder = OneHotEncoder()
107     model_onehot_encoder.fit(phone_brand_device_model['brand_model_label_code'].values.reshape(-1, 1))
108     tr_model_feat = model_onehot_encoder.transform(gender_age_train['brand_model_label_code'].values.reshape(-1, 1))
109     te_model_feat = model_onehot_encoder.transform(gender_age_test['brand_model_label_code'].values.reshape(-1, 1))
110 
111     print('[手機型號]特征維度:', tr_model_feat.shape[1])
112 
113     # 3.3 安裝app特征
114     device_app = app_events.merge(events, how='left', left_on='event_id', right_index=True)
115     # 運行app的總次數
116     n_run_s = device_app['app_id'].groupby(device_app['device_id']).size()
117 
118     # 運行app的個數
119     n_app_s = device_app['app_id'].groupby(device_app['device_id']).nunique()
120 
121     gender_age_train['n_run'] = n_run_s
122     gender_age_train['n_app'] = n_app_s
123 
124     # 填充缺失數據
125     gender_age_train['n_run'].fillna(0, inplace=True)
126     gender_age_train['n_app'].fillna(0, inplace=True)
127 
128     gender_age_test['n_run'] = n_run_s
129     gender_age_test['n_app'] = n_app_s
130 
131     # 填充缺失數據
132     gender_age_test['n_run'].fillna(0, inplace=True)
133     gender_age_test['n_app'].fillna(0, inplace=True)
134 
135     tr_run_feat = gender_age_train['n_run'].values.reshape(-1, 1)
136     tr_app_feat = gender_age_train['n_app'].values.reshape(-1, 1)
137 
138     te_run_feat = gender_age_test['n_run'].values.reshape(-1, 1)
139     te_app_feat = gender_age_test['n_app'].values.reshape(-1, 1)
140 
141     # 3.4 合並所有特征
142     tr_feat = np.hstack((tr_brand_feat.toarray(), tr_model_feat.toarray(), tr_run_feat, tr_app_feat))
143     te_feat = np.hstack((te_brand_feat.toarray(), te_model_feat.toarray(), te_run_feat, te_app_feat))
144     print('特征提取結束')
145     print('每個樣本特征維度:', tr_feat.shape[1])
146 
147     # 3.5 特征范圍歸一化
148     scaler = StandardScaler()
149     tr_feat_scaled = scaler.fit_transform(tr_feat)
150     te_feat_scaled = scaler.transform(te_feat)
151 
152     # 3.6 特征選擇
153     sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
154     tr_feat_scaled_sel = sel.fit_transform(tr_feat_scaled)
155     te_feat_scaled_sel = sel.transform(te_feat_scaled)
156 
157     # 3.7 PCA降維操作
158     pca = PCA(n_components=0.95)  # 保留95%共享率的特征向量
159     tr_feat_scaled_sel_pca = pca.fit_transform(tr_feat_scaled_sel)
160     te_feat_scaled_sel_pca = pca.transform(te_feat_scaled_sel)
161     print('特征處理結束')
162     print('處理后每個樣本特征維度:', tr_feat_scaled_sel_pca.shape[1])
163 
164     # 4 為數據添加標簽
165     group_label_encoder = LabelEncoder()
166     group_label_encoder.fit(gender_age_train['group'].values)
167     y_train = group_label_encoder.transform(gender_age_train['group'].values)
168     y_test = group_label_encoder.transform(gender_age_test['group'].values)
169 
170     # 5. 訓練模型
171     # 5.1 邏輯回歸模型
172     print('訓練邏輯回歸模型...')
173     lr_param_grid = [
174         {'C': [1e-3, 1e-2, 1e-1, 1, 10, 100]}
175     ]
176     lr_model = LogisticRegression()
177     best_lr_model = get_best_model(lr_model,
178                                    tr_feat_scaled_sel_pca, y_train,
179                                    lr_param_grid, cv=3)
180     y_pred_lr = best_lr_model.predict_proba(te_feat_scaled_sel_pca)
181 
182     # 5.2 SVM
183     print('訓練SVM模型...')
184     svm_param_grid = [
185         {'C': [1e-2, 1e-1, 1, 10, 100], 'gamma': [0.001, 0.0001], 'kernel': ['rbf']},
186     ]
187 
188     # 設置probability=True用於輸出預測概率
189     svm_model = svm.SVC(probability=True)
190     best_svm_model = get_best_model(svm_model,
191                                     tr_feat_scaled_sel_pca, y_train,
192                                     svm_param_grid, cv=3)
193     y_pred_svm = best_svm_model.predict_proba(te_feat_scaled_sel_pca)
194 
195     # 6. 查看結果
196     print('邏輯回歸模型 logloss:', log_loss(y_test, y_pred_lr))
197     print('SVM logloss:', log_loss(y_test, y_pred_svm))
198 
199 
200 if __name__ == '__main__':
201     run_main()

 

ml_tools.py

 1 # -*- coding: utf-8 -*-
 2 
 3 from sklearn.model_selection import GridSearchCV
 4 
 5 
 6 def get_best_model(model, X_train, y_train, params, cv=5):
 7     """
 8         交叉驗證獲取最優模型
 9         默認5折交叉驗證
10     """
11     clf = GridSearchCV(model, params, cv=cv)
12     clf.fit(X_train, y_train)
13     return clf.best_estimator_

pd_tools.py

 1 # -*- coding: utf-8 -*-
 2 
 3 import pandas as pd
 4 import math
 5 
 6 
 7 def split_train_test(df_data, size=0.8):
 8     """
 9         分割訓練集和測試集
10     """
11     # 為保證每個類中的數據能在訓練集中和測試集中的比例相同,所以需要依次對每個類進行處理
12     df_train = pd.DataFrame()
13     df_test = pd.DataFrame()
14 
15     labels = df_data['group'].unique().tolist()
16     for label in labels:
17         # 找出group的記錄
18         df_w_label = df_data[df_data['group'] == label]
19         # 重新設置索引,保證每個類的記錄是從0開始索引,方便之后的拆分
20         df_w_label = df_w_label.reset_index()
21 
22         # 默認按80%訓練集,20%測試集分割
23         # 這里為了簡化操作,取前80%放到訓練集中,后20%放到測試集中
24         # 當然也可以隨機拆分80%,20%(嘗試實現下DataFrame中的隨機拆分)
25 
26         # 該類數據的行數
27         n_lines = df_w_label.shape[0]
28         split_line_no = math.floor(n_lines * size)
29         text_df_w_label_train = df_w_label.iloc[:split_line_no, :]
30         text_df_w_label_test = df_w_label.iloc[split_line_no:, :]
31 
32         # 放入整體訓練集,測試集中
33         df_train = df_train.append(text_df_w_label_train)
34         df_test = df_test.append(text_df_w_label_test)
35 
36     df_train = df_train.reset_index()
37     df_test = df_test.reset_index()
38     return df_train, df_test
39 
40 
41 def get_part_data(df_data, percent=1):
42     """
43         從df_data中按percent選取部分數據
44     """
45     df_result = pd.DataFrame()
46     grouped = df_data.groupby('group')
47     for group_name, group in grouped:
48         n_group_size = group.shape[0]
49         n_part_size = math.floor(n_group_size * percent)
50         part_df = group.iloc[:n_part_size, :]
51         df_result = df_result.append(part_df)
52 
53     return df_result

dataset下載地址
鏈接:http://pan.baidu.com/s/1dE7D0bf
密碼:yapd


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM