数据挖掘实战(5):实战篇

博客内容是书籍: 《Python数据分析与挖掘实战》 的阅读笔记。
内容分为三个部分:
    第一部分:第10章 :家用电器用户行为分析与事件识别 的内容;
    第二部分:第11章 :应用系统负载分析与磁盘容量预测 的内容;
    第三部分:第12章 :电子商务网站用户行为分析及服务推荐 的内容;
 
课件 PDF 和 源码 移步到Githubhttps://github.com/Stormzudi/Python-Data-Mining
邮箱:[email protected]


简单说下:博客的内容是按照原书的结构整理的,也算是读书笔记。
编译器:Pycharm

第一部分:

整理思维导图

在学习过程中,按照自己理解的重点将本章分成四个部分:挖掘目标、模型、建模步骤、Python编程知识
其中,在学习这章中,有两个地方值得我们学习,如果遇到了类似的问题,可以运用本章中解题思路进行研究。

(1)特征的选取、阈值的确定
(2)使用keras模块来实现BP神经网络

1. 背景与挖掘目标

背景:

居民在使用家用电器过程中,会因地区气候、不同区域、用户年龄性别差异,形成不同的使用习惯。家电企业若能深入了解不同用户群的使用习惯,开发新功能,就能开拓新市场。

挖掘目标:

1. 根据热水器采集到的数据,划分一次完整用水事件
2. 在划分好的一次完整用水事件中,识别出洗浴事件

2. 分析方法与过程

热水器用户用水事件划分与识别主要包括以下步骤。
1)对热水用户的历史用水数据进行选择性抽取,构建专家样本。
2)对步骤1)形成的数据集进行数据探索分析与预处理,包括探索用水事件时间间隔的分布、规约冗余属性、识别用水数据的缺失值,并对缺失值进行处理,根据建模的需要进行属性构造等。根据以上处理,对用水样本数据建立用水事件时间间隔识别模型和划分一次完整的用水事件模型,再在一次完整用水事件划分结果的基础上,剔除短暂用水事件,缩小识别范围。
3)在步骤2)得到的建模样本数据基础上,建立洗浴事件识别模型,对洗浴事件识别模型进行模型分析评价。
4)对步骤3)形成的模型结果应用并对洗浴事件划分进行优化。
5)调用洗浴事件识别模型,对实时监控的热水器流水数据进行洗浴事件自动识别。
                     

2.1 数据抽取

本案例对原始数据采用无放回随机抽样法抽取200家热水器用户从2014年1月1日至2014年12月31日的用水记录作为原始建模数据。

热水器采集的用水数据包含以下12个属性:热水器编码、发生时间、开关机状态、加热中、保温中、有无水流、实际温度、热水量、水流量、节能模式、加热剩余时间、当前设置温度

在特征工程中,需要将上面12个原始属性进行组合、甚至删除,最终获得建模的属性。

2.2 数据探索分析

这部分数据探究分析的任务是:探究用户真实用水停顿时间间隔的分布情况,也就是分析相邻非零的水流量之间的时间间隔分布情况。

原Excel中时间格式为:20141019063917
通过pd.to_datetime转化成能够计算时间差,正常的时间格式。

data[u'发生时间'] = pd.to_datetime(data[u'发生时间'], format = '%Y%m%d%H%M%S')


最终,得到了用水停顿时间间隔的频数分布表。
                     

可以发现,从3~4分钟、4 ~5分钟之后,用水停顿的时间间隔的发生概率变小,也就是说两次用水事件的事件间隔大部分发生在1 ~5分钟之内。

2.3 数据预处理

(1)数据规约
属性规约: 因为要对热水器用户的洗浴行为的一般规律进行挖掘分析,所以“热水器编号”可以去除;因热水器采集的数据中,“有无水流”可以通过“水流量”反映出来,“节能模式”数据都只为“关”,对建模无作用,可以去除。最终用来建模的属性指标如下表所示。
                     

数值规约: 当热水器“开关机状态”为“关”且水流量为0时,说明热水器不处于工作状态,数据记录可以规约掉。

(2)数据变换

