数据分析和挖掘常用方法
-
介绍 聚类分析 回归分析 分类分析 以及其他常用分析手段
-
不同方法的内在业务联系
-
聚类分析
- 用户由哪些群体组成
- 这些群体有哪些明显特征
-
回归分析
- 未来销售趋势预测
- 营销投入如何影响销售
-
分类分析
- 如何筛选出更值得营销的用户
-
其它分析手段
- 关联分析
- 异常检测分析
-
聚类分析
聚类分析
-
聚类是将大量数据集中具有“相似”特征的数据点或样本划分为一个类别。
聚类常用于数据探索或挖掘前期,在没有做先验经验的背景下做的探索性分析,也适用于样本量较大情况下的数据预处理工作。
-
常见应用场景
-
客户分群
- 针对企业整体的用户特征,在未得到相关知识或经验之前,先根据数据本身特点进行用户分群,然后针对不同群体做进一步分析
- 客户分群目的:用户分组,组内用户特征显示,不同组用户特征差异明显
-
客户分群的数据维度:
- 消费者行为习惯数据
- 消费者对产品的态度
- 消费者自身的人口统计学特征
- 顾客消费行为的度量(RFM)等数据
-
客户分群
-
聚类分析能解决的问题包括
- 数据集可以分为几类
- 每个类别有多少样本量
- 不同类别中各个变量的强弱关系如何(轮廓系数)
- 不同类别的典型特征是什么
-
基于聚类的客户分群:能帮助我们更清楚的认识客户
-
凭着经验和有限数据去理解客户,认识是模糊的
-
采用了聚类方法明确区分了不同客户的特征,对用户的认识更清晰
-
对客户有清晰的认识:
- 可以为不同客群提供定制化的产品或者服务
- 设定品牌的主要形象和定位
- 根据顾客需求,挖掘新的产品和服务机会
-
举例:某旅游类APP,利用积累的用户数据实现对不同客户的差异化运营策略,针对性的指定旅游产品
- 通过聚类分析实现客户分群
-
-
数据分群是否
-
与传统的分群方法相比的优势
- RFM
- 20%客户~80%价值
- 发现之前未知的因素,减少对业务理解局限性影响,能对新的数据快速复制
-
聚类分析非常注重落地效果,每次对用户或产品或社区进行聚类,需要具有如下特征
-
聚类后的用户分群有
明显特征
- 高富帅 矮穷矬
-
聚类之后的用户分群有
足够数量
的用户- 只有几十几百没意义
-
分群之后的用户
是否能触达
- 分群结果必须可操作,如果用户不可触达,如没有任何联系方式,也没有意义
-
从企业角度,做好客户分群需要有
充分的用户信息
- 注意消费者的购买历史,对营销的响应情况等信息的积累
- 尽可能积累对自己有用的有效客户信息
-
聚类后的用户分群有
-
聚类方法仍需要对分群结果进行解读,通过业务合理性来选择分群的数量
-
举例
import pandas as pd dataset = pd.read_csv('customers.csv') dataset.head()
- 考虑最后两列作为分群依据
X = dataset.iloc[:, [3, 4]].values#全部行,第四第五列 Annual Income (k$) 和 Spending Score (1-100)
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters = 5, init = 'k-means++', random_state = 42)#k=5
y_kmeans = kmeans.fit_predict(X)
#K-means与K-means++:
#原始K-means算法最开始随机选取数据集中K个点作为聚类中心,
#而K-means++按照如下的思想选取K个聚类中心:
#假设已经选取了n个初始聚类中心(0<n<K),则在选取第n+1个聚类中心时:距离当前n个聚类中心越远的点会有更高的概率被选为第n+1个聚类中心。
#在选取第一个聚类中心(n=1)时同样通过随机的方法。
- 画图展示聚类结果
plt.scatter(X[y_kmeans == 0, 0], X[y_kmeans == 0, 1], s = 100, c = 'red', label = 'Standard')
plt.scatter(X[y_kmeans == 1, 0], X[y_kmeans == 1, 1], s = 100, c = 'blue', label = 'Traditional')
plt.scatter(X[y_kmeans == 2, 0], X[y_kmeans == 2, 1], s = 100, c = 'green', label = 'Normal')
plt.scatter(X[y_kmeans == 3, 0], X[y_kmeans == 3, 1], s = 100, c = 'cyan', label = 'Youth')
plt.scatter(X[y_kmeans == 4, 0], X[y_kmeans == 4, 1], s = 100, c = 'magenta', label = 'TA')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s = 300, c = 'black', label = 'Centroids')
plt.title('Clusters of customers')
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.legend()
plt.show()
- 评估聚类个数
import matplotlib.pyplot as plt
wcss = []
for i in range(1, 11): #循环使用不同k测试结果
kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
kmeans.fit(X)
wcss.append(kmeans.inertia_) #inertia簇内误差平方和
plt.plot(range(1, 11), wcss)
plt.title('The Elbow Method')
plt.xlabel('Number of clusters')
plt.ylabel('WCSS')
plt.show()
-
结论 5个分群比较好
-
聚类时要注意的问题
-
K均值(K-Means)是
聚类
中最常用的方法之一,它基于点与点距离的相似度来计算最佳类别归属。但K均值在应用
之前一定要注意两种数据异常
:-
1)
数据的异常值
。数据中的异常值能明显改变不同点之间的距离相似度,并且这种影响是非常显著的。因此
基于距离相似度的判别模式下,异常值的处理必不可少。
-
2)
数据的异常量纲
。不同的维度和变量之间,如果存在数值规模或量纲的差异,那么在做距离之前需要先将变量归一化或标准化。例如,跳出率的数值分布区间是[0,1],订单金额可能是[0,10000000],而订单数量则是[0,1000]。如果没有归一化或标准化操作,那么相似度将主要受到订单金额的影响。
-
1)
-
数据量过大的时候不适合使用k-means
- K-Means在算法稳定性、效率和准确率(相对于真实标签的判别)上表现非常好,并且在应对大量数据时依然如此。它的算法时间复杂度上界为O(n * k * t),其中n是样本量、k是划分的聚类数、t是迭代次数。
-
当聚类数和迭代次数不变时,K均值的算法消耗时间只跟样本量有关,因此会呈线性增长趋势。
当真正面对海量数据时,使用K均值算法将面临严重的结果延迟,尤其是当K均值被用做实时性或准实时性的数据预处理、分析和建模时,这种瓶颈效应尤为明显。 -
针对K均值的这一问题,很多延伸算法出现了,MiniBatchKMeans就是其中一个典型代表。-
-
MiniBatchKMeans使用了一个名为Mini Batch(分批处理)的方法计算数据点之间的距离。
MiniBatch的好处是计算过程中不必使用所有的数据样本,而是从不同类别的样本中抽取一部分样本(而非全部样本)作为代表参与聚类算法过程。 - 由于计算样本量少,所以会相应减少运行时间;但另一方面,由于是抽样方法,抽样样本很难完全代表整体样本的全部特征,因此会带来准确度的下降
- 经过对30000样本点分别使用K-Means 和 MiniBatchKMeans 进行聚类,对比之后运行时间 MiniBatchKMeans 是 K-Means的一半 (0.17 v.s. 0.36),但聚类结果差异性很小
- 结论:MiniBatchKMeans在基本保持了K-Means原有较高类别识别率的前提下,其计算效率的提升非常明显。因此,MiniBatchKMeans是一种能有效应对海量数据,尽量保持聚类准确性并且大幅度降低计算耗时的聚类算法
-
MiniBatchKMeans使用了一个名为Mini Batch(分批处理)的方法计算数据点之间的距离。
-
K均值(K-Means)是
-
聚类分析案例
- 年龄与收入分群
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline #加载数据 ageinc_df=pd.read_csv('ageinc.csv') ageinc_df.info() #两列数据,年龄与收入
- 输出显示
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1000 entries, 0 to 999 Data columns (total 2 columns): income 1000 non-null int64 age 1000 non-null int64 dtypes: int64(2) memory usage: 15.7 KB
- 查看数据基本统计信息
ageinc_df.describe()
- 需要对数据进行标准化
ageinc_df['z_income']=(ageinc_df['income']-ageinc_df['income'].mean())/ageinc_df['income'].std() #(收入-收入均值)/收入标准差 ageinc_df['z_age']=(ageinc_df['age']-ageinc_df['age'].mean())/ageinc_df['age'].std() #(年龄-年龄均值)/年龄标准差 ageinc_df.describe()
- 初步进行数据可视化
sns.scatterplot(x='income',y='age',data=ageinc_df)
- 进行聚类分析
from sklearn import cluster model=cluster.KMeans(n_clusters=3,random_state=10) model.fit(ageinc_df[['z_income','z_age']]) #导入sklearn中的cluster #将群体分成3层 #用标准化的收入与年龄来拟合模型 #KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300, # n_clusters=3, n_init=10, n_jobs=1, precompute_distances='auto', # random_state=10, tol=0.0001, verbose=0) #为用户打上标签 ageinc_df['cluster']=model.labels_ #查看用户的分群情况 ageinc_df.head(50)
- 将分群结果可视化
sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df) #横轴为年龄,纵轴为收入,分类为用户分群标签
- 将用户分为4层
from sklearn import cluster model=cluster.KMeans(n_clusters=4,random_state=10) model.fit(ageinc_df[['z_income','z_age']]) #导入sklearn中的cluster #将群体分成4层 #用标准化的收入与年龄来拟合模型 ageinc_df['cluster']=model.labels_ sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df) #横轴为年龄,纵轴为收入,分类为用户分群标签
-
可视化
-
将用户分为6层
from sklearn import cluster model=cluster.KMeans(n_clusters=6,random_state=10) model.fit(ageinc_df[['z_income','z_age']]) #导入sklearn中的cluster #将群体分成6层 #用标准化的收入与年龄来拟合模型 ageinc_df['cluster']=model.labels_ sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df) #横轴为年龄,纵轴为收入,分类为用户分群标签
- 查看不同层用户的收入数据
#使用groupby函数,将用户按照所在群分组,统计收入的数据 ageinc_df.groupby(['cluster'])['income'].describe()
- 分析用户为4层的收入与年龄数据
from sklearn import cluster model=cluster.KMeans(n_clusters=4,random_state=10) model.fit(ageinc_df[['z_income','z_age']]) #导入sklearn中的cluster #将群体分成4层 #用标准化的收入与年龄来拟合模型 ageinc_df['cluster']=model.labels_ #收入 ageinc_df.groupby(['cluster'])['income'].describe()
- 发现收入分为2档,一档0-8w,一档8-18w
#年龄 ageinc_df.groupby(['cluster'])['age'].describe()
- 发现年龄分为2档,0和3为18岁-39岁中青年,1和2为40-60岁中老年
airbnb客户分层
-
案例背景
- Airbnb在全球拥有广泛丰富的用户出行场景。自身在app和网页端,以及通过各种营销渠道会收集到非常全面的用户行为数据
- 通过这些数据,锁定潜在的目标客群并指定相应的营销策略是Airbnb发展的重要基石
-
数据解释
字段名字 字段名字 id 唯一的用户id Android 安卓APP中预订 date_account_created 用户注册日期 Moweb 手机移动网页预订 date_first_booking 第一次订房日期 Web 电脑网页预订 Gender 性别 iOS 苹果APP预订 Age 年龄 Language_en 使用英文界面 Married 已婚 Language_Zh 使用中文界面 Children 有几个小孩 Country_us 目的地是美国 Country_eu 目的地是欧洲 -
数据分析思路
- 分析目标:通过数据,分析用户群体的核心特征
-
分析流程:数据概况分析->单变量分析->聚类分析
-
数据概况分析
- 数据行/列数量
- 缺失值分布
-
单变量分析
- 数字型变量的描述指标
- 类别型变量
- 日期型变量处理
-
聚类分析
- 模型建立
- 选择群数
- 模型评估与优化
-
数据概况分析
-
代码
- 导入数据并查看数据情况
import pandas as pd airbnb=pd.read_csv('airbnb.csv') #查看数据类型 #变量类别:用户个人信息、用户与airbnb的关系、app使用语言、用户去的国家、用户下单渠道 #这里有2个日期变量,之后会进行操作 airbnb.info()
- 用户数据具体情况
airbnb.head()
- 单变量分析
airbnb.describe()
- 发现年龄最小是2最大是2014,属于数据异常,进行数据清洗,这里保留用户年龄在18-70岁之间的群体
airbnb=airbnb[airbnb['age']<=70] airbnb=airbnb[airbnb['age']>=18] airbnb.age.describe()
- 日期数据处理
#将注册日期转变为日期时间格式 airbnb['date_account_created']=pd.to_datetime(airbnb['date_account_created']) airbnb.info() #data_account_created变量格式从object转变为datetime64
#将年份从中提取出来,将2019-注册日期的年份,并生成一个新的变量year_since_account_created airbnb['year_since_account_created']=airbnb['date_account_created'].apply(lambda x:2019-x.year) #计算注册至今(2019年)有几年 airbnb.year_since_account_created.describe() #注册时间最短的是5年,最长的是9年
- 计算用户第一次预定到2019年的时间
airbnb['date_first_booking']=pd.to_datetime(airbnb['date_first_booking']) airbnb['year_since_first_booking']=airbnb['date_first_booking'].apply(lambda x:2019-x.year) airbnb.year_since_first_booking.describe() #距离第一次预定时间最短的是4年,最长的是9年
- 将类别型型转化成哑变量(gender)
airbnb=pd.get_dummies(airbnb) airbnb.info()
- 删除两个日期变量,可以根据数据格式来进行drop
airbnb.drop(airbnb.select_dtypes(['datetime64']),inplace=True,axis=1)
- 选择五个变量,作为分群的维度
airbnb_5=airbnb[['age','web','moweb','ios','android']] #数据标准化,使用sklearn中预处理的scale from sklearn.preprocessing import scale x=pd.DataFrame(scale(airbnb_5)) #使用cluster建模 from sklearn import cluster #先尝试分为3类 model=cluster.KMeans(n_clusters=3,random_state=10) model.fit(x) #KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300, # n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto', # random_state=10, tol=0.0001, verbose=0) #提取标签,查看分类结果 airbnb_5['cluster']=model.labels_ airbnb_5.head(10)
- 模型评估与优化
#使用groupby函数,评估各个变量维度的分群效果 airbnb_5.groupby(['cluster'])['age'].describe()
airbnb_5.groupby(['cluster'])['ios'].describe()
- 使用silhouette score,评估模型效果
from sklearn import metrics#调用sklearn的metrics库 x_cluster=model.fit_predict(x)#个体与群的距离 score=metrics.silhouette_score(x,x_cluster)#评分越高,个体与群越近;评分越低,个体与群越远 print(score) 0.6304549142727769 centers=pd.DataFrame(model.cluster_centers_) centers.to_csv('center_3.csv') #将群体分为5组 model=cluster.KMeans(n_clusters=5,random_state=10) model.fit(x) centers=pd.DataFrame(model.cluster_centers_) centers.to_csv('center_5.csv')
- 分三组之后的中心点数据
age web moweb ios android 0 -0.084934709 0.230108024 1.372846487 -0.271346118 -1.372434556 1 0.073627358 0.206536201 -0.726610207 -0.271346118 0.726088466 2 -0.264674063 -2.914414684 0.132659495 3.685330034 -0.129903148 - 分五组的中心点数据
age web moweb ios android 0 1.567477405 0.34312207 -0.726610207 -0.271346118 0.728632193 1 -0.073690494 0.34312207 1.37625372 -0.271346118 -1.372434556 2 -0.264674063 -2.914414684 0.132659495 3.685330034 -0.129903148 3 -0.240134866 -2.914414684 -0.124800902 -0.271346118 0.055424414 4 -0.450412767 0.34312207 -0.726610207 -0.271346118 0.728632193
回归分析
-
回归是研究自变量x对因变量y影响的一种数据分析方法
- 最简单的回归模型是一元线性回归,可以表示为Y=β0+β1x+ε,其中Y为因变量,x为自变量,β1为影响系数,β0为截距,ε为随机误差。
- 回归分析是广泛应用的统计分析方法,可用于分析自变量和因变量的影响关系(通过自变量求因变量),也可以分析自变量对因变量的影响方向(正向影响还是负向影响)。
-
回归分析的主要应用场景是进行预测和控制例如计划制定、
KPI
(绩效关键指标法[2/8法则])制定、目标制定等;也可以基于预测的数据与实际数据进行比对和分析,确定事件发展程度并给未来行动提供方向性指导。 - 常用的回归算法包括线性回归、多项式回归等
- 回归分析的优点是数据模式和结果便于理解,如线性回归用y=ax+b的形式表达,在解释和理解自变量与因变量关系式相对容易;在基于函数公式的业务应用中,可以直接使用代入法求解,因此应用起来比较容易。
- 回归分析的缺点是只能分析少量变量之间的相互关系,无法处理海量变量间的相互作用关系,尤其是变量共同因素对因变量的影响程度。
-
回归分析的落地场景
-
在各种媒体上投放的广告对最终销售所产生的效果研究
-
公司可以投入的营销渠道
- 传统大众媒体:电视 广播 户外广告
- 直销媒体:电子邮件,短信,电话
- 数字媒体:app 微信 社交应用
-
通过回归分析可以回答
- 各个营销渠道如何互相营销促进销售
- 如何调整营销组合使每一份支出获取最大收益
- 同时在不同渠道进行广告营销,哪个效果更明显
-
销售量 = 营销变量 + 误差因素
-
营销变量 : 可控的渠道投入
- 线上产品:微信 微博 头条
- 传统产品:电商 微信 户外 电视
-
误差因素:不可控的所有因素
- 经济大环境,季节,假期,对手
-
营销变量 : 可控的渠道投入
-
营销变量和销售量之间是线性关系
- 营销投入越大,销售量也会对应的逐步提高
-
回归分析模型:销售额 =93765+0.3* 百度+0.15 * 社交媒体+0.05 *电话直销+0.02 * 短信
- 线性回归模型,假设解释变量和因变量之间是线性关系,但实际情况,销售收入不会随着广告的投入而一直上升
- 使用回归模型的结果,最主要的还是观察各个因素的大小做横向对比
-
公司可以投入的营销渠道
- 回归分析的结果,着重于不同X对于Y影响的对比,直接预测Y的场景较少
-
在各种媒体上投放的广告对最终销售所产生的效果研究
-
回归分析实战
-
P&G销售额预测分析
-
P&G 快消企业,分析目的
- 对商超门店的销售额进行预测
- 量化自身所能控制的各种促销因素所能产生的效果
- 对营销资源做出合理规划
-
P&G传统快消企业,数据特点
- 聚合类的数据
- 渠道众多,无法精准了解用户
-
本例中,通过回归分析实现对各类因素投入产出比做出评估
-
分析数据
- 电视广告,线上,线下,门店内,微信渠道等促销投入和销售额之间的关系
-
数据说明 (以月为观测窗口)
- Revenue 门店销售额
- Reach 微信广告次数
- Local_tv 本地电视广告投入
- Online 线上广告投入
- Instore 门店内海报等投入
- Person 门店促销人员
-
Event 促销事件
- cobranding 品牌联合促销
- holiday 节假日
- special 门店特别促销
- non-event 无促销活动
-
分析流程:数据概况分析->单变量分析->相关性分析与可视化->回归模型
-
数据概况分析
- 数据行/列数量
- 缺失值分布
-
单变量分析
- 数字型变量的描述指标(平均值,最大最小值,标准差)
- 类别型变量(多少个分类,各自占比)
-
相关性分析与可视化
- 按类别交叉对比
- 变量之间的相关性分析
- 散点图/热力图
-
回归分析
- 模型建立
- 模型评估与优化
-
数据概况分析
-
分析数据
- 代码
import pandas as pd #数据读取# #index_col=0 ,数据的第一列是索引,指定索引列 store=pd.read_csv('w2_store_rev.csv',index_col=0)
#数据的基本信息 #发现local_tv有50多个空值 #发现event是object,即类别型变量 store.info()
#统计各个列哪些是空值 #发现local_tv有56个空值 store.isnull().sum() ''' revenue 0 reach 0 local_tv 56 online 0 instore 0 person 0 event 0 dtype: int64 ''' #了解数据的分布 #判断数据是否符合业务场景 store.describe()
#了解event的具体值 store.event.unique() #array(['non_event', 'special', 'cobranding', 'holiday'], dtype=object) #这些类别对应的revenue(销售额)是怎样的 store.groupby(['event'])['revenue'].describe()
#这几个类别对应的local_tv(本地电视广告投入)是怎样的 store.groupby(['event'])['local_tv'].describe()
#将类别变量转化为哑变量 store=pd.get_dummies(store) #生成event的4个标签,每个标签取值0/1 store.head(10)
#确认类别变量已经转换成数字变量 store.info() ''' <class 'pandas.core.frame.DataFrame'> Int64Index: 985 entries, 845 to 26 Data columns (total 10 columns): revenue 985 non-null float64 reach 985 non-null int64 local_tv 929 non-null float64 online 985 non-null int64 instore 985 non-null int64 person 985 non-null int64 event_cobranding 985 non-null uint8 event_holiday 985 non-null uint8 event_non_event 985 non-null uint8 event_special 985 non-null uint8 dtypes: float64(2), int64(4), uint8(4) memory usage: 57.7 KB '''
- 相关性分析
#所有变量,任意两个变量相关分析 #local_tv,person,instore是比较好的指标,与revenue相关度高 store.corr()
#其他变量与revenue的相关分析 #sort_values 将revenue排序,ascending默认升序,False为降序排列 #看到前3个相关变量为local_tv,person,instore store.corr()[['revenue']].sort_values('revenue',ascending=False) ''' revenue revenue 1.000000 local_tv 0.602114 person 0.559208 instore 0.311739 online 0.171227 event_special 0.033752 event_cobranding -0.005623 event_holiday -0.016559 event_non_event -0.019155 reach -0.155314 '''
- 可视化分析
#可视化分析 import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline #线性关系可视化 #斜率与相关系数有关 sns.regplot('local_tv','revenue',store)
#线性关系可视化 sns.regplot('person','revenue',store)
sns.regplot('instore','revenue',store)
- 线性回归分析
from sklearn.linear_model import LinearRegression model=LinearRegression() #设定自变量和因变量 y=store['revenue'] #第一次三个 x=store[['local_tv','person','instore'] #第二次四个 x=store[['local_tv','person','instore','online']] model.fit(x,y)
- 数据有缺失,不处理会报错,需要处理缺失值
#缺失值处理,填充0 store=store.fillna(0) #缺失值处理,均值填充 store=store.fillna(store.local_tv.mean()) store.info() ''' <class 'pandas.core.frame.DataFrame'> Int64Index: 985 entries, 845 to 26 Data columns (total 10 columns): revenue 985 non-null float64 reach 985 non-null int64 local_tv 985 non-null float64 online 985 non-null int64 instore 985 non-null int64 person 985 non-null int64 event_cobranding 985 non-null uint8 event_holiday 985 non-null uint8 event_non_event 985 non-null uint8 event_special 985 non-null uint8 dtypes: float64(2), int64(4), uint8(4) memory usage: 57.7 KB ''' #自变量系数 model.coef_ #模型的截距 model.intercept_ #模型的评估,x为'local_tv','person','instore' score=model.score(x,y)#x和y打分 predictions=model.predict(x)#计算y预测值 error=predictions-y#计算误差 rmse=(error**2).mean()**.5#计算rmse mae=abs(error).mean()#计算mae print(rmse) print(mae)
-
P&G 快消企业,分析目的
-
结果解读
-
注意应用回归模型时研究自变量是否产生变化
-
在应用回归模型做预测时,必须研究对因变量产生影响的自变量是否产生变化,主要考察两个方面:
-
是否产生了新的对因变量影响更大的自变量
- 在建立回归模型时,需要综合考虑自变量的选择问题。如果遗漏了重要的变量,那么模型很可能无法正确反映实际情况,而且参数估计是有偏的,此时的回归模型及其不稳定且方差较大。
- 同样在应用回归模型时,仍然需要重新评估该问题是否发生。例如,在做用户订单金额预测时是基于正常销售状态下的变量实现的;但当发生大型促销活动且促销活动因素没有被纳入回归模型中时,原来的回归模型则无法有效预测。
-
原有自变量是否仍然控制在训练模型时的范围之内。
如果有自变量的变化超过训练模型的范围,那么原来的经验公式可能无法在新的值域范围下适用,这种情况下通常需要重新做研究和建模。- 假设我们建立了一个回归模型,可以广告投放费用预测广告点击率,在训练回归模型时的广告费用在[0,1000]区间内,但在广告费用超过1000(例如2000)时,则无法保证最终预测效果的有效性。
-
是否产生了新的对因变量影响更大的自变量
-
在应用回归模型做预测时,必须研究对因变量产生影响的自变量是否产生变化,主要考察两个方面:
-
回归算法按照自变量的个数分为一元回归和多元回归,按照影响是否是线性分为线性回归和非线性回归。在面对不同回归方法的选择时,注意参考以下因素:
- 入门的开始——简单线性回归。如果是学习为主,那么不需要选择多么强大的模型,基于最小二乘法的普通线性回归最合适;同时,它适合数据集本身结构简单、分布规律有明显线性关系的场景。
- 如果自变量数量少或经过降维后得到了可以使用的二维变量(包括预测变量),那么可以直接通过散点图发现自变量和因变量的相互关系,然后选择最佳回归方法。
- 如果经过基本判断发现自变量间有较强的共线性关系,那么可以使用对多重共线性(自变量高度相关)能灵活处理的算法,例如岭回归。
- 如果在高维度变量下,使用正则化回归方法效果更好,例如Lasso、Ridge
- 如果要同时验证多个算法,并想从中选择一个来做好的拟合,可以使用交叉检验做多个模型的效果对比,并通过R-square、Adjusted R-square、AIC、BIC以及各种残差、误差项指标做综合评估。
- 如果注重模型的可解释性,那么容易理解的线性回归、多项式回归比较适合。
分类分析
-
分类算法概述
- 分类算法通过对已知类别训练集的计算和分析,从中发现类别规则并预测新数据的类别。分类算法是解决分类问题的方法,是数据挖掘、机器学习和模式识别中一个重要的研究领域。分类和回归是解决实际运营问题中非常重要的两种分析和挖掘方法。
- 常用的分类算法包括朴素贝叶斯、逻辑回归、决策树、随机森林、支持向量机等。
- 分类的主要用途和场景是“预测”,基于已有的样本预测新样本的所属类别,例如信用评级、风险等级、欺诈预测等。分类算法也可以用于知识抽取,通过模型找到潜在的规律,帮助业务得到可执行的规则。
-
案例 电信客户流失预测
-
案例简介
- AT&T数据,用户个人,通话,上网等信息数据
- 充分利用数据预测客户的流失情况
- 帮助挽留用户,保证用户基数和活跃程度
-
数据说明
- CustomerID 客户ID
- Gender 性别
- partneratt 配偶是否也为att用户
- dependents_att 家人是否也是att用户
- landline 是否使用att固话服务
- internet_att/internet_other 是否使用att的互联网服务
- Paymentbank/creditcard/electroinc 付款方式
- MonthlyCharges 每月话费
- TotalCharges 累计话费
- Contract_month/1year 用户使用月度/年度合约
- StreamingTv/streamingMovies 是否使用在线视频或者电影app
- Churn 客户转化的flag
-
处理流程
-
分析流程:数据概况分析->单变量分析->相关性分析与可视化->回归模型
-
数据概况分析
- 数据行/列数量
- 缺失值分布
-
单变量分析
- 数字型变量的描述指标(平均值,最大最小值,标准差)
- 类别型变量(多少个分类,各自占比)
-
正负样本占比
-
相关性分析与可视化
- 按类别交叉对比
- 变量之间的相关性分析
- 散点图/热力图
-
回归分析
- 模型建立
- 模型评估与优化
-
数据概况分析
-
分析流程:数据概况分析->单变量分析->相关性分析与可视化->回归模型
- 代码
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline churn=pd.read_csv('churn.csv') churn.info() ''' <class 'pandas.core.frame.DataFrame'> RangeIndex: 7043 entries, 0 to 7042 Data columns (total 16 columns): Churn 7043 non-null object gender 7043 non-null object Partner_att 7043 non-null int64 Dependents_att 7043 non-null int64 landline 7043 non-null int64 internet_att 7043 non-null int64 internet_other 7043 non-null int64 StreamingTV 7043 non-null int64 StreamingMovies 7043 non-null int64 Contract_Month 7043 non-null int64 Contract_1YR 7043 non-null int64 PaymentBank 7043 non-null int64 PaymentCreditcard 7043 non-null int64 PaymentElectronic 7043 non-null int64 MonthlyCharges 7043 non-null float64 TotalCharges 7043 non-null float64 dtypes: float64(2), int64(12), object(2) memory usage: 880.5+ KB ''' #预测目标是churn,是类别型变量 gender也是类别型变量 需要对类别型变量进行处理 churn.head() ''' Churn gender Partner_att Dependents_att landline internet_att \ 0 No Female 1 0 0 1 1 No Male 0 0 1 1 2 Yes Male 0 0 1 1 3 No Male 0 0 0 1 4 Yes Female 0 0 1 0 internet_other StreamingTV StreamingMovies Contract_Month Contract_1YR \ 0 0 0 0 1 0 1 0 0 0 0 1 2 0 0 0 1 0 3 0 0 0 0 1 4 1 0 0 1 0 PaymentBank PaymentCreditcard PaymentElectronic MonthlyCharges \ 0 0 0 1 29.85 1 0 0 0 56.95 2 0 0 0 53.85 3 1 0 0 42.30 4 0 0 1 70.70 TotalCharges 0 29.85 1 1889.50 2 108.15 3 1840.75 4 151.65 ''' #需要把churn和gender转变为数字型变量,使用get_dummies churn=pd.get_dummies(churn) churn.head() ''' Churn_No Churn_Yes gender_Female gender_Male 0 1 0 1 0 1 1 0 0 1 2 0 1 0 1 3 1 0 0 1 4 0 1 1 0 ''' #数据整理,将churn_yes保留,将female保留,drop不需要的数据 churn.drop(['Churn_No','gender_Male'],axis=1,inplace=True) #变量大小写不规则,统一变成小写 churn.columns=churn.columns.str.lower() churn.head() ''' churn_yes gender_female 0 0 1 1 0 0 2 1 0 3 0 0 4 1 1 ''' #将churn_yes重命名,方便后续的变量编写 churn=churn.rename(columns={'churn_yes':'flag'}) #二分类模型,分析flag 1和0的占比 churn.flag.value_counts() ''' 0 5174 1 1869 Name: flag, dtype: int64 ''' churn.flag.value_counts(1) ''' 0 0.73463 1 0.26537 Name: flag, dtype: float64 ''' summary=churn.groupby('flag') summary.mean() ''' partner_att dependents_att landline internet_att internet_other \ flag 0 0.528218 0.344801 0.901044 0.379204 0.347700 1 0.357945 0.174425 0.909042 0.245586 0.693954 streamingtv streamingmovies contract_month contract_1yr paymentbank \ flag 0 0.365868 0.369927 0.429068 0.252609 0.248550 1 0.435527 0.437667 0.885500 0.088818 0.138042 paymentcreditcard paymentelectronic monthlycharges totalcharges \ flag 0 0.249324 0.250097 61.265124 2545.918081 1 0.124131 0.573034 74.441332 1528.514714 gender_female flag 0 0.492656 1 0.502408 '''
- 观察flag在0和1的情况下,所有自变量的差别 internet_other变量,在0的分组中,均值是0.35,在1的分组中,均值是0.69。数据显示如果使用别的公司的互联网,用户流失的概率就越高
sns.countplot(y='contract_month',hue='flag',data=churn)
- 结论:contract_month为1的客户流失的概率更高,即与非按月付费客户相比,按月付费客户流失比例高
- 相关性分析
#围绕flag变量,分析其他变量与flag的相关关系 churn.corr()[['flag']].sort_values('flag',ascending=False) ''' flag flag 1.000000 contract_month 0.405103 internet_other 0.308020 paymentelectronic 0.301919 monthlycharges 0.193356 streamingtv 0.063228 streamingmovies 0.061382 landline 0.011942 gender_female 0.008612 paymentbank -0.117937 internet_att -0.124214 paymentcreditcard -0.134302 partner_att -0.150448 dependents_att -0.164221 contract_1yr -0.177820 totalcharges -0.198175 ''' # contract_month与internet_other与flag相关性高
- 逻辑回归模型
#设定因变量与自变量, y 是 flag, x 根据刚才的相关分析挑选contract_month,internet_other与streamingtv #自变量可以分为几类,partner/dependents,internet,streaming,contract,payment,charges,后续大家可以自己挑选进行建模 y=churn['flag'] x=churn[['contract_month','internet_other','streamingtv']] #模型优化,streamingtv调整为paymentelectronic y=churn['flag'] x=churn[['contract_month','internet_other','paymentelectronic']] #调用sklearn模块,随机抽取训练集与测试集 from sklearn.model_selection import train_test_split x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3,random_state=100) #模型优化,测试集与训练集对半分,第三次也执行此处代码 from sklearn.model_selection import train_test_split x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.5,random_state=100) #使用sklearn from sklearn import linear_model lr=linear_model.LogisticRegression() lr.fit(x_train,y_train) ''' LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1, penalty='l2', random_state=None, solver='liblinear', tol=0.0001, verbose=0, warm_start=False) '''
- 模型的截距与系数
#第一次 lr.intercept_ lr.coef_ #array([-3.21761938]) #array([[2.19790192, 1.14360005, 0.23641705]]) #第二次,测试集与训练集对半分 lr.intercept_ array([-3.26144359]) array([[2.23886897, 1.09248895, 0.32579547]]) #第三次,变量调整 array([-3.18770265]) array([[2.0019671 , 1.02830763, 0.62165925]])
- 模型的评估
y_pred_train=lr.predict(x_train) y_pred_test=lr.predict(x_test) import sklearn.metrics as metrics metrics.accuracy_score(y_train,y_pred_train) from sklearn.metrics import roc_curve,auc fpr,tpr,threshold=roc_curve(y_train,y_pred_train) roc_auc=auc(fpr,tpr)
-
案例简介
-
用分类分析来提炼规则、提取变量、处理缺失值
-
分类分析用于提炼应用规则
预测是分类分析的主要应用方向,但将分类用于提炼应用规则,为数据化运营提供规则支持也是其重点应用之一,这种应用相对于其他算法更加具有落地价值。常见的应用场景如下:- 要针对沉默会员做会员重新激活,应该挑选具有什么特征的会员?
- 商品A库存积压严重,现在要通过促销活动清仓,选择哪些类型的促销活动更容易实现该目标?
- 网站需要大流量广告位来满足VIP商家的精准广告投放,具有哪些特征的广告位更符合VIP商家的客户需求?
-
从分类算法中提炼特征规则,利用的是在构建算法过程中的分类规则
- 以决策树为例,决策树的分裂节点是表示局部最优值的显著特征值,每个节点下的特征变量以及对应的值的组合构成了规则。如图4-11所示是利用sklearn构建的决策树规则的一部分。其中X[0]~X[3]是决策树模型的特征变量,而类似于X[2]≤21891.5则是该特征变量对应显著性分裂值。
-
分类分析用于提取变量特征
- 具体实现思路是:获取原始数据集并对数据做预处理,将预处理的数据集放到分类算法中进行训练,然后从算法模型中提取特征权重信息。
-
分类分析用于处理缺失值
-
-
聚类和分类算法的区别
- 学习方式不同聚类是一种非监督式学习算法,而分类是监督式学习算法。
- 对源数据集要求不同,有无目标值
-
应用场景不同
- 聚类一般应用于数据探索性分析、数据降维、数据压缩等探索性、过程性分析和处理
- 分类更多地用于预测性分析和使用。
- 解读结果不同。聚类算法的结果是将不同的数据集按照各自的典型特征分成不同类别,不同人对聚类的结果解读可能不同;而分类的结果却是一个固定值(例如高、中、低、是、否等),不存在不同解读的情况。
-
模型评估指标不同
- 聚类分析没有所谓的“准确”与否,以及多么准确的相关度量,更多的是基于距离的度量。如果是对带有标签的数据集做聚类则可以做相似度、完整度等方面的评估
- 而分类模型的指标例如准确率、混淆矩阵、提升率等都有明显的好与坏、提升程度等评估指标。例如准确率、混淆矩阵、提升率等都有明显的好与坏、提升程度等评估指标。
- 假如原始数据集带有类别标签,那么选择分类或聚类算法都可以(标签列数据并不是一定要使用)。假如原始数据集不带有类别标签,那么只能选择使用聚类算法。
-
有关分类和聚类的应用示例
- 假如现在公司要对某新会员做促销活动,例如推荐商品、提供个性化信息、推荐最感兴趣的热榜等,并尽量提供该用户感兴趣的内容。
- 分类:基于现有的会员及其特定类别标签(可选择有代表性或与实际运营场景最相关的类别标签)做分类模型训练,将该新用户的数据作为新的样本输入模型,预测得到该用户所属的目标类别。接着计算该类别下用户最经常购买的商品、经常浏览的信息等,并给出推荐内容。
- 聚类:将新的会员和现有的会员作为一个整体做聚类分析,然后获得该会员所属的聚类类别,进而提取其所在类别下其他会员的经常购买商品、经常浏览信息等,并给出推荐内容。
-
如何选择分类分析算法
- 文本分类:朴素贝叶斯,例如电子邮件中垃圾邮件的识别。
- 训练集较小,选择高偏差且低方差的分类算法:朴素贝叶斯、支持向量机(不容易过拟合)
-
算法模型的计算时间短和模型易用性,
不要选
支持向量机、人工神经网络 - 重视算法的准确率:支持向量机或GBDT、XGBoost等基于Boosting的集成方法
- 注重效果的稳定性或模型鲁棒性,那么应选择随机森林、组合投票模型等基于Bagging的集成方法。
- 想得到有关预测结果的概率信息,基于预测概率做进一步的应用:逻辑回归
- 担心离群点或数据不可分并且需要清晰的决策规则:决策树。
关联分析
- 关联分析通过寻找最能够解释数据变量之间关系的规则,来找出大量多元数据集中有用的关联规则,它是从大量数据中发现多种数据之间关系的一种方法。另外,它也可以基于时间序列对多种数据间的关系进行挖掘。
- 关联分析的典型案例是“啤酒和尿布”的捆绑销售,即买了尿布的用户还会同时买啤酒。
- 关联规则相对其他数据挖掘模型更加简单,易于业务理解和应用关联模型的典型应用场景是购物篮分析等,通过分析用户同时购买了哪些商品来分析用户购物习惯。这种策略还会应用于捆绑销售、库存管理、商品促销设计、页面促销设计、货架设计、商品陈列设计、页面内容排版、推荐系统、商品价格策略和基于购买的用户特征分析等。网站分析工具Webtrekk中的关联分析报表便应用了关联规则算法。
关联分析相关概念
关联分析是一种在大规模数据集中寻找有趣关系的任务。 这些关系可以有两种形式:
- 频繁项集(frequent item sets)是指经常出现在一块的物品的集合。
- 关联规则(associational rules)是暗示两种物品之间可能存在很强的关系。
从大规模数据集中寻找物品间的隐含关系被称作关联分析(association analysis)或者关联规则学习(association rule learning)
- 关联性衡量指标
假设我们下图所示的一份数据集
记录1 豆奶,莴苣
记录2 莴苣,尿布,葡萄酒,甜菜
记录3 豆奶,尿布,葡萄酒,橙汁
记录4 莴苣,豆奶,尿布,葡萄酒
记录5 莴苣,豆奶,尿布,橙汁
确定X, Y的关联性,需要用两个指标来衡量:
-
支持度(support)
支持度是针对项集而言的
项集的支持度被定义为数据集中包含该项集的记录所占的比例
那么项集
{豆奶}
的支持度就是4/5,那么项集
{豆奶, 莴苣}
的支持度就是3/5 -
置信度(confidence)
置信度也成为可信度,是针对一个关联规则而言的,如
{豆奶}
>>>
{莴苣}
,表示
{豆奶}
之于
{莴苣}
的关联程度(注意:
{莴苣}
>>>
{豆奶}
不等价于
{豆奶}
>>>
{莴苣}
)
{豆奶}
>>>
{莴苣}
的置信度 = 支持度(
{豆奶, 莴苣}
)/支持度(
{豆奶}
),即3/4
{莴苣}
>>>
{豆奶}
的置信度 = 支持度(
{豆奶, 莴苣}
)/支持度(
{莴苣}
),即3/4注意:这里他们俩的置信度相等纯属巧合
如果不考虑关联规则的支持度和置信度,那么在数据库中会存在着无穷多的关联规则。因此我们为了提取出真正的频繁项集和关联规则,必须指定一个最小支持度阈值和最小置信度阈值,因为对于支持度和置信度太低的关联规则基本没有什么使用价值。
-
最小支持度
:它表示了一组物品集在统计意义上需要满足的最低程度
-
最小可信度
它反映了关联规则的最低可靠程度
**同时满足最小可信度阈值和最小支持度阈值的关联规则被称为强关联规则。**比如啤酒与尿布。
比如这里,如果我们假设最小支持度阈值为50%,最小可信度阈值为70%,那么这里
{豆奶}
>>>
{莴苣}
和
{莴苣}
>>>
{豆奶}
都属于符合条件的两条关联规则,分别表示:
- 同时购买豆奶和莴苣的顾客占全部顾客的60%
-
{豆奶}
>>>
{莴苣}
:在购买豆奶的用户中,有75%的顾客会购买莴苣 -
{莴苣}
>>>
{豆奶}
:在购买莴苣的用户中,有75%的顾客会购买豆奶
频繁规则和有效规则
-
频繁规则:指的是关联结果中
支持度
和
置信度
都比较高的规则, -
有效规则指的是关联规则真正能促进规则中的前/后项的提升
-
在做关联结果分析时,频繁规则往往会被“想当然”地认为是有效规则,但实际情况却并总是如此。
-
举例:1000条事务数据用来显示购买苹果和香蕉的订单记录
- 其中有600个客户的订单记录中包含了苹果
- 有800个客户的订单记录中包含了香蕉
- 有400个客户同时购买了苹果和香蕉
-
假如我们产生了一条关联规则,用来表示购买了苹果的客户中还有很多人购买香蕉,那么该规则可以表示为:苹果→香蕉。
- 支持度:support=P((A,B)|ALL)=P(B&A)/P(ALL)=400/1000=40%
- 置信度:confidence=P(B|A)=P(B&A)/P(A)=400/600=67%
-
只看支持度和置信度将无法完整体现规则的有效性,通过另一个指标
提升度
则可以有效应对该问题- 买了苹果的客户中有67%的人也会同时购买香蕉 看似不错
- 所有购买了香蕉的客户比例80%(800/1000)
-
提升度(Lift)
- 指的是应用关联规则和不应用产生结果的比例
- 当提升度为1时,说明应用关联规则和不应用关联规则产生相同
- 当提升度大于1时,说明应用关联规则比不应用关联规则能产生更好的结果
- 当提升度小于1时,关联规则具有负相关的作用,该规则是无效规则
- 上面的案例中 Lift=P(B|A)/P(B)=(400/600)/(800/1000)=0.67/0.8=0.83
-
关联规则的应用场景
-
相同维度下的关联分析(关联分析的前后项是相同逻辑的内容维度)
-
网站页面浏览关联分析
- 可以帮助我们找到用户在不同页面(包含广告页、活动页、超市页、单品页、帮助页等)之间的频繁访问关系,以分析用户特定的页面浏览模式。
- 可用于了解不同页面之间的分流和引流关系
- 可以用来做不同页面间的页面浏览推荐,利于提高用户网站体验和转化率。
-
广告流量关联分析
- 针对站外广告投放渠道用户浏览或点击的行为分析,该分析主要用于了解用户的浏览和点击广告的模式,例如点击了A广告之后又点击了B广告;浏览了C广告之后又浏览了D广告
- 这种站外广告曝光和点击的关联分析可以为广告的精准投放提供参考。
- 可以用于网站引流的分析,假如公司通过一组整合传播媒体做活动宣传,那么我们可以分析用户通过宣传渠道到达网站的先后关系和频繁模式,可以从中发觉类似于用户从M广告到达网站之后,还会从N媒体点击到达网站,这对于广告媒体的投放组合和整合营销评估具有重要意义。
-
用户关键字搜索关联分析
- 分析用户在站内的搜索关键字是发现用户搜索兴趣并了解用户真实需求的方法之一。通过对用户搜索关键字的关联分析,可以得到类似于搜索了苹果之后又搜索了iPhone,搜索了三星之后又搜索了HTC,这种关联模型可用于搜索推荐、搜索联想等场景,有助于改善搜索体验,提高客户的目标转化率。
-
网站页面浏览关联分析
-
跨维度的关联分析
-
不同场景下的关联分析
发生的事件处于不同的时间下,但通常都在一个约束时间范围内(例如session,会话)。这种模式可以广泛用于分析运营中关注的要素- 例如用户浏览商品与购买商品的关联分析、关注产品价格与购买商品价格的关联分析、用户加入购物车与提交订单的关联分析等
- 通过这种跨事件的关联分析,可以找到用户不同行为模式之间的关系,尤其可以发掘用户的真实需求和关注(潜在)需求之间的关联和差异性。这些信息可用于针对当前用户行为的个性化推荐,并对后续促销活动的价格策略的制定有参考价值。
-
相同场景下的事件关联
- 用户在同一个页面中点击不同功能、选择不同的应用等
- 这类信息可以帮助我们了解用户对于功能应用的先后顺序,有利于做产品优化和用户体验提升;对于不同产品功能组合、开发和升级有了更加明确的参考方向,便于针对用户习惯性操作模式做功能迭代
- 针对用户频繁查看和点击的内容,可以采用打包、组合、轮转等策略,帮助客户尽量缩小内容查找空间和时间,也能提升内容曝光度和用户体验度。
-
不同场景下的关联分析
-
负相关,支持度和置信度高而提升度低的强规则使用
- 在商品销售策略中,不将具有互斥性的商品放到同一个组合购买计划中。
- 在站外广告媒体的投放中,不将具有互斥性的多个广告媒体做整合传播或媒体投放。
- 在关键字提示信息中,不将具有互斥性的关键字提示给客户。
- 在页面推荐的信息流中,不将具有互斥性的信息流展示给用户。
-
关联规则使用的逆向思维
-
常见的关联规则基于两种模式产生:
- 基于同一个时间内发生的事件:购物篮分,使用订单ID获取要分析的item数据
- 基于不同时间下发生的事件,但是可以通过特定的主键信息关联:用户在不同日期购买了多件商品,使用用户ID获取要分析的item数据
-
是否一定要将这些关联项放到一起?
- 将前后项内容故意分离开,利用用户主动查找的时机来产生更多价值或完成特定转化目标
-
不放到一起的前提:
- 关联规则必须是强规则&效规则
- 发生关联的前后项之间需要有非常强的完成动机
- 不能过多降低用户体验
- 举例:在做大型促销活动时,需要用户完成多个步骤才能获得超底价商品的购买资格
-
常见的关联规则基于两种模式产生:
-
关联规则的序列模式(基于不同时间下发生的频繁规则)
- 于普通关联模式最大的区别:有时间间隔,且有先后顺序,如购买了冰箱的客户会在3个月内购买洗衣机。
- 这是一种预测性分析的模式,能够将事件发生的时间和对象提取出来,因此更加适合对基于时间下的数据化运营的应用需求。
-
常见使用场景
- 客户购买行为预测:基于用户上次的购买时间和商品信息,预测下次购物的时间和商品
- Web访问模式预测:基于用户上次浏览页面的时间和页面信息,预测下次最可能浏览的页面
- 关键字搜索预测:基于用户上次搜索关键字的时间和关键字,预测下次最可能搜索哪些关键字
-
相同维度下的关联分析(关联分析的前后项是相同逻辑的内容维度)
案例 商品交叉销售分析
# 导入库
import pandas as pd
import apriori
#加载数据文件
data = pd.read_csv('order_table.csv')
# 转换为关联所用的记录模式
order_ids = pd.unique(data['order_id'])
order_records = [data[data['order_id']==each_id]['product_name'].tolist() for each_id in order_ids]
# 通过调用自定义的apriori做关联分析
minS = 0.1 # 定义最小支持度阀值
minC = 0.5 # 定义最小置信度阀值
L, suppData = apriori.apriori(order_records, minSupport=minS) # 计算得到满足最小支持度的规则
rules = apriori.generateRules(order_records, L, suppData, minConf=minC) # 计算满足最小置信度的规则
# 关联结果报表评估
model_summary = 'data record: {1} \nassociation rules count: {0}' # 展示数据集记录数和满足阀值定义的规则数量
print(model_summary.format(len(rules), len(order_records)),'\n','-'*60) # 使用str.format做格式化输出
rules_all = pd.DataFrame(rules, columns=['item1', 'item2', 'instance', 'support', 'confidence',
'lift']) # 创建频繁规则数据框
rules_sort = rules_all.sort_values(['lift'],ascending=False)
rules_sort.head(10)
'''
data record: 2240
association rules count: 169
------------------------------------------------------------
item1 item2 instance support \
113 (berries) (whipped/sour cream) 27 0.0121
168 (curd) (yogurt, whole milk) 29 0.0129
80 (butter) (whipped/sour cream) 32 0.0143
166 (frozen vegetables) (other vegetables, whole milk) 23 0.0103
55 (tropical fruit) (pip fruit) 48 0.0214
54 (pip fruit) (tropical fruit) 48 0.0214
81 (curd) (whipped/sour cream) 32 0.0143
167 (root vegetables) (other vegetables, whole milk) 50 0.0223
30 (beef) (root vegetables) 36 0.0161
40 (cream cheese ) (citrus fruit) 23 0.0103
confidence lift
113 0.3253 4.1168
168 0.2042 3.6307
80 0.2560 3.2398
166 0.2190 3.0288
55 0.2087 2.9967
54 0.3077 2.9967
81 0.2254 2.8519
167 0.2041 2.8219
30 0.2903 2.6544
40 0.2500 2.6415
'''
异常检测分析
-
数据集中的异常数据通常被认为是异常点、离群点或孤立点,特点是这些数据的特征与大多数数据不一致,呈现出“异常”的特点,检测这些数据的方法称为异常检测。
-
在大多数数据分析和挖掘工作中,异常值都会被当作“噪音”剔除。但在某些情况下,如果数据工作的目标就是围绕异常值展开,那么异常值会成为数据工作的焦点。
-
“噪音”的出现有多种原因
- 业务操作的影响(典型案例:网站广告费用增加10倍,导致流量激增)
- 数据采集问题(典型案例:数据缺失、不全、溢出、格式匹配等问题)
- 数据同步问题(异构数据库同步过程中的丢失、连接错误等导致的数据异常)
- 在对离群点进行挖掘分析之前,需要从中区分出真正的“离群数据”,将“垃圾数据”去掉。
-
常用的异常检测方法
- 基于统计的异常检测方法(如基于泊松分布、正态分布等分布规律找到异常分布点)
- 基于距离的异常检测方法(如基于K均值找到离所有分类最远的点)
- 基于密度的离群检测方法
- 基于偏移的异常点检测方法
- 基于时间序列的异常点监测方法等
-
异常值检测常用于异常订单识别、风险客户预警、黄牛识别、贷款风险识别、欺诈检测、技术入侵等针对个体的分析场景。
-
在大多数场景下,通过非监督式方法实现的异常检测的结果只能用来缩小排查范围、为业务的执行提供更加精准和高效的执行目标而已
异常检测案例
-
sklearn中提供了多种用于异常检测的方法
- one-class SVM(svm.OneClassSVM):该方法是SVM的变体,基于libsvm实现。它对数据集的分布没有假设,可应用到非高斯分布的数据,对高维数据非常有效。
- EllipticEnvelope(covariance.EllipticEnvelope):这是基于协方差的稳健估计,可用于异常检测,但前提是数据是高斯分布的。
- Isolation Forest(sklearn.ensemble.IsolationForest):一种与随机森林类似,都是高效的集成算法,算法鲁棒性高且对数据集的分布无假设。另外,基于树的集成算法,对数据特征的要求宽松。
- LocalOutlierFactor(sklearn.neighbors.LocalOutlierFactor):基于近邻的密度来估计局部偏差,然后确定异常因子,属于KNN的变体。
-
本示例的基本场景是:业务部门从Google Analytics原始数据中转换的点击数据,希望数据部门分析一下里面是否有异常流量,尤其是疑似作弊的流量
- 业务部门给的数据是不带标记的数据,只能用无监督式分析方法
- 查看数据之后发现,特征较多(47维),有的特征是分类型变量,有的特征是数值型变量
-
基于以上分析,选择
Isolation Forest
算法做非监督式的异常点检测分析- 该算法对特征的要求低,不需要做离散化,不需要数值标准化
- 不需要考虑特征间的关系(例如共线性)等,不需要额外做特征过滤和筛选
-
关于
Isolation Forest
-
孤立森林算法是一种适用于连续数据的无监督异常检测方法,由南京大学周志华教授等人于2008年首次提出,之后又于2012年提出了改进版本。
-
孤立森林算法通过对样本点的孤立来检测异常值
- 该算法利用一种名为孤立树iTree的二叉搜索树结构来孤立样本
- 异常值的数量较少且与大部分样本的特征不同
- 异常值会被更早的孤立出来,也即异常值会距离的根节点更近,而正常值则会距离根节点有更远的距离
- 相较于LOF,K-means等传统算法,孤立森林算法对高纬数据有较好的鲁棒性。
-
假设数据集有N条数据,构建一颗iTree时,从N条数据中均匀抽样(一般是无放回抽样)出ψ个样本出来,作为这颗树的训练样本。在样本中,随机选一个特征,并在这个特征的所有值范围内(最小值与最大值之间)随机选一个值,对样本进行二叉划分,将样本中小于该值的划分到节点的左边,大于等于该值的划分到节点的右边。由此得到一个分裂条件和左、右两边的数据集,然后分别在左右两边的数据集上重复上面的过程,直到数据集只有一条记录或者达到了树的限定高度。
-
代码
# 导入库 from sklearn.preprocessing import OrdinalEncoder from sklearn.ensemble import IsolationForest import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 导入3D样式库 # 数据准备 raw_data = pd.read_csv('outlier.txt',sep=',') # 读取数据 raw_data.shape #(10492, 47) # 去除全部为空的特征 data_dropna = raw_data.dropna(axis='columns',how='all') data_dropna = data_dropna.drop(['clientId'],axis=1) data_dropna.shape #(10492, 44) # 填充NA列 # 找到NA列 cols_is_na = data_dropna.isnull().any() na_cols = [cols_is_na.index[ind] for ind, na_result in enumerate(cols_is_na) if na_result == True] print(data_dropna[na_cols].dtypes) # 填充NA列 print(data_dropna[na_cols].head()) #print(type(data_dropna[na_cols].iloc[2,3])) fill_rules = {'newVisits': 0, 'pageviews': 0, 'isVideoAd': False, 'isTrueDirect': False} data_fillna = data_dropna.fillna(fill_rules) print(data_fillna.isnull().any().sum()) ''' newVisits float64 pageviews float64 isVideoAd object isTrueDirect object dtype: object newVisits pageviews isVideoAd isTrueDirect 0 1.0 11.0 NaN NaN 1 NaN 9.0 NaN NaN 2 NaN 11.0 NaN True 3 NaN 10.0 NaN NaN 4 NaN 6.0 NaN True ''' # 拆分数值特征和字符串特征 str_or_num = (data_fillna.dtypes=='object') str_cols = [str_or_num.index[ind] for ind, na_result in enumerate(str_or_num) if na_result == True] string_data = data_fillna[str_cols] num_data = data_fillna[[i for i in str_or_num.index if i not in str_cols]] # 分类特征转换为数值型索引 model_oe = OrdinalEncoder() string_data_con = model_oe.fit_transform(string_data) string_data_pd = pd.DataFrame(string_data_con,columns=string_data.columns) # 合并原数值型特征和onehotencode后的特征 feature_merge = pd.concat((num_data,string_data_pd),axis=1) # 异常点检测 model_isof = IsolationForest(n_estimators=20, n_jobs=1) outlier_label = model_isof.fit_predict(feature_merge) # 异常结果汇总 outlier_pd = pd.DataFrame(outlier_label,columns=['outlier_label']) data_merge = pd.concat((data_fillna,outlier_pd),axis=1) outlier_count = data_merge.groupby(['outlier_label'])['visitNumber'].count() print('outliers: {0}/{1}'.format(outlier_count.iloc[0], data_merge.shape[0])) # 输出异常的结果数量 #outliers: 1050/10492 # 统计每个渠道的异常情况 def cal_sample(df): data_count = df.groupby(['source'],as_index=False)['outlier_label'].count() return data_count.sort_values(['outlier_label'],ascending=False) # 取出异常样本 outlier_source = data_merge[data_merge['outlier_label']==-1] outlier_source_sort = cal_sample(outlier_source) # 取出正常样本 normal_source = data_merge[data_merge['outlier_label']==1] normal_source_sort = cal_sample(normal_source) # 合并总样本 source_merge = pd.merge(outlier_source_sort,normal_source_sort,on='source',how='outer') source_merge = source_merge.rename(index=str, columns={'outlier_label_x':'outlier_count','outlier_label_y':'normal_count'}) source_merge=source_merge.fillna(0) # 计算异常比例 source_merge['total_count'] = source_merge['outlier_count']+source_merge['normal_count'] source_merge['outlier_rate'] = source_merge['outlier_count']/(source_merge['total_count']) print(source_merge.sort_values(['total_count'],ascending=False).head()) ''' source outlier_count normal_count total_count outlier_rate 0 google 455.0 4025.0 4480.0 0.101562 1 (direct) 174.0 2834.0 3008.0 0.057846 5 webgains 32.0 601.0 633.0 0.050553 4 shareasale 41.0 438.0 479.0 0.085595 2 linkshare 67.0 354.0 421.0 0.159145 ''' # 异常点图形展示 plt.style.use('ggplot') # 使用ggplot样式库 fig = plt.figure(figsize=(10, 8)) # 创建画布对象 # 画图 ax = fig.add_subplot(111, projection='3d') ax.scatter(source_merge['outlier_count'], source_merge['total_count'], source_merge['outlier_rate'], s=100, edgecolors='k', c='r', marker='o',alpha=0.5) ax.set_xlabel('outlier_count') ax.set_ylabel('total_count') ax.set_zlabel('outlier_rate') plt.title('outlier point distribution') # 设置图像标题
-
非结构化数据的分析与挖掘
- 案例1 词频统计
# 导入库
import re # 正则表达式库
import collections # 词频统计库
import numpy as np # numpy库
import jieba # 结巴分词
import wordcloud # 词云展示库
from PIL import Image # 图像处理库
import matplotlib.pyplot as plt # 图像展示库
# 读取文本文件
with open('article1.txt') as fn:
string_data = fn.read() # 使用read方法读取整段文本
# 文本预处理
pattern = re.compile(u'\t|\n|\.|-|一|:|;|\)|\(|\?|"') # 建立正则表达式匹配模式
string_data = re.sub(pattern, '', string_data) # 将符合模式的字符串替换掉
# 文本分词
seg_list_exact = jieba.cut(string_data, cut_all=False) # 精确模式分词[默认模式]
remove_words = ['的', ',', '和', '是', '随着', '对于', ' ', '对', '等', '能', '都', '。', '、', '中', '与', '在', '其', '了', '可以', '进行', '有', '更', '需要', '提供', '多', '能力', '通过', '会', '不同', '一个', '这个', '我们', '将', '并', '同时', '看', '如果', '但', '到', '非常', '—', '如何', '包括', '这'] # 自定义去除词库
# remove_words = [] #空去除词列表,用于跟关键字提取做效果对比
object_list = [i for i in seg_list_exact if i not in remove_words] # 将不在去除词列表中的词添加到列表中
# 词频统计
word_counts = collections.Counter(object_list) # 对分词做词频统计
word_counts_top5 = word_counts.most_common(5) # 获取前10个频率最高的词
for w, c in word_counts_top5: # 分别读出每条词和出现从次数
print(w, c) # 打印输出
# 词频展示
mask = np.array(Image.open('wordcloud.jpg')) # 定义词频背景
wc = wordcloud.WordCloud(
font_path='C:/Windows/Fonts/simhei.ttf', # 设置字体格式,不设置将无法显示中文
mask=mask, # 设置背景图
max_words=200, # 设置最大显示的词数
max_font_size=100, # 设置字体最大值
)
wc.generate_from_frequencies(word_counts) # 从字典生成词云
image_colors = wordcloud.ImageColorGenerator(mask) # 从背景图建立颜色方案
wc.recolor(color_func=image_colors) # 将词云颜色设置为背景图方案
plt.imshow(wc) # 显示词云
plt.axis('off') # 关闭坐标轴
-
案例2 词性标注
# 导入库 import jieba.posseg as pseg import pandas as pd with open('article1.txt') as fn: string_data = fn.read() # 使用read方法读取整段文本 # 分词+词性标注 words = pseg.cut(string_data) # 分词 words_pd = pd.DataFrame(words, columns=['word', 'type']) # 创建结果数据框 print(words_pd.head(4)) # 展示结果前4条 ''' word type 0 Adobe eng 1 x 2 Analytics eng 3 和 c ''' # 词性分类汇总-两列分类 words_gb = words_pd.groupby(['type', 'word'])['word'].count() print(words_gb.head(4)) ''' type word a 不同 14 不足 2 不通 1 严谨 2 Name: word, dtype: int64 ''' # 词性分类汇总-单列分类 words_gb2 = words_pd.groupby('type').count() words_gb2 = words_gb2.sort_values(by='word', ascending=False) print(words_gb2.head(4)) ''' word type x 994 n 981 v 834 eng 295 ''' # 选择特定类型词语做展示 words_pd_index = words_pd['type'].isin(['n', 'eng']) words_pd_select = words_pd[words_pd_index] print(words_pd_select.head(4)) ''' word type 0 Adobe eng 2 Analytics eng 4 Webtrekk eng 9 领域 n ''' #导入库 import jieba.analyse # 导入关键字提取库 import pandas as pd # 导入pandas # 读取文本数据 with open('article1.txt') as fn: string_data = fn.read() # 使用read方法读取整段文本 # 关键字提取 tags_pairs = jieba.analyse.extract_tags(string_data, topK=5, withWeight=True, allowPOS=['ns', 'n', 'vn', 'v', 'nr'], withFlag=True) # 提取关键字标签 tags_list = [(i[0].word, i[0].flag, i[1]) for i in tags_pairs] # tags_pd = pd.DataFrame(tags_list, columns=['word', 'flag', 'weight']) # 创建数据框 print(tags_pd) # 打印数据框 ''' word flag weight 0 数据 n 0.313395 1 报表 n 0.163367 2 功能 n 0.150263 3 分析 vn 0.134857 4 用户 n 0.126633 '''
dobe eng
1 x
2 Analytics eng
3 和 c
‘’’
词性分类汇总-两列分类
words_gb = words_pd.groupby([‘type’, ‘word’])[‘word’].count()
print(words_gb.head(4))
‘’’
type word
a 不同 14
不足 2
不通 1
严谨 2
Name: word, dtype: int64
‘’’
词性分类汇总-单列分类
words_gb2 = words_pd.groupby(‘type’).count()
words_gb2 = words_gb2.sort_values(by=‘word’, ascending=False)
print(words_gb2.head(4))
‘’’
word
type
x 994
n 981
v 834
eng 295
‘’’
选择特定类型词语做展示
words_pd_index = words_pd[‘type’].isin([‘n’, ‘eng’])
words_pd_select = words_pd[words_pd_index]
print(words_pd_select.head(4))
‘’’
word type
0 Adobe eng
2 Analytics eng
4 Webtrekk eng
9 领域 n
‘’’
#导入库
import jieba.analyse # 导入关键字提取库
import pandas as pd # 导入pandas
读取文本数据
with open(‘article1.txt’) as fn:
string_data = fn.read() # 使用read方法读取整段文本
关键字提取
tags_pairs = jieba.analyse.extract_tags(string_data, topK=5, withWeight=True, allowPOS=[‘ns’, ‘n’, ‘vn’, ‘v’, ‘nr’], withFlag=True) # 提取关键字标签
tags_list = [(i[0].word, i[0].flag, i[1]) for i in tags_pairs] #
tags_pd = pd.DataFrame(tags_list, columns=[‘word’, ‘flag’, ‘weight’]) # 创建数据框
print(tags_pd) # 打印数据框
‘’’
word flag weight
0 数据 n 0.313395
1 报表 n 0.163367
2 功能 n 0.150263
3 分析 vn 0.134857
4 用户 n 0.126633
‘’’