Python语言结合机器学习算法进行微博预测

2018-07-04  本文已影响0人  墨小飞

本文是基于Python语言结合基础的机器学习算法来对微博传播广度下的微博转发次数来进行预测的,并分析了微博在转发过程中有可能出现峰值的时刻。

1、环境准备
  1. 使用语言:python
  2. 软件IDE:PyCharm
  3. 数据来源:DataCastle(数据城堡)原始发布数据
2、理论知识储备以及机器学习算法原理图解
2.1 微博转发广度

其中a为发送原始微博的用户,b,b1,b2都是用户a的粉丝,所以a所发的微博会被他的所有粉丝看到,假如b转发了a所发的微博,则b的所有粉丝即c,c1,c2都可以看到b所转发的a的那条微博,微博的转发广度就是在被转发人所发布的这条微博被转发者所转发之后所覆盖的所有用户。

微博转发广度示意图.png

故这条微博的转发广度就为6。如果c还继续转发b所转发的a发布的微博,同理,这里不再做演示。

2.2 KNN算法

现已经存在一部分样本数据,并且每个数据都具有相应的标签,然后往此数据中输入新的无任何标签的数据值,然后比较新输入数据的特征与已有的特征作对比,找出数据特征最为相近的数据值,将其贴上最多的数据值所具有的标签。

KNN原理图解.jpg
2.3 决策树算法

决策树算法是属于机器学习监督学习分类算法中的,一般在理解随机森林之前要对决策树有所理解,其中决策树就是一个比较简单的是否问题,对所有的问题都只会有是和否两种结果供选择,不同的选择会导致不同的树的走向,直到最终走向叶子结点,决策树就是在这种不断分类中而形成的一种树形的分类算法。

决策树算法原理.png

从上图就可以看出,其实决策树就是If()语句的层层嵌套,会一直根据判断是否来树状延伸下去。

2.4 随机森林算法

随机森林首先是一种有放回的分类算法,是基于决策树的一种算法,其中随机森林是通过决策树随机构建的,并且每一棵决策树之间都是没有任何关联的,并且对数据也是进行随机采样的,对特征的选取也是完全随机的,然后对数据分别进行训练,训练完成之后以一种投票的方式来决定最终的结果,随机森林这种通过随机和森林的方式可以保证模型的方差降低而不需要进行剪枝,也可以取得比较好的泛化能力和抗拟合能力。

随机森林算法原理.png
2.5 决策树算法改进原理

本次对决策树算法的改进是通过使用sklearn.grid_search库下的GridSearchCV方法,通过对原始数据集进行训练,再通过构建决策树中的参数列表来使用网格搜索和交叉验证的暴力搜索方式来对决策树中的各个参数的取值进行验证,每次获取某个参数的最佳值应用到下一次搜索中去,使用迭代的思想对参数值进行穷尽搜索,根据得分情况来对参数的取值进行统计,最终取出最佳分数值以及对应的最佳参数列表,直接将最佳参数的取值应用到决策树算法模型构建中去,来分析算法改进前后的性能差异。

决策树算法改进原理.png
2.6 随机森林算法改进原理

首先随机森林是一种随机构建特征值的机器学习算法,其包含众多决策树算法模型,且每一个决策树之间都没有任何联系,基于这种情况,可以采用对特征值进行划分的方法,将不同的特征值应用到不同的随机森林模型中去进行训练,对同一条微博的不同预测所产生的值去构建集合,就可以得到每条微博预测值集合,在所统计的集合中选择出最佳的单条微博预测值,最终将最佳预测结果进行整合,构成最佳预测集合。总的来说,改进后的随进森林是通过构建多随机森林对数据集进行多次预测,每次取出最佳预测值,然后组成预测集合,再从集合中取出误差最小的,最后再将所有误差最小的预测结果进行整合,构成最佳预测集合。

改进后的随机森林算法原理图.png

在微博传播广度下使用机器学习算法进行预测的完整代码如下(其中包括KNN算法、决策树算法改进前后、随机森林算法改进前后):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : Moxiaofei
# @File    : handle.py
# @Software: PyCharm
# 微博传播广度下预测

# 导入所需要的模块
import pandas
from sklearn.neighbors import KNeighborsClassifier
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV


# 读取数据
data = pandas.read_csv('handle.csv', sep=' ')
# 定义用于训练时的特征
x_col = ["emotional_level", "follow_num", "at_flag", "topic_flag", "url_flag", "content_length",
         "time_step", "fans_num", "width1", "width2", "width3", "width4"]
# 定义自变量和目标变量
x_train = data[x_col][:14717]
y_train = data['repost_num'][:14717]
# 定义需要预测的自变量和目标变量
predict_value = data[x_col][14717:]
true_value = data['repost_num'][14717:]