1. 一次完整用水事件的划分模型
  用户的用水数据存储在数据库中,记录了各种各样的用水事件,包括洗浴、洗手、刷牙、洗脸、洗衣和洗菜等,而且一次用水事件由数条甚至数千条的状态记录组成。所以,本案例首先需要在大量的状态记录中划分出哪些连续的数据是一次完整的用水事件。
                     

一次完整用水事件的划分步骤如下。
1)读取数据记录,识别到第一条水流量不为0的数据记录记为 R 1 R_1 R1,按顺序识别接下来的一条水流量不为0数据记录为 R 2 R_2 R2

2)若 g a p i > T gap_i>T gapi>T,则 R i + 1 R_{i+1} Ri+1 R i R_i Ri及之间的数据记录不能划分到可一次用水事件。同时将 R i + 1 R_{i+1} Ri+1记录作为新的读取数据记录的开始,返回步骤1);若 g a p i < T gap_i<T gapi<T,则将 R i + 1 R_{i+1} Ri+1 R i R_i Ri之间数据记录的划分到同一次用水事件,并记录接下来的水流量不为0数据记录为 R i + 2 R_{i+2} Ri+2

3)循环执行步骤2),直到数据记录读取完毕,结束事件划分。

代码如下:

# -*- coding: utf-8 -*-
"""
目的:用水事件划分
步骤:只用统计流量大于0的记录,然后差分,统计大于阈值
"""

import pandas as pd

threshold = pd.Timedelta('4 min')  # 阈值为分钟
inputfile = '../data/water_heater.xls'  # 输入数据路径,需要使用Excel格式
outputfile = '../tmp/dividsequence.xls'  # 输出数据路径,需要使用Excel格式

data = pd.read_excel(inputfile)
data[u'发生时间'] = pd.to_datetime(data[u'发生时间'], format='%Y%m%d%H%M%S')  # 转换成时间序列
data = data[data[u'水流量'] > 0]  # 只要流量大于0的记录
d = data[u'发生时间'].diff() > threshold  # 相邻时间作差分,比较是否大于阈值

"""
# 由于得到的d为布尔类型,在使用d.cumsum()后,遇到True,会默认加1,False会保持累加数不变
"""
data[u'事件编号'] = d.cumsum() + 1  # 通过累积求和的方式为事件编

data.to_excel(outputfile)  # 写入到文件中

得到了对用户的用水数据进行划分的结果。
                     

2. 用水事件阈值寻优模型
由于在不同的地区,以及不同的季节使用热水器时停顿的时长也可以不同,固定的停顿时长阈值对于某些特殊的情况的处理是不理想的。于是,需要对两个事件的时间间隔(阈值)进行探究性分析。

按照原本的结果可以分析得到:
                     
把两个事件的时间间隔分成(4min或者5min)比较合理。

阈值寻找的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File  : threshold_optimization.py
# @Author: Stormzudi
# @Date  : 2020/8/23 16:58

"""
功能:阈值寻找最优代码
结果:获取最优的阈值(4 min)
"""

import numpy as np
import pandas as pd

inputfile = '../data/water_heater.xls'  # 输入数据路径,需要使用Excel格式
n = 4  # 使用以后四个点的平均斜率

threshold = pd.Timedelta(minutes=5)  # 专家阈值
data = pd.read_excel(inputfile)
data[u'发生时间'] = pd.to_datetime(data[u'发生时间'], format='%Y%m%d%H%M%S')
data = data[data[u'水流量'] > 0]  # 只要流量大于0的记录


def event_num(ts):
    d = data[u'发生时间'].diff() > ts  # 相邻时间作差分,比较是否大于阈值
    return d.sum() + 1  # 这样直接返回事件数


dt = [pd.Timedelta(minutes = i) for i in np.arange(1, 9, 0.25)]
h = pd.DataFrame(dt, columns = [u'阈值'])  # 定义阈值列
h[u'事件数'] = h[u'阈值'].apply(event_num)  # 计算每个阈值对应的事件数
h[u'斜率'] = h[u'事件数'].diff()/0.25  # 计算每两个相邻点对应的斜率
h[u'斜率指标'] = h[u'斜率'].abs().rolling(2).mean()  # 采用后n个的斜率绝对值平均作为斜率指标
ts = h[u'阈值'][h[u'斜率指标'].idxmin() - n]
# 注:用idxmin返回最小值的Index,由于rolling_mean()自动计算的是前n个斜率的绝对值平均
# 所以结果要进行平移(-n)

