【火炉炼AI】机器学习018-项目案例:根据大楼进出人数预测是否举办活动
【火爐煉AI】機器學習018-項目案例:根據大樓進出人數預測是否舉辦活動
(本文所使用的Python庫和版本號: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
我們經常看到辦公大樓中人來人往,進進出出,在平時沒有什么活動的時候,進出大樓的人數會非常少,而一旦舉辦有大型商業活動,則人山人海,熙熙攘攘,所以很明顯,大樓進出的人數和大樓是否舉辦活動有很明顯的關聯,那么,是否可以構建一個模型,通過大樓進出人數來預測該大樓是否在舉辦某種活動了?
答案是肯定的,且聽煉丹老頑童娓娓道來。
1. 準備數據集
本項目案例所使用到的原始數據集來源于: UCI大學數據集,該數據集是公開的,讀者可以自行下載該數據集到自己的本地電腦上。
1.1 了解數據集
從該數據集的官方網站上,我們可以看到該數據集的基本介紹:
可以看出,該數據集一共有10080個樣本,沒有缺失數據,一共有四個基本屬性,集四個features,可以用于分類模型和時序模型,此處我們只是用來進行“是否舉辦活動”的預測,很明顯,是一個多分類問題,具體而言是一個二分類問題。
在我們下載該數據后,通過查看比對,發現該有效數據主要存放在兩個文件中(CalIt2.data和CalIt2.events),其中CalIt2.data中存儲了10080條數據記錄,每一條數據包含有四列,每一列的信息說明如下表所示。而CalIt2.events包括有30條數據記錄,也包括有四列,其中的第一列是日期,第二列是活動開始時間,第三列是活動結束時間,第四列表示有活動。下是我總結的本項目案例數據集的基本信息。
其中表格中前面四行表示數據集的四個features,這些信息位于CalIt2.data中,最后一行表示數據集的Label,位于CalIt2.events中。
1.2 數據規整
由于本項目的數據集位于兩個不同的文件中,同時兩個文件的樣本格式也不是一一對應,故而在構建模型之前,需要我們對數據進行規整,組成我們所需要的數據類型。
此處所用到的數據規整至少包括有三個方面:將同一個時間段內進出大樓的人數統一到一行,將CalIt2.events中的標記數據加載到CalIt2.data中組成完整的數據集,將數據集中的日期轉換為星期數,作為一個特征向量。
1.2.1 進出大樓人員統一到一行
由于原始數據集CalIt2.data中,進大樓的位于一行,最前面的代號為9,出大樓的位于另外一行,最前面的代號為7,故而我們需要將這兩行數據統一到一行,下面是實現代碼,所采用的核心思想是:用DataFrame的布爾索引來獲取進出大樓的單獨一個DataFrame,然后將這兩個DF整合到一個DataFrame中。
# 將feature_set中進樓和出樓的人員統計到一行。 # 目前數據集中出樓人員(代號7)位于偶數行,進樓人員(代號9)位于奇數行。 # 可以使用for in 方式依次取出各行的人員數,但此處我更愿意使用布爾型索引 code_7=feature_set[0]==7 code_7_data=feature_set[code_7].iloc[:,3].reset_index(drop=True) code_9=feature_set[0]==9 code_9_data=feature_set[code_9].reset_index(drop=True) # print(code_9_data)# OK feature_set2=code_9_data feature_set2[4]=code_7_data feature_set2.drop([0],axis=1,inplace=True) # 刪除第0列 # print(feature_set2) # col3 表示in,col4表示out,打印沒有問題 # feature_set2.to_csv('d:/feature_set2.csv') # 保存以便查看是否有誤 復制代碼打印結果可以參考我的原始代碼(我的github),此處由于打印出來后結果太長,我沒有貼上來。
1.2.2 將label添加到Feature_set中組成完整的數據集
由于原始數據集的features特征向量放置在CalIt2.data文件中,且Label向量放置在CalIt2.events中,故而有必要將這兩部分整合到一起。但是,整合過程并不是簡單的將兩個DataFrame連接起來,而要考慮時間范圍。在CalIt2.events文件中列舉了有活動的日期和起止時間,故而我們需要對Features中的日期和時間拿出來和CalIt2.events進行逐一比對,如果日期和時間落在events文件中,則表示這個時間段有活動,需要作出特殊標記。有很多種方法可以是實現這種逐一比對,下面我還是采用DataFrame的切片和索引來完成,我認為,這種方式算是速度比較快的一種方式。
# 下面是如何將feature_set2和label_set整合到一個DataFrame中來 # 要判斷時間,如果feature_set2中的日期和時間都落在了label_set對應的時間內, # 則表示有event發生,用1表示,如果沒有,用0表示。 # 比較日期時間的方法有很多,此處我采用比較簡單的方法 feature_set2[5]=0 # 表示是否有event的列都初始化為0def calc_mins(time_str):nums=time_str.split(':')return 60*int(nums[0])+int(nums[1]) # 將時間轉換為分鐘數,此處不用考慮秒for row_id,date in enumerate(label_set[0]): # 先取出label中的日期temp_df=feature_set2[feature_set2[1]==date]if temp_df is None:continuestart_min=calc_mins(label_set.iloc[row_id,1])stop_min=calc_mins(label_set.iloc[row_id,2])for row in temp_df[2]: # 在逐一判斷時間是否位于label中時間之間feature_min=calc_mins(row)if feature_min>=start_min and feature_min<=stop_min: feature_row=temp_df[temp_df[2]==row].index.tolist()feature_set2.loc[feature_row,5]=1 # feature_set2.to_csv('d:/feature_set2_withLabel.csv') # 保存后打印查看沒有問題 復制代碼1.2.3 將日期轉換為星期數
這個相對于前面兩個數據規整方面,要簡單得多,直接貼代碼。
# 進一步處理,由于日期在以后的日子里不可重復,作為feature并不合適,而可以用星期數來代替, feature_set2[0]=pd.to_datetime(feature_set2[1]) # print(feature_set2.tail()) feature_set2[0]=feature_set2[0].map(lambda x: x.strftime('%w')) # 將日期轉換為星期數 feature_set2=feature_set2.reindex(columns=range(6)) print(feature_set2.tail()) # 查看轉換沒有問題 feature_set2.to_csv('E:\PyProjects\DataSet\BuildingInOut/Sorted_Set.txt') # 將整理好的數據集保存,下次可以直接讀取 復制代碼-----------------------輸---------出--------------------------------
0 1 2 3 4 5 5035 6 11/05/05 21:30:00 0 0 0 5036 6 11/05/05 22:00:00 0 3 0 5037 6 11/05/05 22:30:00 0 0 0 5038 6 11/05/05 23:00:00 0 0 0 5039 6 11/05/05 23:30:00 0 1 0
-------------------------完-------------------------------------
處理完成之后的feature_set2可以直接保存一下,這樣下次可以直接調用這個數據規整之后的文件,讀取里面的數據集來訓練和測試即可。
1.3 數據編碼
很明顯,從上面的數據集中可以看到第1列是日期,不適合做特征向量,需要刪除,而第2列是字符串類型,沒法用于機器學習,故而我們需要對第2列進行編碼,如下代碼:
# 由于第1列只是包含日期,作為特征向量并不合適,故而需要刪除 feature_set2.drop([1],axis=1,inplace=True) # 而第2列明顯是字符串類型,里面的內容對機器學習而言如同天書,故需要編碼 from sklearn import preprocessing time_encoder=preprocessing.LabelEncoder() feature_set2[2]=time_encoder.fit_transform(feature_set2[2]) print(feature_set2.tail()) 復制代碼------------------輸---------出--------------------------------
0 2 3 4 5 5035 6 43 0 0 0 5036 6 44 0 3 0 5037 6 45 0 0 0 5038 6 46 0 0 0 5039 6 47 0 1 0
---------------------完-------------------------------------
所以,可以看到,第2列已經變成了數字編碼,這部分內容在我以前的文章中用到過很多次。如【火爐煉AI】機器學習013-用樸素貝葉斯分類器估算個人收入階層
########################小**********結#################
1. 在網絡上,我找了好久都沒有找到如何處理這個數據集,好多都是直接給出處理后的結果,所以此處我就自己對這個數據集進行了規整,并將規整的代碼放出來。
2. 數據集的規整和預處理往往會花掉機器學習的大部分時間,此處因為已經有了現成數據,僅僅是對數據進行規整,故而耗時相對較少。
3. Pandas和Numpy基本上是數據預處理,數據清洗,數據規整的有力神器,一定要熟練掌握。
#####################################################
2. 使用SVM構建分類器
SVM分類器的構建和其他項目案例中并沒有太大差別,可以直接參考我的其他文章:【火爐煉AI】機器學習014-用SVM構建非線性分類模型.下面直接貼出代碼。
# 下面是使用SVM構建分類器 from sklearn.svm import SVC classifier=SVC(kernel='rbf',probability=True,class_weight='balanced') classifier.fit(train_X,train_y) 復制代碼-------------------輸---------出--------------------------------
SVC(C=1.0, cache_size=200, class_weight='balanced', coef0=0.0, decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf', max_iter=-1, probability=True, random_state=None, shrinking=True, tol=0.001, verbose=False)
-------------------------完-------------------------------------
# 用交叉驗證來檢驗模型的準確性,只是在test set上驗證準確性 from sklearn.cross_validation import cross_val_score num_validations=5 accuracy=cross_val_score(classifier,test_X,test_y,scoring='accuracy',cv=num_validations) print('準確率:{:.2f}%'.format(accuracy.mean()*100)) precision=cross_val_score(classifier,test_X,test_y,scoring='precision_weighted',cv=num_validations) print('精確度:{:.2f}%'.format(precision.mean()*100)) recall=cross_val_score(classifier,test_X,test_y,scoring='recall_weighted',cv=num_validations) print('召回率:{:.2f}%'.format(recall.mean()*100)) f1=cross_val_score(classifier,test_X,test_y,scoring='f1_weighted',cv=num_validations) print('F1 值:{:.2f}%'.format(f1.mean()*100)) 復制代碼-----------------------輸---------出--------------------------------
準確率:93.78%
精確度:92.96%
召回率:93.78%
F1 值:92.96%
----------------------------完-------------------------------------
從交叉驗證的結果可以看出,在測試集上,該SVM分類器仍然可以得到各項指標都達到90%以上的效果,可以認為,該SVM分類器的效果比較好。當然,如果還想繼續提升該分類效果,可以使用GridSearch方法來搜索最佳參數組合,GridSearch的使用方法可以參考我的文章【火爐煉AI】機器學習017-使用GridSearch搜索最佳參數組合
3. 使用該分類器對新樣本進行預測
首先我們需要新樣本數據,此處我自己構建了一些新樣本,并不一定準確,但是可以用于預測。對新樣本的預測也很簡單,直接使用classifier.predict()函數即可。
# 看起來該模型的預測效果很不錯 # 那么用它來對新樣本數據進行預測,會是什么樣了? new_samples=np.array([[2,'09:30:00',20,12], # 即某個星期二,上午9點-9點半時間段,進大樓20人,出大樓12人[2,'11:30:00',26,9],[6,'12:30:00',4,22],[0,'05:00:00',1,0]]) transformed=time_encoder.transform(new_samples[:,1]) # print(transformed) # 檢查OK new_samples[:,1]=transformed print(new_samples)# 使用classifier進行預測 output_class = classifier.predict(new_samples) print('has events? {}'.format(output_class)) 復制代碼---------------------輸---------出--------------------------------
[['2' '19' '20' '12']
['2' '23' '26' '9']
['6' '25' '4' '22']
['0' '10' '1' '0']]
has events? [0 1 0 0]
----------------------------完-------------------------------------
從輸出結果可以看出,只有第二個樣本有活動,其他樣本都沒有活動,可以想象的出來,第一個樣本9點-9點半有很多人進樓,但是少量人出樓,會不會是正常的上班族?而第二個樣本11點到11點半之間有很多人進來,卻很少有了出去,這個時間段應該就是會議期間正常的人員流動,而第三個樣本12點到12點半,有很多人出樓,這大概是人家出去吃午飯吧。而第四個樣本,周日的凌晨五點,估計只有鬼才能在大樓門口晃悠了。。。。
########################小**********結#################
1. 這個項目的難點不在于SVM模型的構建和分類訓練上,而在于前期數據集的規整上。
2. 后面使用SVM進行模型構建和訓練,對新樣本進行預測,在我前面的文章中講了很多次了,至此已經沒有什么新意了。
#####################################################
注:本部分代碼已經全部上傳到(我的github)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊杰,陳小莉譯
總結
以上是生活随笔為你收集整理的【火炉炼AI】机器学习018-项目案例:根据大楼进出人数预测是否举办活动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: window服务器上搭建git服务,wi
- 下一篇: 安全公司正在借 AI 之力,预测、防御并