数据分析-数据挖掘
数据挖掘和机器学习
机器学习 — 预测的准 — 需要分割训练集和测试集
- 聚类、分类、 回归
数据挖掘— 特征x和y之间的关系及其影响 一般不分割数据集
- 聚类/分类/回归
- 可选算法:
- 线性回归,逻辑回归,决策树,贝叶斯,xgboost
- 不能用knn,svm,神经网络 没有可解释性
聚类分析
分析方法
优势
- 能够发现未知的重要特征
技术问题
- 均值的问题 kmeans 更新中心点 均值点
- 异常数据会影响均值 要去异常
- 量纲的问题 —要做标准化 — 基于距离的
- 数据量大的问题
- m个样本,n个特征,k个中心点,t次迭代 算法复杂度 O(tkm*n)
- mini-batch-kmeans来解决数据量大的问题
- 结论:MiniBatchKMeans在基本保持了K-Means原有较高类别识别率的前提下,其计算效率的提升非常明显。因此,MiniBatchKMeans是一种能有效应对海量数据,尽量保持聚类准确性并且大幅度降低计算耗时的聚类算法
- 聚类分析:分析聚类簇的中心点的特点
- kmeans的作用:kmenas可以帮我们采样 假如有1亿数据
- 先用minibatchkmeans聚成5w个类 得到5w个中心点
- 拿着5w中心点去做后续的分类和回归任务
客户分群案例
from sklearn.cluster import KMeans
dataset = pd.read_csv('data/customers.csv')
dataset.head()
X = dataset.iloc[:, [3, 4]].values#全部行,第四第五列 Annual Income (k$) 和 Spending Score (1-100)
X.max(axis=0),X.min(axis=0)
#实例化
km=KMeans(n_clusters=5)
y_label=km.fit_predict(X)
y_label
km.cluster_centers_
import matplotlib.pyplot as plt
plt.scatter(X[y_label==0,0],X[y_label==0,1],color='blue',label='A')
plt.scatter(X[y_label==1,0],X[y_label==1,1],color='red',label='B')
plt.scatter(X[y_label==2,0],X[y_label==2,1],color='green',label='C')
plt.scatter(X[y_label==3,0],X[y_label==3,1],color='cyan',label='D')
plt.scatter(X[y_label==4,0],X[y_label==4,1],color='magenta',label='E')
plt.scatter(km.cluster_centers_[:,0],km.cluster_centers_[:,1],color='black',label='center')
plt.title('Clusters of customers')
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.legend()
plt.show()
km.cluster_centers_
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()
年龄收入分群案例
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
#加载数据
ageinc_df=pd.read_csv('data/ageinc.csv')
ageinc_df.info()
#两列数据,年龄与收入
ageinc_df.describe()
#标准化
ageinc_df[['z_income','z_age']]=(ageinc_df-ageinc_df.mean())/ageinc_df.std()
ageinc_df.head()
import seaborn as sns
sns.scatterplot(x='income',y='age',data=ageinc_df)
#模型 聚3簇
km=KMeans(n_clusters=3)
km.fit(ageinc_df[['z_income','z_age']])
#获取标签
ageinc_df.loc[:,'cluster_3']=km.labels_
ageinc_df.head()
sns.scatterplot(x='age',y='income',hue='cluster_3',data=ageinc_df)
#横轴为年龄,纵轴为收入,分类为用户分群标签
#肘部法决定聚几个簇
wcss = []
for i in range(1, 11): #循环使用不同k测试结果
kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
kmeans.fit(ageinc_df[['z_income','z_age']])
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()
# 分析聚类结果
#简单分析
#由于作了标准化 聚类中心点是标准化后的数据
#按照聚类标签分组 统计每一组原特征的均值
ageinc_df.groupby('cluster_4',as_index=False)[['income','age']].mean()
#分布差异分析
ageinc_df.groupby('cluster_4')[['income','age']].describe()
sns.boxplot(x='cluster_4',y='income',data=ageinc_df)
sns.boxplot(x='cluster_4',y='age',data=ageinc_df)
- 量纲不一致—做标准化
- 肘部法判断最优簇数 k值
- 聚类结果分析
- 简单均值比较
- 按照聚类的标签分组,计算每一组原特征的均值差异
-
ageinc_df.groupby('cluster_4',as_index=False)[['income','age']].mean()
- 分布分析
- 按照聚类标签分组,查看每一组原特征的分布差异
ageinc_df.groupby(‘cluster_4’)[[‘income’,‘age’]].describe()
- 按照聚类标签分组,查看每一组原特征的分布差异
- 最终一般是绘图对比
- 均值比较 — 雷达图
- 分布比较— 箱线图
- 简单均值比较
聚类分析总结
- 数据处理上
- 去异常
- 标准化
- 类别型数据—做onehot
- 级别型数据 —编码 1,2,3
- 模型构建
- k取值 :肘部法、根据业务的需求来
- 结果分析
- 重点分析聚类簇的中心点
- km.cluster_centers_ 输出的标准化后的数据
- 按照聚类标签分组统计均值 得到原数据中心点
- 分析中心点差异和特征分布差异
- 重点分析聚类簇的中心点
回归分析
步骤
- 前提:数据应拿到
- 分析流程:数据概况分析->单变量分析->相关性分析与可视化->回归模型
- 数据概况分析
- 数据行/列数量
- 缺失值分布
- 单变量分析
- 数字值型变量的描述指标(平均值,最大最小值,标准差)
- describe()
- 类别型变量(多少个分类,各自占比)
- value_counts()
- 数字值型变量的描述指标(平均值,最大最小值,标准差)
- 相关性分析与可视化
- x离散y连续 --按类别交叉对比
- 均值比较 — 方差分析
- 做法: 按照x分组,计算每一组的y的均值,观察是否有差异
- 有差异 代表有影响
- 没有差异 代表没有影响
- 柱形图(比均值)和箱线图(比分布)
- x连续y连续— 变量之间的相关性分析
- 皮尔森 斯皮尔曼
- df.corr()
- 散点图/热力图
- x离散y连续 --按类别交叉对比
- 回归分析
- 模型建立
- 模型评估与优化
- 数据概况分析
结果
- revenue=1.75186122local_tv+2037.7933person+4.07672953*online-52678.6888
- 表示local_tv每增加1块钱投入,销售额对应增长1.75
- person每增加一个人,销售额增加2037
- online每增加一块钱投入 销售额增加4.06
- -52678.6888 偏置没有意思
- 结论:适当提高online的投入 减少local_tv的投入,人员结合用工成本进行管控
- 注意问题
- 每次进行微调,收集新的数据,每个月对模型进行更新迭代,
- 要注意是否产生了新的更重要的自变量
- 如果搞了活动,这个因素要考虑
- x的值不能超过训练数据的范围,否则模型会失效
- 模型的局部有效性
- 每次进行微调,收集新的数据,每个月对模型进行更新迭代,
总结
- 变量少到1个自变量,直接画图
- 如果特征有共线性
- 判断共线性:vif方差膨胀系数,相关系数
- 怎么解决:
- 删掉共线性很强的特征
- 岭回归
- 高维:岭回归
- 关注可解释性: 线性回归和多项式回归(多项式扩展+线性回归)
分类分析
- 预测
- 做模型预测准
- 挖掘
- 目标是离散
- 决策树 提取规则 可视化 规则还给到业务部门
用户流失预测案例分析
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
churn=pd.read_csv('data/churn.csv')
churn.info()
#单变量分析
churn.describe()
#离散数据
churn['gender'].value_counts()
churn['Churn'].value_counts()
#相关性分析 目标是离散的
#离散特征和离散y的关系 -- 交叉表分析 卡方检验 看比例是否有差异
pd.crosstab(churn['gender'],churn['Churn'])
churn.groupby('Churn').mean() #实际上是比例
#验证交叉表
pd.crosstab(churn['Churn'],churn['Partner_att'])
#可视化
sns.barplot(x='Churn',y='Contract_Month',data=churn)
sns.countplot(y='Contract_Month',hue='Churn',data=churn)
#数据清洗
#需要把churn和gender转变为数字型变量,使用get_dummies
churn=pd.get_dummies(churn)
#删掉两列 Churn_No gender_Male
churn=churn.drop(['Churn_No','gender_Male'],axis=1)
#变量大小写不规则,统一变成小写
churn.columns=churn.columns.str.lower()
#修改列名
churn=churn.rename(columns={'churn_yes':'flag'})
import numpy as np
#皮尔森相关性
corr=churn.corr()[['flag']].rename(columns={'flag':'r'})
#计算绝对值
corr.loc[:,'abs_r']=corr['r'].apply(np.fabs)
#按照绝对值排序
corr=corr.sort_values('abs_r',ascending=False)
corr
#模型训练
#利用选择的特征构建模型
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
#拿到x和y
y=churn['flag']
x=churn[['contract_month','internet_other','paymentelectronic','totalcharges','monthlycharges']]
#分割数据集
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3,random_state=100)
#模型训练
model=LogisticRegression()
model.fit(x_train,y_train)
#结果分析 y=2.01264249*contract_month+1.05076404*internet_other+0.64248053*paymentelectronic-3.21842661
# p=sigmoid(y) y>0:正例 y<0:负例
model.coef_
model.intercept_
#评估 准确率
model.score(x_test,y_test)
#绘制roc
from sklearn.metrics import roc_curve,auc
#提取正例的概率
y_score=model.predict_proba(x_test)[:,1] #预测为1的概率
fpr,tpr,threshold=roc_curve(y_test,y_score)
#绘制曲线
plt.plot(fpr,tpr)
- 提取数据
- 导入数据
- 数据清洗
- 探索性分析
- 单变量分析
- 特征分析、 目标分析
- 多变量分析
- 特征跟目标之间的相关性
- x离散y离散
- 交叉表— 看比例是否差异
- x连续y离散或者x离散y连续
- 均值比较或者方差分析
- 柱状图 箱线图
- 均值比较或者方差分析
- x连续y连续
- 相关性分析 皮尔森 斯皮尔曼
- 热力图
- x离散y离散
- 特征和特征之间的相关性
- 共线性
- 特征跟目标之间的相关性
- 单变量分析
- 特征筛选
- 模型构建和优化
- 评估和输出模型
附图:
1.交叉表
2.均值比较方差分析
3.热力图
分类分析方法总结
- 分类分析作用
- 提取规则— 数据挖掘
- 提取变量— 特征选择
- 缺失值填充— 拿没缺失的训练,对缺失的进行预测
- 聚类和分类比较
- 聚类无监督 分类有监督
- 聚类没有y 分类有y
- 聚类只能做探索性分析(模糊分析),分类可以做预测等精确分析
- 结果解读
- 聚类:比较各个簇的均值点的差异
- 分类不需要解释 是/不是
- 评价
- 聚类没有准确率
- 分类有准确率,auc等指标
- 常用逻辑回归和决策树 xgboost 随机森林
关联分析 -apirior - fp-growth
- 作用:挖掘频繁项集
- 相关概念
- 支持度— 项集出现的次数/总次数
- 置信度— 对规则而言
- {豆奶} >>>{莴苣}的置信度 = 支持度({豆奶, 莴苣})/支持度(
{豆奶}
),即3/4 - {莴苣}>>>{豆奶}的置信度 = 支持度({豆奶, 莴苣})/支持度({莴苣}`),即3/4
- 两者一般不相等
- {豆奶} >>>{莴苣}的置信度 = 支持度({豆奶, 莴苣})/支持度(
- 频繁规则
- 最小支持度
- 最小置信度
- 同时满足最小支持度和最小置信度的规则就是频繁规则(强关联规则)
- 有效规则
- 提升度: 应用规则结果/不应用规则的结果
- =1 规则没有任何影响
- 小于1 规则起到正的作用 有效规则
- 大于1 规则是负作用 无效规则
- 提升度: 应用规则结果/不应用规则的结果
- apirior算法原理
- 首先搜索一项集—>过滤一项集 —>得到频繁一项集
- 有频繁一项集组合候选二项集—>重复动作
- 知道不能再组合更高的频繁项集,程序终止
商品交叉销售分析(略)
# 导入库
import pandas as pd
import apriori
#加载数据文件
data = pd.read_csv('data/order_table.csv')
data.head()
order_ids=data['order_id'].unique()
records=[ data[data['order_id']==id]['product_name'].tolist() for id in order_ids]
records=[d['product_name'].tolist() for key,d in data.groupby('order_id')]
#统计强关联规则
minS=0.05#最小支持度
minC=0.2#最小置信度
L,suppdata=apriori.apriori(records,minSupport=minS)
#筛选满足最小置信度的规则
rules=apriori.generateRules(records,L,suppdata,minConf=minC)
rules
# 关联结果报表评估
model_summary = 'data record: {1} \nassociation rules count: {0}' # 展示数据集记录数和满足阀值定义的规则数量
print(model_summary.format(len(rules), len(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)
异常检测分析
- 常用算法
- one-class SVM 一分类svm
- svm天然抵抗不平衡
- isolation forest 孤立森林
- GMM 高斯混合模型
- 底层思想是完整版EM kmeans是阉割版的EM
- one-class SVM 一分类svm
- 重点:孤立森林
- 什么是异常?
- 离散: A:10000 B:1000 C:10
- 连续: 过大或者过小是异常
- 原理
孤立森林算法通过对样本点的孤立来检测异常值- 该算法利用一种名为孤立树iTree的二叉搜索树结构来孤立样本
- 异常值的数量较少且与大部分样本的特征不同
- 异常值会被更早的孤立出来,也即异常值会距离的根节点更近,而正常值则会距离根节点有更远的距离
- 特点:
- 离散和连续都可以处理
- 不需要调参
- 对高维数据也可以处理
- 什么是异常?
连续数据
- 更大的概率将异常样本尽快分开,离根节点近
离散 - 少类的样本很快就不能分了,离根节点近
孤立森林案例
# 导入库
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('data/outlier.txt',sep=',') # 读取数据
raw_data.shape
# 数据清洗
#取出全nan的列
# raw_data.isnull().all(axis=0)
data_dropna=raw_data.dropna(axis=1,how='all')
#删掉 clientId
data_dropna=data_dropna.drop(['clientId'],axis=1)
data_dropna.shape
#找到有空值的列
#判断有没有nan
cols_na=data_dropna.isnull().any(0)
#提取有nan的
cols_na=cols_na[cols_na]
cols_na.index
#查看空值列的类型
data_dropna[cols_na.index].dtypes
#填充空值
fill_rules = {'newVisits': 0, 'pageviews': 0, 'isVideoAd': False, 'isTrueDirect': False}
data_fillna=data_dropna.fillna(fill_rules)
data_fillna.info()
# -----------------------特征工程
# 拆分数值特征和字符串特征
str_or_num = (data_fillna.dtypes=='object')
#拆分数值和字符串
str_cols=str_or_num[str_or_num].index
num_cols=str_or_num[str_or_num==False].index
str_cols,num_cols
#挑出字符串数据和数值数据
str_data=data_fillna[str_cols]
num_data=data_fillna[num_cols]
#对字符串特征进行编码
ordinal=OrdinalEncoder()
temp=ordinal.fit_transform(str_data)#经过sklearn处理后都成了ndarray
string_data=pd.DataFrame(temp,columns=str_cols)
string_data.head()
#数据合并
data_merge=pd.concat([num_data,string_data],axis=1)
data_merge.shape
#模型训练
data_merge.index,data_fillna.index
#实例化孤立森林
forest=IsolationForest(n_estimators=50,n_jobs=-1)
data_fillna.loc[:,'outlier_label']=forest.fit_predict(data_merge)#预测标签直接保存到原数据中
outlier_count=data_fillna['outlier_label'].value_counts()
outlier_count
print('outliers: {0}/{1}'.format(outlier_count[-1], outlier_count.sum())) # 输出异常的结果数量
# -----------统计结果
#分析不同渠道source 的正常样本和异常样本数量
result=pd.pivot_table(data_fillna,
index='source',
columns='outlier_label',
values='keyword',
aggfunc='count',
fill_value=0,
margins=True)
#修改列名
result.columns=['outlier_count','normal_count','total']
result.head()
#计算异常比例
result.loc[:,'outlier_rate']=result['outlier_count']/result['total']
result.head()
# --------可视化
# 异常点图形展示
plt.style.use('ggplot') # 使用ggplot样式库
fig = plt.figure(figsize=(10, 8)) # 创建画布对象
# 画图
ax = fig.add_subplot(111, projection='3d')
ax.scatter(result['outlier_count'], result['total'], result['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') # 设置图像标题
- 获取数据 业务方提供
- 明确需求: 缩小异常样本的搜索范围
- 导入数据
- 数据清洗
- 删除全nan的列
- 删除id列
- 填充空值
- 特征工程
- 对字符串特征进行ordinalencoder编码 变成0,1,2,3,4,5,6…
- 模型训练
-
#实例化孤立森林 forest=IsolationForest(n_estimators=50,n_jobs=-1) data_fillna.loc[:,'outlier_label']=forest.fit_predict(data_merge)#预测标签直接保存到原数据中
-
- 统计分析
- 分析各渠道的异常样本比例
- 异常比例较高的渠道需要重点关注
- 可视化
非结构化数据分析与挖掘-词频/词云图(略)
- 读取文本
- 正则表达式去除特殊符号— 文本清洗
- jieba分词
- jieba.lcut 列表
- jieba.cut 生成器
- 去除停用词
- Counter计数
- wordcloud词云图展示
词性标注— jieba.posesg
关键词提取— jieba.analyse.extract_tags
# 导入库
import re # 正则表达式库
import collections # 词频统计库
import numpy as np # numpy库
import jieba # 结巴分词
import wordcloud # 词云展示库
from PIL import Image # 图像处理库
import matplotlib.pyplot as plt # 图像展示库
文本清洗
# 读取文本文件
with open('data/article1.txt',encoding='gbk') as fn:
string_data = fn.read() # 使用read方法读取整段文本
# 文本预处理
pattern = re.compile(u'\t|\n|\.|-|:|;|\)|\(|\?|"') # 建立正则表达式匹配模式
string_data = re.sub(pattern, '', string_data) # 将符合模式的字符串替换掉
string_data
#分词
words=jieba.cut(string_data)
words
#去除停用词
remove_words = ['的', ',', '和', '是', '随着', '对于', ' ', '对', '等', '能', '都', '。', '、', '中', '与', '在', '其', '了', '可以', '进行', '有', '更', '需要', '提供', '多', '能力', '通过', '会', '不同', '一个', '这个', '我们', '将', '并', '同时', '看', '如果', '但', '到', '非常', '—', '一','如何', '包括', '这'] # 自定义去除词库
words=[word for word in words if word not in remove_words]
words
#统计词频
word_counts=collections.Counter(words)
word_counts
#展示前10名
word_counts_top10=word_counts.most_common(10)
for w, c in word_counts_top10: # 分别读出每条词和出现从次数
print(w, c) # 打印输出
#词云图显示
# 词频展示
mask = np.array(Image.open('data/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') # 关闭坐标轴 stylecloud
# 词性标注-------------------------------------------------------------
# 导入库
import jieba.posseg as pseg
words=pseg.lcut(string_data)
words
#直接封装
import pandas as pd
words=pd.DataFrame(words,columns=['word','type'])
words.head()
#词性的频率
words['type'].value_counts()
# 关键词提取 textrank谷歌pagerank排名算法
#导入库
import jieba.analyse # 导入关键字提取库
result=jieba.analyse.extract_tags(string_data,topK=5,withWeight=True,allowPOS=['ns', 'n', 'vn', 'v', 'nr'],withFlag=True)
result
tags_list = [(i[0].word, i[0].flag, i[1]) for i in result] #
tags_pd = pd.DataFrame(tags_list, columns=['word', 'flag', 'weight']) # 创建数据框
tags_pd # 打印数据框