if ts > threshold:
    ts = pd.Timedelta(minutes = 4)

print(h)

3. 属性构造
在本案例研究中,构造4类指标:时长指标、频率指标、用水的量化指标、用水波动指标

时长指标:
                     

频率指标:
                     
用水的量化指标:
                     

用水波动指标:
                     

按照上面的构造方法,属性构造的代码如下:

# -*- coding: utf-8 -*-
"""
用水事件属性构造
"""

import pandas as pd

threshold = pd.Timedelta('4 min') #阈值为分钟
inputfile = '../data/water_heater.xls' #输入数据路径,需要使用Excel格式
outputfile = '../tmp/attribute_extract.xls' #输入数据路径,需要使用Excel格式

data = pd.read_excel(inputfile)
data[u'发生时间'] = pd.to_datetime(data[u'发生时间'], format = '%Y%m%d%H%M%S')
data = data[data[u'水流量'] > 0] #只要流量大于0的记录
d = data[u'发生时间'].diff() > threshold #相邻时间作差分,比较是否大于阈值
data[u'事件编号'] = d.cumsum() + 1 #通过累积求和的方式为事件编号

data_g = data.groupby(u'事件编号')  # 按照事件编号进行分组
result = pd.DataFrame()

for n, g in data_g:
    print(n)
    print(g)
    dt = pd.Timedelta(seconds=2)
    temp = pd.DataFrame(index = [0])
    tstart = g[u'发生时间'].min()
    tend = g[u'发生时间'].max()
    temp[u'用水事件时长(Min)'] = (dt + tend - tstart).total_seconds()/60
    temp[u'开关机切换次数'] = ((g[u'开关机状态']==u'关').rolling(2).sum() == 1).sum()
    temp[u'总用水量(L)'] = g[u'水流量'].sum()
    tdiff = g[u'发生时间'].diff()
    if len(g[u'发生时间']) == 1:
        temp[u'总用水时长(Min)'] = dt.total_seconds()/60
    else:
        temp[u'总用水时长(Min)'] = (tdiff.sum() - tdiff.iloc[1]/2 - tdiff.iloc[len(tdiff)-1]/2).total_seconds()/60
    temp[u'平均水流量(L/min)'] = temp[u'总用水量(L)']/temp[u'总用水时长(Min)']
    result = result.append(temp, ignore_index = True)

# result.to_excel(outputfile)

2.4 模型构建

经过数据预处理后,得到建模样本的数据。

在训练神经网络的时候,选取了“候选洗浴事件”的11个属性作为网络的输入,分别为:洗浴时间点、总用水时长、总停顿时长、平均停顿时长、停顿次数、用水时长、用水时长/总用水时长、总用水量、平均水流量、水流量波动和停顿时长波动。

训练BP网络时给定的输出为1与0,其中1代表该次事件为洗浴事件,0表示该次事件不是洗浴事件。其中,是否为洗浴事件根据用户提供的用水记录日志得到。

BP神经网络的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File  : neural_network.py
# @Author: Stormzudi
# @Date  : 2020/8/23 18:27

"""
建立、训练多层神经网络,并完成模型的检验
"""

from __future__ import print_function
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
import pandas as pd

# 文件的导入
inputfile1='../data/train_neural_network_data.xls'  # 训练数据
inputfile2='../data/test_neural_network_data.xls'  # 测试数据
testoutputfile = '../tmp/test_output_data.xls'  # 测试数据模型输出文件
data_train = pd.read_excel(inputfile1)  # 读入训练数据(由日志标记事件是否为洗浴)
data_test = pd.read_excel(inputfile2)  # 读入测试数据(由日志标记事件是否为洗浴)
y_train = data_train.iloc[:,4].values  # 训练样本标签列
x_train = data_train.iloc[:,5:17].values  # 训练样本特征
y_test = data_test.iloc[:,4].values  # 测试样本标签列
x_test = data_test.iloc[:,5:17].values  # 测试样本特征


