先聊聊日常
最近在学flask web开发这一块,然后加上java和算法,着实脑阔有点疼。学不下去的时候就去刷刷视频,看到有人在讲一个16年kaggle上的竞赛,关于移动用户人口统计,不过视频上没怎么细讲,可我的兴趣就却勾起来了,立马跑下床打开kaggle看了一下这个竞赛的内容,数据集主要是年龄,性别,用户的地理位置(经纬度),用户的手机品牌,用户的id等等,数据集还是比较大的,一共有280多M吧,然后今天去实验室就暂时放下了flask,开始做起这个来了,也当是适时放松一下。
开始动手
简单的看了一下数据集的介绍,因为这次竞赛是中国举办的,所以手机品牌也是中文写的,所以还是比较友善的。因为数据集太大,属性太多,我不可能每一样都去训练去预测,所以我只选择了数据可视化和针对用户年龄和divice_id进行预测。这里的device_id就是每个手机的一个标志吧,反正简单的说就是预测用这款手机的人的性别年龄。
1.首先我是做了一下数据可视化
本来数据可视化才是我的初心,因为我看到了别人画出来美丽的可视化图像我也想动手试试。所以我把这个分成了两个部分,一是数据可视化,二是用keras去弄个神经网络训练了一下,得到预测值。
环境呢:我用的是ubuntu16.04+tensorflow-gpu+keras+jupyter notebook
当然,用windows的tensorflow-gpu是一样的,只不过数据量有点大,我怕我那小小的笔记本扛不住所以用的是实验室里专门搭的那台电脑。
好了,开始讲讲数据可视化部分,一开始还是常规的导入相关的库
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib.cm as cm
import os
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import log_loss
#解决basemap导入问题
import conda
conda_file_dir = conda.__file__
conda_dir = conda_file_dir.split('lib')[0]
proj_lib = os.path.join(os.path.join(conda_dir, 'share'), 'proj')
os.environ["PROJ_LIB"] = proj_lib
from mpl_toolkits.basemap import Basemap
这里basemap的导入可能会出现一些问题,不过像我代码这样写就可以啦。
然后就是导入数据并查看数据内容,检查有无缺失的情况
#导入数据
gatrain=pd.read_csv('/media/digits/KINGSTON/kaggle/gender_age_train.csv')
gatest=pd.read_csv('/media/digits/KINGSTON/kaggle/gender_age_test.csv')
#查看一下数据
gatrain.info()
gatrain.head(8)
#可视化一下训练集数据,用之前的条形图
gatrain.group.value_counts().sort_index(ascending=False).plot(kind='barh')
#对性别进行分组,观察训练集中的性别比例
gatrain.gender.value_counts().plot(kind='bar')
可以看到训练集中各个年龄的人数和男女性别比例的分布
接下来划分的更细一点
#对训练集中不同性别不同年龄的人进行数量统计,并用柱形图可视化
c=gatrain.groupby(['age','gender']).size().unstack().reindex(index=np.arange(gatrain.age.min()
,gatrain.age.max()+1)).fillna(0)
ax1,ax2=c.plot(kind='bar',figsize=(12,6),subplots=True)
ax1.vlines(np.array([23,26,28,32,42])-0.5,0,1800,alpha=0.5,linewidth=1,color='red')
ax2.vlines(np.array([22,26,28,31,38])-0.5,0,3000,alpha=0.5,linewidth=1,color='red')
然后简单的对训练集的年龄区间进行Label标准化,看了一下log_loss的值。这个方法在等下模型训练中还会用到所以这里就不多讲了。
再来看看用户手机的信息,还是一样的导入数据,查看内容,检查缺失
这里代码我就不多贴了,和之前我写的数据分析中用的一样,直接上图
有重复的id出现,所以我们看看这些用户是不是使用的同一品牌的手机
dup=phone.loc[phone.device_id.isin(dup.index)]
first=dup.groupby('device_id').first()
last=dup.groupby('device_id').last()
diff=(first!=last).sum(axis=1).nonzero()
pd.concat((first.iloc[diff],last.iloc[diff]),axis=1)
可以看到有的一个device_id对应两个品牌的手机
最后呢,我就用basemap对用户使用手机的区域画出可视化图形来。
df=pd.read_csv('/media/digits/KINGSTON/kaggle/events.csv',dtype={'device_id':np.str})
df.head(10)
df.info()
#可以看到一共有3252949个数据,数据量太大了,所以我们抽样来数据可视化
df_sample=df.sample(n=100000)
plt.figure(1,figsize=(12,6))
m1=Basemap(projection='merc',
llcrnrlat=-60,
urcrnrlat=65,
llcrnrlon=-180,
urcrnrlon=180,
lat_ts=0,
resolution='c')
m1.fillcontinents(color='#191919',lake_color='#000000')
m1.drawmapboundary(fill_color='#000000')
m1.drawcountries(linewidth=0.15,color='w')
mxy=m1(df_sample['longitude'].tolist(),df_sample['latitude'].tolist())
m1.scatter(mxy[0],mxy[1],s=3,c='#1292db',lw=0,alpha=1,zorder=5)
'''这里的中文显示问题我在ubuntu上一直没弄好,改了那个matplotlib里面的文件
但是还是显示错误,最后只能英文了,估计是那个电脑上没有下载中文字体的原因。'''
plt.title('Global view')
plt.show()
最后对中国境内用户分布更突出的画出来
#对中国境内再仔细画出
lon_min,lon_max=75,135
lat_min,lat_max=15,55
in_china=(df['longitude']>lon_min) &\
(df['longitude']<lon_max) &\
(df['latitude']>lat_min) &\
(df['latitude']<lat_max)
df_china=df[in_china].sample(n=100000)
#开始画中国内部分布
plt.figure(2,figsize=(12,6))
m2=Basemap(projection='merc',
llcrnrlat=lat_min,
urcrnrlat=lat_max,
llcrnrlon=lon_min,
urcrnrlon=lon_max,
lat_ts=35,
resolution='i')
m2.fillcontinents(color='#191919',lake_color='#000000')
m2.drawmapboundary(fill_color='#000000')
m2.drawcountries(linewidth=0.15,color='w')
mxy=m2(df_china['longitude'].tolist(),df_china['latitude'].tolist())
m2.scatter(mxy[0],mxy[1],s=5,c='#1292db',lw=0,alpha=0.05,zorder=5)
到这里,数据可视化就差不多完成了,当然还有各个品牌手机数量的统计比较啊等等数据我并没有可视化出来,原因嘛还是因为当时没想到这么多,哈哈哈。
2.开始针对用户年龄性别构建模型进行预测
一般来说,这种竞赛上使用的模型算法各式各样的都有,不过最近几年比较火的就是神经网络、卷积神经网络这一类,或者是集成学习,模型融合,当然也有些人用简单的logistic和svm也有很好的表现。再加上一些特征工程,交叉验证,网格搜索等等方法,都能提高模型的性能。这次呢,我做了一个简单的神经网络模型对用户年龄性别进行预测。
#导入相关的库
import numpy as np
import pandas as pd
import os
from scipy.sparse import csr_matrix,hstack
from keras.models import Sequential
from keras.layers import Dense,Dropout,Activation
from keras.wrappers.scikit_learn import KerasClassifier
from keras.utils import np_utils
from keras.optimizers import SGD
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.pipeline import Pipeline
from sklearn.metrics import log_loss
CUDA_VISIBLE_DEVICES=1#使用GPU
对了,这里提一句,有可能你安装了tensorflow-gpu,但是模型训练的时候你看nvidia-smi中GPU还是没使用,这个时候就需要uninstall tensorflow,tensorflow-gpu和keras,然后重新安装tensorflow-gpu和keras,确保是在用GPU训练。
#设置随机数种子
seed=5
np.random.seed(seed)
#导入数据
ga_train=pd.read_csv('/media/digits/KINGSTON/kaggle/gender_age_train.csv',index_col='device_id')
ga_test=pd.read_csv('/media/digits/KINGSTON/kaggle/gender_age_test.csv',index_col='device_id')
phone=pd.read_csv('/media/digits/KINGSTON/kaggle/phone_brand_device_model.csv')
#除去手机数据集中重复的设备id
phone=phone.drop_duplicates('device_id',keep='first').set_index('device_id')
events=pd.read_csv('/media/digits/KINGSTON/kaggle/events.csv',parse_dates=['timestamp'],index_col='event_id')
#根据事件分离数据
dd=events.device_id.unique()
gatrain=ga_train
gatest_events=ga_test.index.intersection(dd)
gatest=ga_test[~ga_test.index.isin(gatest_events)]
#对品牌进行数字编码
brandencoder=LabelEncoder().fit(phone.phone_brand)
phone['brand']=brandencoder.transform(phone['phone_brand'])
gatrain['brand']=phone['brand']
gatest['brand']=phone['brand']
nbrands=len(brandencoder.classes_)
#设备模型
m=phone.phone_brand.str.cat(phone.device_model)
modelencoder=LabelEncoder().fit(m)
phone['model']=modelencoder.transform(m)
gatrain['model']=phone['model']
gatest['model']=phone['model']
nmodels=len(modelencoder.classes_)
#把得到的模型和品牌在训练集和测试集上覆盖重叠
brand_without_training=set(gatest.brand)-set(gatrain.brand)
brand_without_testing=set(gatrain.brand)-set(gatest.brand)
model_without_training=set(gatest.model)-set(gatrain.model)
model_without_testing=set(gatrain.model)-set(gatest.model)
#除掉不相关的数据
test_without_training=gatest[(gatest.model.isin(model_without_training))&(gatest.brand.isin(brand_without_training))]
training_without_testing=gatrain[(gatrain.model.isin(model_without_testing))&(gatrain.brand.isin(brand_without_testing))]
gatest=gatest[~gatest.brand.isin(test_without_training.brand)]
gatrain=gatrain[~gatrain.brand.isin(training_without_testing.brand)]
#区分训练集和测试集
gatrain['trainrow']=np.arange(gatrain.shape[0])
gatest['testrow']=np.arange(gatest.shape[0])
#压缩稀疏矩阵,得到特征
xtr_brand=csr_matrix((np.ones(gatrain.shape[0]),(gatrain.trainrow,gatrain.brand)),shape=(gatrain.shape[0],nbrands))
xte_brand=csr_matrix((np.ones(gatest.shape[0]),(gatest.testrow,gatest.brand)),shape=(gatest.shape[0],nbrands))
print('品牌特征:train shape{},test shape{}'.format(xtr_brand.shape,xte_brand.shape))
xtr_model=csr_matrix((np.ones(gatrain.shape[0]),(gatrain.trainrow,gatrain.model)),shape=(gatrain.shape[0],nmodels))
xte_model=csr_matrix((np.ones(gatest.shape[0]),(gatest.testrow,gatest.model)),shape=(gatest.shape[0],nmodels))
print('模型特征:train shape{},test shape{}'.format(xtr_model.shape,xte_model.shape))
#合并所有特征
Xtrain=hstack((xtr_brand,xtr_model),format='csr')
Xtest=hstack((xte_brand,xte_model),format='csr')
print('所有特征:train shape{},test shape{}'.format(Xtrain.shape,Xtest.shape))
#开始构建模型并训练
targetencoder=LabelEncoder().fit(gatrain.group)
y=targetencoder.transform(gatrain.group)
nclasses=len(targetencoder.classes_)
dummy_y=np_utils.to_categorical(y)
#定义批次
def batch_generator(X,y,batch_size,shuffle):
number_of_batches=np.ceil(X.shape[0]/batch_size)
count=0
sample_index=np.arange(X.shape[0])
if shuffle:
np.random.shuffle(sample_index)
while True:
batch_index=sample_index[batch_size*count:batch_size*(count+1)]
X_batch=X[batch_index,:].toarray()
y_batch=y[batch_index]
count+=1
yield X_batch,y_batch
if(count==number_of_batches):
if shuffle:
np.random.shuffle(sample_index)
count=0
def batch_generatorp(X,batch_size,shuffle):
number_of_batches=X.shape[0] / np.ceil(X.shape[0]/batch_size)
count=0
sample_index=np.arange(X.shape[0])
while True:
batch_index=sample_index[batch_size*count:batch_size*(count+1)]
X_batch=X[batch_index,:].toarray()
count+=1
yield X_batch
if(count==number_of_batches):
count=0
#定义模型
def baseline_model():
model=Sequential()
model.add(Dense(50,input_dim=Xtrain.shape[1],init='normal',activation='tanh'))#定义网络层
model.add(Dropout(0.5))#添加遗忘层,防止过拟合
model.add(Dense(12,init='normal',activation='sigmoid'))
model.compile(loss='categorical_crossentropy',optimizer='adadelta',metrics=['accuracy'])
return model
model=baseline_model()
#分割训练集和验证集
X_train,X_val,y_train,y_val=train_test_split(Xtrain,dummy_y,test_size=0.002,random_state=42)
#训练
fit=model.fit_generator(generator=batch_generator(X_train,y_train,400,True),
nb_epoch=15,samples_per_epoch=70496,
validation_data=(X_val.todense(),y_val),
verbose=2)
scores_val=model.predict_generator(generator=batch_generatorp(X_val,400,False),val_samples=X_val.shape[0])
scores=model.predict_generator(generator=batch_generatorp(Xtest,800,False),val_samples=Xtest.shape[0])
print('logloss val{}'.format(log_loss(y_val,scores_val)))
pred=pd.DataFrame(scores,index=gatest.index,columns=targetencoder.classes_)
#写入文件,保存结果
pred.to_csv('/media/digits/KINGSTON/kaggle/标签和品牌预测结果.csv',index=True)
最后在验证集上的对数损失是2.37,预测结果也保存到了csv文件中。
总结
今天算是放松了一天吧,没有去为算法想破脑袋,也没有搭建web改bug啥的,就是晚上回来看了一会java,所以也没有前几天那么累。好多人都让我休息,干嘛把自己逼得这么紧,放个暑假还一天忙到晚,但是我慢慢喜欢上了这种充实。之前我也喜欢玩游戏,七个赛季的王者,还经常吃吃鸡lol啥的,可是那样一天一下子就过去了,躺着想想今天好像什么也没做不是浪费生命了嘛。之前我也不是不优秀,但是人总是要想着变得更加优秀吧。现在这样,每天保证一定量的学习然后打打球,偶尔中午休息的时候玩把云顶,充实又快乐,这才是我想要的生活,这才是忘掉烦恼的最好办法。(烦恼是什么?又丑又穷还没女朋友呗)哈哈哈,不过说真的,下学期就大三了也要开始慢慢准备考研复习了,还是要更努力点才行。悄咪咪说一句,目标华科,冲冲冲!!!