本文是基于Python語(yǔ)言結(jié)合基礎(chǔ)的機(jī)器學(xué)習(xí)算法來(lái)對(duì)微博傳播廣度下的微博轉(zhuǎn)發(fā)次數(shù)來(lái)進(jìn)行預(yù)測(cè)的,并分析了微博在轉(zhuǎn)發(fā)過(guò)程中有可能出現(xiàn)峰值的時(shí)刻。
1、環(huán)境準(zhǔn)備
- 使用語(yǔ)言:python
- 軟件IDE:PyCharm
- 數(shù)據(jù)來(lái)源:DataCastle(數(shù)據(jù)城堡)原始發(fā)布數(shù)據(jù)
2、理論知識(shí)儲(chǔ)備以及機(jī)器學(xué)習(xí)算法原理圖解
2.1 微博轉(zhuǎn)發(fā)廣度
其中a為發(fā)送原始微博的用戶,b,b1,b2都是用戶a的粉絲,所以a所發(fā)的微博會(huì)被他的所有粉絲看到,假如b轉(zhuǎn)發(fā)了a所發(fā)的微博,則b的所有粉絲即c,c1,c2都可以看到b所轉(zhuǎn)發(fā)的a的那條微博,微博的轉(zhuǎn)發(fā)廣度就是在被轉(zhuǎn)發(fā)人所發(fā)布的這條微博被轉(zhuǎn)發(fā)者所轉(zhuǎn)發(fā)之后所覆蓋的所有用戶。
故這條微博的轉(zhuǎn)發(fā)廣度就為6。如果c還繼續(xù)轉(zhuǎn)發(fā)b所轉(zhuǎn)發(fā)的a發(fā)布的微博,同理,這里不再做演示。
2.2 KNN算法
現(xiàn)已經(jīng)存在一部分樣本數(shù)據(jù),并且每個(gè)數(shù)據(jù)都具有相應(yīng)的標(biāo)簽,然后往此數(shù)據(jù)中輸入新的無(wú)任何標(biāo)簽的數(shù)據(jù)值,然后比較新輸入數(shù)據(jù)的特征與已有的特征作對(duì)比,找出數(shù)據(jù)特征最為相近的數(shù)據(jù)值,將其貼上最多的數(shù)據(jù)值所具有的標(biāo)簽。
2.3 決策樹算法
決策樹算法是屬于機(jī)器學(xué)習(xí)監(jiān)督學(xué)習(xí)分類算法中的,一般在理解隨機(jī)森林之前要對(duì)決策樹有所理解,其中決策樹就是一個(gè)比較簡(jiǎn)單的是否問(wèn)題,對(duì)所有的問(wèn)題都只會(huì)有是和否兩種結(jié)果供選擇,不同的選擇會(huì)導(dǎo)致不同的樹的走向,直到最終走向葉子結(jié)點(diǎn),決策樹就是在這種不斷分類中而形成的一種樹形的分類算法。
從上圖就可以看出,其實(shí)決策樹就是If()語(yǔ)句的層層嵌套,會(huì)一直根據(jù)判斷是否來(lái)樹狀延伸下去。
2.4 隨機(jī)森林算法
隨機(jī)森林首先是一種有放回的分類算法,是基于決策樹的一種算法,其中隨機(jī)森林是通過(guò)決策樹隨機(jī)構(gòu)建的,并且每一棵決策樹之間都是沒(méi)有任何關(guān)聯(lián)的,并且對(duì)數(shù)據(jù)也是進(jìn)行隨機(jī)采樣的,對(duì)特征的選取也是完全隨機(jī)的,然后對(duì)數(shù)據(jù)分別進(jìn)行訓(xùn)練,訓(xùn)練完成之后以一種投票的方式來(lái)決定最終的結(jié)果,隨機(jī)森林這種通過(guò)隨機(jī)和森林的方式可以保證模型的方差降低而不需要進(jìn)行剪枝,也可以取得比較好的泛化能力和抗擬合能力。
2.5 決策樹算法改進(jìn)原理
本次對(duì)決策樹算法的改進(jìn)是通過(guò)使用sklearn.grid_search庫(kù)下的GridSearchCV方法,通過(guò)對(duì)原始數(shù)據(jù)集進(jìn)行訓(xùn)練,再通過(guò)構(gòu)建決策樹中的參數(shù)列表來(lái)使用網(wǎng)格搜索和交叉驗(yàn)證的暴力搜索方式來(lái)對(duì)決策樹中的各個(gè)參數(shù)的取值進(jìn)行驗(yàn)證,每次獲取某個(gè)參數(shù)的最佳值應(yīng)用到下一次搜索中去,使用迭代的思想對(duì)參數(shù)值進(jìn)行窮盡搜索,根據(jù)得分情況來(lái)對(duì)參數(shù)的取值進(jìn)行統(tǒng)計(jì),最終取出最佳分?jǐn)?shù)值以及對(duì)應(yīng)的最佳參數(shù)列表,直接將最佳參數(shù)的取值應(yīng)用到?jīng)Q策樹算法模型構(gòu)建中去,來(lái)分析算法改進(jìn)前后的性能差異。
2.6 隨機(jī)森林算法改進(jìn)原理
首先隨機(jī)森林是一種隨機(jī)構(gòu)建特征值的機(jī)器學(xué)習(xí)算法,其包含眾多決策樹算法模型,且每一個(gè)決策樹之間都沒(méi)有任何聯(lián)系,基于這種情況,可以采用對(duì)特征值進(jìn)行劃分的方法,將不同的特征值應(yīng)用到不同的隨機(jī)森林模型中去進(jìn)行訓(xùn)練,對(duì)同一條微博的不同預(yù)測(cè)所產(chǎn)生的值去構(gòu)建集合,就可以得到每條微博預(yù)測(cè)值集合,在所統(tǒng)計(jì)的集合中選擇出最佳的單條微博預(yù)測(cè)值,最終將最佳預(yù)測(cè)結(jié)果進(jìn)行整合,構(gòu)成最佳預(yù)測(cè)集合。總的來(lái)說(shuō),改進(jìn)后的隨進(jìn)森林是通過(guò)構(gòu)建多隨機(jī)森林對(duì)數(shù)據(jù)集進(jìn)行多次預(yù)測(cè),每次取出最佳預(yù)測(cè)值,然后組成預(yù)測(cè)集合,再?gòu)募现腥〕稣`差最小的,最后再將所有誤差最小的預(yù)測(cè)結(jié)果進(jìn)行整合,構(gòu)成最佳預(yù)測(cè)集合。
在微博傳播廣度下使用機(jī)器學(xué)習(xí)算法進(jìn)行預(yù)測(cè)的完整代碼如下(其中包括KNN算法、決策樹算法改進(jìn)前后、隨機(jī)森林算法改進(jìn)前后):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Moxiaofei
# @File : handle.py
# @Software: PyCharm
# 微博傳播廣度下預(yù)測(cè)
# 導(dǎo)入所需要的模塊
import pandas
from sklearn.neighbors import KNeighborsClassifier
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
# 讀取數(shù)據(jù)
data = pandas.read_csv('handle.csv', sep=' ')
# 定義用于訓(xùn)練時(shí)的特征
x_col = ["emotional_level", "follow_num", "at_flag", "topic_flag", "url_flag", "content_length",
"time_step", "fans_num", "width1", "width2", "width3", "width4"]
# 定義自變量和目標(biāo)變量
x_train = data[x_col][:14717]
y_train = data['repost_num'][:14717]
# 定義需要預(yù)測(cè)的自變量和目標(biāo)變量
predict_value = data[x_col][14717:]
true_value = data['repost_num'][14717:]
# KNN算法
def knn_algorithm(x_train, y_train):
# 預(yù)測(cè)出來(lái)的數(shù)據(jù)
pre_data = (KNeighborsClassifier().fit(x_train, y_train)).predict(predict_value)
# 平均絕對(duì)百分比誤差
avg_error = calculate_avg_error(pre_data, true_value)
accuracy = (100 - avg_error*100)/100
return avg_error, accuracy
# 決策樹算法
def decisionTree_algorithm(x_train, y_train):
# 預(yù)測(cè)出來(lái)的數(shù)據(jù)
pre_data = (tree.DecisionTreeClassifier().fit(x_train, y_train)).predict(predict_value)
# 平均絕對(duì)百分比誤差
avg_error = calculate_avg_error(pre_data, true_value)
accuracy = (100 - avg_error * 100) / 100
return avg_error, accuracy
# 隨機(jī)森林算法
def randomForest_algorithm(x_train, y_train):
# 預(yù)測(cè)出來(lái)的數(shù)據(jù)
pre_data = (RandomForestClassifier().fit(x_train, y_train)).predict(predict_value)
# 平均絕對(duì)百分比誤差
avg_error = calculate_avg_error(pre_data, true_value)
accuracy = (100 - avg_error * 100) / 100
return avg_error, accuracy
# 改進(jìn)的決策樹算法
def imporve_decisionTree(x_train, y_train):
decision_tree_classifier = tree.DecisionTreeClassifier(max_features='sqrt')
# 要選擇的參數(shù)列表
parameter_grid = {'max_depth': list(range(1, 10)),
'min_samples_split': list(range(2, 10)),
'min_samples_leaf': list(range(1, 10))}
# 使用GridSearchCV來(lái)查找最佳參數(shù)
gridsearch = GridSearchCV(decision_tree_classifier, param_grid=parameter_grid, cv=5)
gridsearch.fit(x_train, y_train)
# 取出得分最高的參數(shù)值,并構(gòu)建最佳的決策樹
best_param = gridsearch.best_params_
print(best_param)
best_decision_tree_classifier = tree.DecisionTreeClassifier(max_depth=best_param['max_depth'],
min_samples_split=best_param['min_samples_split'],
min_samples_leaf=best_param['min_samples_leaf'])
# 訓(xùn)練數(shù)據(jù)集 使用預(yù)測(cè)值訓(xùn)練真實(shí)值
best_decision_tree_classifier.fit(x_train, y_train)
# 預(yù)測(cè)數(shù)據(jù)集
best_pre_value = best_decision_tree_classifier.predict(predict_value)
# 計(jì)算真實(shí)值與預(yù)測(cè)值之間的平均百分比
best_avg_error = calculate_avg_error(best_pre_value, true_value)
best_accuracy = (100-100*best_avg_error)/100
return best_avg_error, best_accuracy
# 改進(jìn)的隨機(jī)森林算法
def improve_randomForest(x_train, y_train):
# n_estimators的取值范圍
n_estimators_options = list(range(10, 100, 10))
sample_leaf_options = list(range(1, 10, 1))
results = []
for leaf_size in sample_leaf_options:
for n_estimators_size in n_estimators_options:
alg = RandomForestClassifier(min_samples_leaf=leaf_size, n_estimators=n_estimators_size, random_state=50)
alg.fit(x_train, y_train)
predict = alg.predict(predict_value)
average_err = calculate_avg_error(predict, true_value)
# 用一個(gè)三元組,分別記錄當(dāng)前的 min_samples_leaf,n_estimators, 和平均誤差
results.append((leaf_size, n_estimators_size, predict, average_err))
# 打印精度最大的那一個(gè)三元組
min_pre = min(results, key=lambda x: x[3])
accuracy_rate = (100 - min_pre[3]*100)/100
return min_pre[3], accuracy_rate
# 計(jì)算平均絕對(duì)百分比誤差
def calculate_avg_error(pre_value, true_value):
return float(format(((abs(pre_value - true_value) / true_value).sum()) / len(pre_value), '.2f'))
if __name__ == '__main__':
error_list = []
accuracy_list = []
# KNN算法預(yù)測(cè)出的結(jié)果
res_knn = knn_algorithm(x_train, y_train)
error_list.append(res_knn[0])
accuracy_list.append(res_knn[1])
# 決策樹算法預(yù)測(cè)出的結(jié)果
res_decisoinTree = decisionTree_algorithm(x_train, y_train)
error_list.append(res_decisoinTree[0])
accuracy_list.append(res_decisoinTree[1])
# 隨機(jī)森林算法預(yù)測(cè)出的結(jié)果
res_randomForest = randomForest_algorithm(x_train, y_train)
error_list.append(res_randomForest[0])
accuracy_list.append(res_randomForest[1])
# 改進(jìn)之后的決策樹算法預(yù)測(cè)出的結(jié)果
res_improve_decisionTree = imporve_decisionTree(x_train, y_train)
error_list.append(res_improve_decisionTree[0])
accuracy_list.append(res_improve_decisionTree[1])
# 改進(jìn)之后的隨機(jī)森林算法預(yù)測(cè)出的結(jié)果
res_improve_randomForest = improve_randomForest(x_train, y_train)
error_list.append(res_improve_randomForest[0])
accuracy_list.append(res_improve_randomForest[1])
# 打印所使用的算法的預(yù)測(cè)平均絕對(duì)百分比誤差
print(error_list)
# 打印所使用的算法的預(yù)測(cè)準(zhǔn)確率
print(accuracy_list)
在微博傳播廣度下各數(shù)據(jù)特征之間的關(guān)系以及峰值出現(xiàn)的時(shí)刻圖:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Moxiaofei
# @File : draw.py
# @Software: PyCharm
# 繪圖
# 導(dǎo)入所需要的模塊
from matplotlib import pyplot as plt
import pandas as pd
# *******************************
# 微博傳播廣度下的圖形繪制
# *******************************
# 讀取數(shù)據(jù)
data = pd.read_csv('handle.csv', sep=' ')
# ------用戶粉絲數(shù)與轉(zhuǎn)發(fā)數(shù)的關(guān)系散點(diǎn)圖------ #
plt.figure(figsize=(7, 5))
fans_num = data['fans_num']
repost_num = data['repost_num']
plt.scatter(fans_num, repost_num)
plt.title('The relationship between fans_num and repost_num')
plt.xlabel('the number of the fans')
plt.ylabel('the number of the repost')
# 保存圖片到本路徑下
# plt.savefig('repost_fans.png', dpi=400, bbox_inches='tight')
# plt.show()
# ------計(jì)算在某個(gè)時(shí)間段內(nèi)轉(zhuǎn)發(fā)次數(shù)最多的,繪制成圖顯示峰值------ #
res = []
# i的取值為[1,11]
for i in range(1, 12):
res.append(data['width'+str(i+1)] - data['width'+str(i)])
time_repost_num = []
MAX_TIME_DICT = []
for j in range(0, 14767):
# [32, 85, 1, 267, 95, 74, 18, 8, 103, 33, 17] 所有的差值
line = [x[j] for x in res]
# print(line)
# 最大值所出現(xiàn)的時(shí)刻
max_sub_time = line.index(max(line)) + int(1)
MAX_TIME_DICT.append(max_sub_time)
# 在差值里面統(tǒng)計(jì)時(shí)刻和最大差值
time_count = []
for i in range(1, 12):
# 輸出出現(xiàn)最大差值的時(shí)刻的數(shù)量
time_count.append(MAX_TIME_DICT.count(i))
plt.figure(figsize=(7, 5))
time = range(1, 12)
plt.plot(time, time_count)
plt.title('The relationship between time and D-value')
plt.xlabel('the number of the time')
plt.ylabel('the number of the D-value')
# plt.savefig('top.png', dpi=400, bbox_inches='tight')
# plt.show()
# ------峰值 微博3小時(shí)傳播次數(shù)和總傳播次數(shù)的散點(diǎn)圖------ #
plt.figure(figsize=(7, 5))
x1 = data['width12']
y1 = data['repost_num']
plt.scatter(x1, y1)
plt.title('The relationship between spread_num and repost_num')
plt.xlabel('the number of the spread_num')
plt.ylabel('the number of the repost_num')
# plt.savefig('3_all.png', dpi=400, bbox_inches='tight')
# plt.show()
這里只是簡(jiǎn)述了所使用算法的原理,并對(duì)微博傳播廣度下的轉(zhuǎn)發(fā)數(shù)進(jìn)行預(yù)測(cè)的代碼的展示;此外,還對(duì)微博深度下的特征進(jìn)行了預(yù)測(cè)研究,預(yù)測(cè)了其可能出現(xiàn)峰值的時(shí)刻。需要完整代碼可移步至此