# 建立神经网络模型
"""
units:代表该层的输出维度
output_dim:表示输入隐藏层
input_dim:表示输入层
"""
model = Sequential()
model.add(Dense(output_dim=17, input_dim=11))  # 添加输入层11、隐藏层17的连接
model.add(Activation('relu'))  # 以Relu函数为激活函数
model.add(Dense(output_dim=1, input_dim=17))  # 添加隐藏层17、输出层1的连接
model.add(Activation('sigmoid'))  # 以sigmoid函数为激活函数
# 编译模型,损失函数为binary_crossentropy,用adam法求解
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(x_train, y_train, nb_epoch = 100, batch_size = 1)  # 训练模型
model.save_weights('../tmp/net.model')  # 保存模型参数

r = pd.DataFrame(model.predict_classes(x_test), columns = [u'预测结果'])
pd.concat([data_test.iloc[:,:5], r], axis=1).to_excel(testoutputfile)  # 链接后存入文件中
model.predict(x_test)

结果显示(只保留前五列数据):


最后一列是模型的预测结果,前5列是原始数据。该模型检验了两周用户的用水情况,训练样本少可能会影响模型的准确性。

3. 小结

本章重点是在数据清洗、数据规约、数据变换。
其中运用的神经网络模型可以使用其他模型来构造,同时,在制定时间间隔时存在很大的优化空间,可以根据具体的优化方案进行优化,总之,特征工程决定了模型的上线,而模型的选取只是逼近这个上线的过程, 在数据挖掘案例的过程中要着重分析数据特性,找到合适的属性来构造模型。

 
 

第二部分:

整理思维导图

在学习过程中,按照自己理解的重点将本章分成三个部分:挖掘目标、模型、建模步骤
其中,在学习这章中,有两个地方值得我们学习,如果遇到了类似的问题,可以运用本章中解题思路进行研究。

(1)预处理阶段运用的属性构造方法
(2)ARIMA模型中的调参以及模型步骤

1. 背景与挖掘目标

背景:

如图11-1所示,影响应用系统性能的因素包括:服务器、数据库、中间件和存储设备。任何一种资源负载过大,都可能会引起应用系统性能下降甚至瘫痪。因此需要关注服务器、数据库、中间件和存储设备的运行状态,及时了解当前应用系统的负载情况,以便提前预防,确保系统安全稳定运行

挖掘目标:

1. 针对历史磁盘数据,采用时间序列分析方法,预测应用系统服务器磁盘已使用空间大小。
2. 根据用户需求设置不同的预警等级,将预测值与容量值进行比较,对其结果进行预警判断,为系统管理员提供定制化的预警提示。

2. 分析方法与过程

应用系统容量预处建模过程主要包括以下步骤。
1)从数据源中选择性抽取历史数据与每天定时抽取数据。
2)对抽取的数据进行周期性分析以及数据清洗、数据变换等操作后,形成建模数据。
3)采用时间序列分析法对建模数据进行模型的构建,利用模型预测服务器磁盘已使用情况。
4)应用模型预测服务器磁盘将要使用情况,通过预测到的磁盘使用大小与磁盘容量大小按照定制化标准进行判断,将结果反馈给系统管理员,提示管理员需要注意磁盘的使用情况。

采用时间序列分析法分析磁盘性能数据,预测未来的磁盘使用空间的情况,其挖掘建模总体流程如下。
                      

2.1 数据抽取

磁盘使用情况的数据都存放在性能数据中,而监控采集的性能数据中存在大量的其他属性数据。为了抽取出磁盘数据,以属性的标识号(TARGET_ID)与采集指标的时间(COLLECTTIME)为条件,对性能数据进行抽取。本案例抽取2014-10-01至2014-11-16财
务管理系统中某一台数据库服务器的磁盘的相关数据。

2.2 数据探索分析

数据探究分析的过程为,绘制出C盘与D盘的时序图,判断随着时间磁盘已使用的情况。

由原课本中的图像可以得知,磁盘的使用情况都不具备有周期性,它们表现出缓慢性增长,呈现趋势性。因此,可以初步确认数据是非平稳的。

所以接下来要进行数据的预处理。

2.3 数据预处理

(1)数据清洗
按照原文要求数据清洗阶段需要将磁盘容量表剔除掉,认为将所有服务器的磁盘容量作为一个固定值。
                      

(2)属性构造
属性构造其实就是将原始性能表转化成能够进行预测的表。
主要是利用了Pandas中的groupby()方法实现分组。
最终,得到的是一张可以做预测的表格。