# KNN算法
def knn_algorithm(x_train, y_train):
    # 预测出来的数据
    pre_data = (KNeighborsClassifier().fit(x_train, y_train)).predict(predict_value)
    # 平均绝对百分比误差
    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):
    # 预测出来的数据
    pre_data = (tree.DecisionTreeClassifier().fit(x_train, y_train)).predict(predict_value)
    # 平均绝对百分比误差
    avg_error = calculate_avg_error(pre_data, true_value)
    accuracy = (100 - avg_error * 100) / 100
    return avg_error, accuracy


# 随机森林算法
def randomForest_algorithm(x_train, y_train):
    # 预测出来的数据
    pre_data = (RandomForestClassifier().fit(x_train, y_train)).predict(predict_value)
    # 平均绝对百分比误差
    avg_error = calculate_avg_error(pre_data, true_value)
    accuracy = (100 - avg_error * 100) / 100
    return avg_error, accuracy


# 改进的决策树算法
def imporve_decisionTree(x_train, y_train):
    decision_tree_classifier = tree.DecisionTreeClassifier(max_features='sqrt')
    # 要选择的参数列表
    parameter_grid = {'max_depth': list(range(1, 10)),
                      'min_samples_split': list(range(2, 10)),
                      'min_samples_leaf': list(range(1, 10))}
    # 使用GridSearchCV来查找最佳参数
    gridsearch = GridSearchCV(decision_tree_classifier, param_grid=parameter_grid, cv=5)
    gridsearch.fit(x_train, y_train)
    # 取出得分最高的参数值,并构建最佳的决策树
    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'])
    # 训练数据集  使用预测值训练真实值
    best_decision_tree_classifier.fit(x_train, y_train)
    # 预测数据集
    best_pre_value = best_decision_tree_classifier.predict(predict_value)
    # 计算真实值与预测值之间的平均百分比
    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


# 改进的随机森林算法
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)
            # 用一个三元组,分别记录当前的 min_samples_leaf,n_estimators, 和平均误差
            results.append((leaf_size, n_estimators_size, predict, average_err))
    # 打印精度最大的那一个三元组
    min_pre = min(results, key=lambda x: x[3])
    accuracy_rate = (100 - min_pre[3]*100)/100
    return min_pre[3], accuracy_rate


# 计算平均绝对百分比误差
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算法预测出的结果
    res_knn = knn_algorithm(x_train, y_train)
    error_list.append(res_knn[0])
    accuracy_list.append(res_knn[1])

    # 决策树算法预测出的结果
    res_decisoinTree = decisionTree_algorithm(x_train, y_train)
    error_list.append(res_decisoinTree[0])
    accuracy_list.append(res_decisoinTree[1])

    # 随机森林算法预测出的结果
    res_randomForest = randomForest_algorithm(x_train, y_train)
    error_list.append(res_randomForest[0])
    accuracy_list.append(res_randomForest[1])

    # 改进之后的决策树算法预测出的结果
    res_improve_decisionTree = imporve_decisionTree(x_train, y_train)
    error_list.append(res_improve_decisionTree[0])
    accuracy_list.append(res_improve_decisionTree[1])

    # 改进之后的随机森林算法预测出的结果
    res_improve_randomForest = improve_randomForest(x_train, y_train)
    error_list.append(res_improve_randomForest[0])
    accuracy_list.append(res_improve_randomForest[1])

    # 打印所使用的算法的预测平均绝对百分比误差
    print(error_list)
    # 打印所使用的算法的预测准确率
    print(accuracy_list)

在微博传播广度下各数据特征之间的关系以及峰值出现的时刻图:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : Moxiaofei
# @File    : draw.py
# @Software: PyCharm
# 绘图

# 导入所需要的模块
from matplotlib import pyplot as plt
import pandas as pd

# *******************************
# 微博传播广度下的图形绘制
# *******************************
# 读取数据
data = pd.read_csv('handle.csv', sep=' ')

# ------用户粉丝数与转发数的关系散点图------  #
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()

# ------计算在某个时间段内转发次数最多的,绘制成图显示峰值------  #
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)
    # 最大值所出现的时刻
    max_sub_time = line.index(max(line)) + int(1)
    MAX_TIME_DICT.append(max_sub_time)
    # 在差值里面统计时刻和最大差值
time_count = []
for i in range(1, 12):
    # 输出出现最大差值的时刻的数量
    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小时传播次数和总传播次数的散点图------  #
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()

这里只是简述了所使用算法的原理,并对微博传播广度下的转发数进行预测的代码的展示;此外,还对微博深度下的特征进行了预测研究,预测了其可能出现峰值的时刻。需要完整代码可移步至此

上一篇下一篇

猜你喜欢

热点阅读