代码如下:

#-*- coding: utf-8 -*-
#属性变换
import pandas as pd

#参数初始化
discfile = '../data/discdata.xls' #磁盘原始数据
transformeddata = '../tmp/discdata_processed.xls' #变换后的数据

data = pd.read_excel(discfile)
data = data[data['TARGET_ID'] == 184].copy() #只保留TARGET_ID184的数据

data_group = data.groupby('COLLECTTIME') #以时间分组

# 遍历分组
# for name,group in data.groupby('COLLECTTIME'):
#     print(name)
#     print(group)

def attr_trans(x): #定义属性变换函数
  result = pd.Series(index = ['SYS_NAME', 'CWXT_DB:184:C:\\', 'CWXT_DB:184:D:\\',	'COLLECTTIME'])
  result['SYS_NAME'] = x['SYS_NAME'].iloc[0]
  result['COLLECTTIME'] = x['COLLECTTIME'].iloc[0]
  result['CWXT_DB:184:C:\\'] = x['VALUE'].iloc[0]
  result['CWXT_DB:184:D:\\'] = x['VALUE'].iloc[1]
  return result

data_processed = data_group.apply(attr_trans) #逐组处理
data_processed.to_excel(transformeddata, index = False)

2.4 模型构建

模型的构建和我之前写的一篇博客如出一辙。同时,书本上有几个重点要注意下。


(1)白噪声检验
(2)平稳性检验

 
我之前写的博客:
ARIMA模型 - [SPSS & Python]:https://blog.csdn.net/qq_41709378/article/details/105869122
课件 PDF 和 源码 移步到Githubhttps://github.com/Stormzudi/Python-Data-Mining

3. 小结

(1)本章要注意使用Pandas的groupby模块,了解它的使用方法.
(2)ARIMA模型中(p,d,q)调参的方法,了解模型中需要检测的两种方法的代码。

 
 

第三部分:

整理思维导图

在学习过程中,按照自己理解的重点将本章分成三个部分:挖掘目标、模型、建模步骤
其中,在学习这章中,有两个地方值得我们学习,如果遇到了类似的问题,可以运用本章中解题思路进行研究。

(1)数据库的连接与使用
(2)特征分析(方法)


 
接下来,讲解下数据库与编译器的连接。

编译器:Pycharm 专业版

在原文PDF 和 源码中有.sql数据文件:7law.sql
如何将其导入到编译器中呢?

首先,你要保证你的Pycharm是能与数据库连接

(1)右击需要安装的数据库“test”,然后选择“Run SQL Script…”找到需要安装的“.sql”文件。

(2)正在运行7law.sql中。。。
                     

(3)安装完成,安装在test数据库下,表为“all_gzdata”
                     

于是可以使用python中专门连接数据库的模块sqlalchemy来调用数据库,并且使用数据库中的数据进行数据分析。

from sqlalchemy import create_engine

engine = create_engine('mysql://root:654321@localhost/test?charset=utf8')  # 访问数据库test
sql = pd.read_sql('all_gzdata', engine, chunksize=10000)  # 访问test数据库下的表all_gzdata, 只获取前10000个数据

1. 背景与挖掘目标

背景:

推荐系统并不需要用户提供明确的需求,而是通过分析用户的历史行为,从而主动向用户推荐能够满足他们兴趣和需求的信息。因此,对于用户而言,推荐系统和搜索引擎是两个互补的工具。搜索引擎满足有明确目标用户的需求,而推荐系统能够帮助用户发现其感兴趣的内容。因此,在电子商务领域中推荐技术可以起到以下作用:(1)用户发现其感兴趣的物品,节省用户时间、提升用户体验。(2)提高用户对电子商务网站的忠诚度,如果推荐系统能够准确地发现用户的兴趣点,并将合适的资源推荐给用户。

挖掘目标:

1. 按地域研究用户访问时间、访问内容和访问次数等分析主题,深入了解用户对访问网站的行为和目的及关心的内容。
2. 借助大量的用户的访问记录,发现用户的访问行为习惯,对不同需求的用户进行相关的服务页面的推荐。

2. 分析方法与过程

本案例的目标是对用户进行推荐,即以一定的方式将用户与物品(网站)之间建立联系。

为了避免:(1)数据量大,(2)用户区别很大,导致推荐效果不佳,需要对网页类型进行分类,然后对每个类型中的内容进行推荐。
                     
其分析过程包括以下内容:

  1. 从系统中获取用户访问网站的原始记录。
  2. 对数据进行多维度分析,包括用户访问内容,流失用户分析以及用户分类等分析。
  3. 对数据进行预处理,包含数据去重、数据变换和数据分类等处理过程。
  4. 以用户访问html后缀的网页为关键条件,对数据进行处理。
  5. 对比多种推荐算法进行推荐,通过模型评价,得到比较好的智能推荐模型。通过模型对样本数据进行预测,获得推荐结果。

2.1 数据抽取

数据抽取的处理过程是:建立数据库→导入数据→搭建Python的数据库操作环境→对数据进行分析→建立模型。其中,用到的开源数据库为MariaDB 10.0.17(网站https://mariadb.org/en/可下载并自行安装,是MySQL的一个分支)。安装数据库后导入本章的数据原始文件7law.sql,就成功地配置好了数据库平台。

正如在上一节介绍的,安装好后。
可以使用python中专门连接数据库的模块sqlalchemy来调用数据库,并且使用数据库中的数据进行数据分析。

from sqlalchemy import create_engine

engine = create_engine('mysql://root:654321@localhost/test?charset=utf8')  # 访问数据库test
sql = pd.read_sql('all_gzdata', engine, chunksize=10000)  # 访问test数据库下的表all_gzdata, 只获取前10000个数据

2.2 数据探索分析

(1)网页类型分析
这一步是针对原始数据中用户点击的网页类型进行统计,网页类型是指“网址类型”中的前三位数字。

# 网页类型分析
counts = [i['fullURLId'] for i in sql]  # 逐块统计
counts = pd.concat(counts).groupby(level=0).sum()  # 合并统计结果,把相同的统计项合并(即按index分组并求和)
counts = counts.reset_index()  # 重新设置index,将原来的index作为counts的一列。
counts.columns = ['index', 'num']  # 重新设置列名,主要是第二列,默认为0
counts['type'] = counts['num'].str.extract('(\d{3})')  # 提取前三个数字作为类别id
counts_ = counts[['type', 'num']].groupby('type').sum()  # 按类别合并
counts_.sort_values('num', ascending=False)  # 降序排列

 
分析其他(107)页面的情况。在网页的分类中,有律师、地区、咨询相关的网页分类,为何这些还会存在其他类别中?进行数据查看后,发现大部分是以下网址的形式存在。

#统计107类别的情况
def count107(i): #自定义统计函数
  j = i[['fullURL']][i['fullURLId'].str.contains('107')].copy() #找出类别包含107的网址
  j['type'] = None #添加空列
  j['type'][j['fullURL'].str.contains('info/.+?/')] = u'知识首页'
  j['type'][j['fullURL'].str.contains('info/.+?/.+?')] = u'知识列表页'
  j['type'][j['fullURL'].str.contains('/\d+?_*\d+?\.html')] = u'知识内容页'
  return j['type'].value_counts()

counts2 = [count107(i) for i in sql] #逐块统计
counts2 = pd.concat(counts2).groupby(level=0).sum() #合并统计结果

(2)点击次数分析
统计分析原始数据用户浏览网页次数(以“真实IP”区分)的情况。

#统计点击次数
c = [i['realIP'].value_counts() for i in sql] #分块统计各个IP的出现次数
count3 = pd.concat(c).groupby(level = 0).sum() #合并统计结果,level=0表示按index分组
count3 = pd.DataFrame(count3) #Series转为DataFrame
count3[1] = 1 #添加一列,全为1
count3.groupby(0).sum() #统计各个“不同的点击次数”分别出现的次数

2.3 数据预处理

在原始数据的探索分析的基础上,发现与分析目标无关或模型需要处理的数据,针对此类数据进行处理。其中涉及的数据处理方式有:数据清洗、数据集成和数据变换。通过这几类的处理方式,将原始数据处理成模型需要的输人数据,其数据处理流程图如下。

(1)数据清洗
数据清洗过程是删除一些作用不大,反而会影响推荐的结果网页。

import pandas as pd
from sqlalchemy import create_engine

engine = create_engine('mysql://root:654321@localhost/test?charset=utf8')  # 访问数据库test
sql = pd.read_sql('all_gzdata', engine, chunksize = 10000) 

for i in sql:
  d = i[['realIP', 'fullURL']] #只要网址列
  d = d[d['fullURL'].str.contains('\.html')].copy() #只要含有.html的网址
  #保存到数据库的cleaned_gzdata表中(如果表不存在则自动创建)
  d.to_sql('cleaned_gzdata', engine, index = False, if_exists = 'append')

(2)数据变换
网页与网页之间存在翻页的现象,因此,针对这些网页需要还原其原始类别,处理方式为首先识别翻页的网址,然后对翻页的网址进行还原,最后征对每个用户访问的页面进行去重操作。

import pandas as pd
from sqlalchemy import create_engine

engine = create_engine('mysql://root:654321@localhost/test?charset=utf8')  # 访问数据库test
sql = pd.read_sql('cleaned_gzdata', engine, chunksize = 10000) 

for i in sql: #逐块变换并去重
  d = i.copy()
  d['fullURL'] = d['fullURL'].str.replace('_\d{0,2}.html', '.html') #将下划线后面部分去掉,规范为标准网址
  d = d.drop_duplicates() #删除重复记录
  d.to_sql('changed_gzdata', engine, index = False, if_exists = 'append') #保存


# 网站分类
for i in sql: #逐块变换并去重
  d = i.copy()
  d['type_1'] = d['fullURL'] #复制一列
  d['type_1'][d['fullURL'].str.contains('(ask)|(askzt)')] = 'zixun' #将含有ask、askzt关键字的网址的类别一归为咨询(后面的规则就不详细列出来了,实际问题自己添加即可)
  d.to_sql('splited_gzdata', engine, index = False, if_exists = 'append') #保存

2.4 模型构建

关于物品相似度计算的方法有:
1)夹角余弦
2)杰卡德(Jaccard)相似系数;
3)相关系数等。
将用户对某一个物品的喜好或者评分作为一个向量,例如所有用户对物品1的评分或者喜好程度表示为 A 1 = ( x 11 , x 21 , x 31 . . . , x n 1 ) A_1=(x_{11},x_{21},x_{31}...,x_{n1}) A1=(x11,x21,x31...,xn1),所有用户对物品M的评分或者喜好程度表示为 A m = ( x 1 m , x 2 m , x 3 m . . . , x n m ) A_m=(x_{1m},x_{2m},x_{3m}...,x_{nm}) Am=(x1m,x2m,x3m...,xnm),其中m为物品,n为用户数。可以采用上述几种方法计算两个物品之间的相似度,其计算公式见表12-24。由于用户的行为是二元选择(0-1型),因此本例在计算物品的相似度过程中采用杰卡德相似系数法。
                     
代码如下:

import numpy as np

def Jaccard(a, b): #自定义杰卡德相似系数函数,仅对0-1矩阵有效
  return 1.0*(a*b).sum()/(a+b-a*b).sum()

class Recommender():
  
  sim = None #相似度矩阵
  
  def similarity(self, x, distance): #计算相似度矩阵的函数
    y = np.ones((len(x), len(x)))
    for i in range(len(x)):
      for j in range(len(x)):
        y[i,j] = distance(x[i], x[j])
    return y
  
  def fit(self, x, distance = Jaccard): #训练函数
    self.sim = self.similarity(x, distance)
  
  def recommend(self, a): #推荐函数
    return np.dot(self.sim, a)*(1-a)

文章中还结合结果进行了准确度分析

3. 小结

本章的案例重在分析,虽然没用运用到机器学习具体的模型,但是着重分析了获取数据到分析数据的过程。
文章中实现了对用户的个性化推荐。通过对用户访问日志的数据进行分析与处理,采用基于物品的协同过滤算法对处理好的数据进行建模分析,最后通过模型评价与结果分析(精确度分析),发现基于物品的协同过滤算法的优缺点,同时对其缺点提出改进的方法。

 
 
课件 PDF 和 源码 移步到Githubhttps://github.com/Stormzudi/Python-Data-Mining

猜你喜欢

转载自blog.csdn.net/qq_41709378/article/details/108241491