Pandas高级数据分析快速入门之一——Python开发环境篇
Pandas高级数据分析快速入门之二——基础篇
Pandas高级数据分析快速入门之三——数据挖掘与统计分析篇
Pandas高级数据分析快速入门之四——数据可视化篇
Pandas高级数据分析快速入门之五——机器学习特征工程篇
Pandas高级数据分析快速入门之六——机器学习预测分析篇

0. Pandas高级数据分析使用机器学习概述

需求 解决方案 技术方案
时序趋势 斜率 线性回归算斜率,Scipy.stats.linregress
正常状态 聚类数据密度,最多的均值 聚类数据密度,SKlearn DBScan
数据相关性 相关性分析 相关系数,Pearson相关系数
预测两种状态 聚类分析 聚类,SKlearn KMean
数据可比性 归一化、标准化 数据标准化,sklearn StandardScaler

1. 线性回归计算斜率和方差

在Python科学计算包Scipy的统计模块stats 中,有 linregress 函数可以做一元线性回归,返回斜率、截距、相关系数、p值和标准误差。

交易间隔天数趋势回归斜率,左侧为典型流失情况, K ∆ t = 2.872 K_{∆t}=2.872 Kt=2.872;右侧为不流失正常情况, K ∆ t = − 2.272 K_{∆t}=-2.272 Kt=2.272
在这里插入图片描述
计算斜率和方差

scipy.stats.linregress(x, y=None)

参数:

  • 输入数据x,y,类数组
    两组测量值。两个数组的长度应该相同。如果只给出了x(y=None),那么它必须是一个二维数组,其中一个维度的长度为2。然后通过沿长度为2的维度拆分数组来找到两组测量值。

返回值:

  • 斜率、截距、相关系数、p值和标准误差。

本文涉及到的交易数据,参照上篇博文[1]描述获取数据集及其DataFrame,此处略。

from scipy import stats

def stats_linear_regression(df):
    user_df = df.loc[df['carduser_id']== 2085603 ].reset_index(drop=True)
       
    Days = user_df['days'].values
    Days = Days[1:]
    k = []
    for i in range(len(Days)):
        k.append(i)
    #Days = Days.reshape(-1,1)
    x = np.array(k)
    y = Days
    # 科学计算包中统计方法,用于计算散点回归线趋势的斜率、截距
    slope, intercept, r_value, p_value, std_err = stats.linregress(x, y) 
    print('slope is ' + str(slope))
    
    # 画图
    plt.rcParams['figure.figsize']= 10,5 #设置图例尺寸
    plt.rcParams['font.sans-serif']=['SimHei'] #设置为中文黑体,如果设置楷体则为 KaiTi
    plt.rcParams['axes.unicode_minus']=False

    plt.scatter(x, y, color='b',label='间隔时间')
    plt.plot(x, slope*x + intercept, color='r',label='趋势回归线')
    plt.legend()      #绘制图例,右上角标识图
    plt.show()   

stats_linear_regression(trade_df)
slope is -0.11791958041958041

在这里插入图片描述

2. 数据密度计算正常状态/周期

基于聚类——数据密度(DBSCAN)提取典型(正常状态)特征,DBSCAN是基于一组邻域来描述样本集密度的空间聚类算法,将具有足够密度的区域划分为簇,参数 ( ϵ , M i n P t s ) (ϵ,MinPts) (ϵ,MinPts)用来描述邻域的样本分布紧密程度。其中, ϵ ϵ ϵ描述了某一样本的邻域距离阈值, M i n P t s MinPts MinPts描述了某一样本的距离为ϵ的邻域中样本个数的阈值。

通过DBSCan聚类分析各个客户交易行为规律,设 ∆ t ∆t t x x x,使用交易间隔天数的密度分簇,寻找最大的簇为“平常交易间隔天数 μ t μ_t μt”,与交易间隔天数平均值、中位数、众数相比,更接近实际情况。
例如图所示交易序列,中位数为15,均值为19.5,聚类最大簇的平均间隔时间μ_t为12天。

sklearn.cluster.DBSCAN参数

sklearn.cluster.DBSCAN(eps=0.5, *, min_samples=5, metric=‘euclidean’, metric_params=None, algorithm=‘auto’, leaf_size=30, p=None, n_jobs=None)

参数:

  • eps:两个样本之间的最大距离,其中一个样本被视为在另一个样本的邻域中。这不是簇内点距离的最大界限。这是为数据集和距离函数选择的最重要的DBSCAN参数。
  • min_samples:最小采样点,默认值=5
    将一个点视为核心点的邻域中的样本数(或总权重)。
  • metric:或可调用,默认值为“欧几里德”。
    计算要素阵列中实例之间的距离时使用的度量。如果metric是字符串或可调用,则它必须是sklearn.metrics.pairwise_distance为其metric参数所允许的选项之一。若度量是“预计算”的,则假定X是距离矩阵,且必须是平方。X可以是术语表,在这种情况下,只有“非零”元素可以被视为DBSCAN的邻居。
  • leaf_size,默认值=30。
    传递给BallTree或cKDTree的叶大小。这可能会影响构造和查询的速度,以及存储树所需的内存。最佳值取决于问题的性质。
  • n_jobs,整形数。 指定计算所用的进程数。内部原理是同时进行n_init指定次数的计算。
    (1)若值为 -1,则用所有的CPU进行运算。若值为1,则不进行并行运算,这样的话方便调试。
    (2)若值小于-1,则用到的CPU数为(n_cpus + 1 + n_jobs)。因此如果 n_jobs值为-2,则用到的CPU数为总CPU数减1。

属性:

  • labels_:给fit()的数据集中每个点的cluster label。噪声样本的标签为-1。
from sklearn.cluster import DBSCAN
from numpy import unique
import matplotlib.pyplot as plt

# 数据密度分析
def dbcsan_analysis(df): 
    user_df = df.loc[df['carduser_id']== 2085728 ].reset_index(drop=True)
       
    Days = user_df['days'].values
    Days = Days[1:]
    k = []
    for i in range(len(Days)):
        k.append(i)

    Days = Days.reshape(-1,1)
    dbs = DBSCAN(eps = 3, min_samples = 5).fit(Days)
    labels = dbs.labels_ 

    # 检索唯一群集
    clusters = unique(labels)
    k = np.array(k)
    k = k.reshape(-1)
    Days = Days.reshape(-1)
    
    plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签 KaiTi
    plt.rcParams['axes.unicode_minus']=False

    scatter = plt.scatter(k, Days, c=labels ,cmap='viridis') #'inferno')
    plt.show()  
    
    sub_df = user_df.drop(index=[0]).reset_index(drop=True) # 删除第一行,因为第一行的时间间隔不合理,或者不存在
    Days = sub_df[['days']].copy() # 间隔时间,建立副本处理
    Days['lables'] = labels
    Days = Days.loc[Days['lables']!=-1].reset_index(drop=True)

    count_group = Days[['lables','days']].groupby(by=['lables'],as_index=False).count()
    maxcount= count_group.sort_values(by=['days'], ascending = True).tail(1)[['lables']].values[0][0]
    
    count_mean = Days[['lables','days']].groupby(by=['lables'],as_index=False).mean()
    count_mean['days']= count_mean['days'].round(0)
    DBSan_mean = count_mean[['days']].loc[count_mean['lables']==maxcount].values[0][0]
    mean = Days[['days']].mean()
    
    median = Days[['days']].median()
    
    print(DBSan_mean)
    print(mean)
    print(median)
    
dbcsan_analysis(trade_df)

在这里插入图片描述

14.0
days    17.673469
days    15.0

3. 相关分析计算特征间关系

皮尔森相关系数 (Pearson Correlation) 是一种最简单的,能帮助理解特征和响应变量之间关系的方法,该方法衡量的是变量之间的线性相关性,结果的取值区间为 [ − 1 , 1 ] [ − 1 , 1 ] [11],-1表示完全的负相关,+1表示完全的正相关,0表示没有线性相关。

ρ X , Y = c o v ( X , Y ) σ X σ Y \rho_{X,Y}=\frac{cov(X,Y)}{\sigma _{X}\sigma_{Y}} ρX,Y=σXσYcov(X,Y)

ρ X , Y = ∑ i = 1 n ( X i − X ‾ ) ( Y i − Y ‾ ) ∑ i = 1 n ( X − X ‾ ) 2 ∑ i = 1 n ( Y − Y ‾ ) 2 \rho_{X,Y}=\frac{\sum_{i=1}^{n}(X_{i}-\overline{X})(Y_{i}-\overline{Y})}{\sqrt{\sum_{i=1}^{n}(X-\overline{X})^{2}}\sqrt{\sum_{i=1}^{n}(Y-\overline{Y})^{2}}} ρX,Y=i=1n(XX)2 i=1n(YY)2 i=1n(XiX)(YiY)

DataFrame.corr(method=‘pearson’, min_periods=1)

参数说明:

method:可选值为{‘pearson’, ‘kendall’, ‘spearman’}

  • pearson:Pearson相关系数来衡量两个数据集合是否在一条线上面,即针对线性数据的相关系数计算,针对非线性数据便会有误差。
  • kendall:用于反映分类变量相关性的指标,即针对无序序列的相关系数,非正太分布的数据
  • spearman:非线性的,非正太分布的数据的相关系数

min_periods:样本最少的数据量

返回值:各类型之间的相关系数DataFrame矩阵表格。

def pearson_corr(df):
    user_df = df.loc[df['carduser_id']== 2085728 ].reset_index(drop=True)
    relat = user_df[['volumn','amount']]
    pearson = relat.corr(method='pearson',min_periods=1)
    pv = round((pearson['amount'].values)[0],4)    
    
    return pv

pv = pearson_corr(trade_df)
print(pv)
0.9489

4. 归一化、标准化

现实的数据一般都是有单位的,比如常用身高的单位有米、厘米,这些情况会影响到数据分析的结果,这个无量纲化并不是说统一量纲为米,而是说,无论是米还是厘米,最后都会变成1,也就是没有了单位。无量纲化使不同规格的数据转换到同一规格。常见的无量纲化方法有标准化和归一化。

标准化(Z-Score)

x ′ = x i − μ σ x' = \frac{x_{i}- \mu }{\sigma} x=σxiμ
其中:

  • x ′ x' x—新值
  • x i x_{i} xi—输入值(原始值)
  • μ \mu μ σ \sigma σ表示 X i X_{i} Xi均值和标准差。

最大、最小值归一化(缩放)

x ′ = x i − x m i n x m a x − x m i n x'=\frac{x_{i}-x_{min}}{x_{max}-x_{min}} x=xmaxxminxixmin

其中:

  • x ′ x' x—输出新值,范围为 [ 0 , 1 ] [0,1] [0,1]
  • x i x_{i} xi—输入值(原始值)
  • x m i n x_{min} xmin—输入最小值
  • x m a x x_{max} xmax—输入最大值
from sklearn.preprocessing import StandardScaler
#特征归一化
def _feature_StandardScaler(data,normalization=True):       
    #数据归一化处理
    if normalization:
        scaler = StandardScaler()
        columns = data.columns
        indexs_train = data.index
        data = pd.DataFrame(scaler.fit_transform(data),index = indexs_train, columns = columns)

    return data
#原数据记录中,有日期等,不能做归一化,只选数值型数据
data = _feature_StandardScaler(df[['balance','recharge','volumn','all_oils','all_goods']])
print(data)
        balance  recharge    volumn  all_oils  all_goods
0     -0.529351 -0.393336 -1.346787  1.360023  -1.875326
1     -0.744385 -0.393336 -0.163501  0.150542   0.073976
2     -0.989514 -0.393336  0.047515 -0.018725   0.073976
3     -0.946507  0.307995  0.648507 -0.853328   0.073976
4     -0.989514  0.000515 -0.026894  0.029593  -0.393856
...         ...       ...       ...       ...        ...

5. 聚类——KMean

K-Means算法原理
对于给定的样本集,按照样本之间的距离大小,将样本集划分为K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。

该算法其采用聚类误差平方和函数 E E E作为聚类准则函数:
E = ∑ i = 1 k ∑ j = 1 n i ‖ x i j - m i ‖ 2 E = ∑_{i=1}^k∑_{j=1}^{n_i}‖x_{ij} - m_{i}‖^2 E=i=1kj=1nixijmi2
其中, n i n_{i} ni表示第 i i i 簇的样本个数;
x i j x_{ij} xij表示第 i i i 簇第 j j j 个样本;
m i m_i mi表示第 i i i 簇的聚类中心或质心。

m i = 1 N i ∑ j = 1 N i x i j m_i = \frac{1}{N_i}∑_{j=1}^{N_i}x_{ij} mi=Ni1j=1Nixij

sklearn.cluster.KMeans 参数介绍

sklearn.cluster.KMeans(
    n_clusters=8,
    init='k-means++', 
    n_init=10, 
    max_iter=300, 
    tol=0.0001, 
    precompute_distances='auto', 
    verbose=0, 
    random_state=None, 
    copy_x=True, 
    n_jobs=1, 
    algorithm='auto'
    )

参数:

  • n_clusters:整形,缺省值=8 【生成的聚类数,即产生的质心(centroids)数。】
  • max_iter:整形,缺省值=300,执行一次k-means算法所进行的最大迭代数。
  • n_init:整形,缺省值=10,用不同的质心初始化值运行算法的次数,最终解是在inertia意义下选出的最优结果。
  • init:有三个可选值:’k-means++’, ‘random’,或者传递一个ndarray向量。
    此参数指定初始化方法,默认值为 ‘k-means++’。
    (1)‘k-means++’ 用一种特殊的方法选定初始质心从而能加速迭代过程的收敛
    (2)‘random’ 随机从训练数据中选取初始质心。
    (3)如果传递的是一个ndarray,则应该形如 (n_clusters, n_features) 并给出初始质心。
  • precompute_distances:三个可选值,‘auto’,True 或者 False。
    预计算距离,计算速度更快但占用更多内存。
    (1)‘auto’:如果 样本数乘以聚类数大于 12million 的话则不预计算距离。
    (2)True:总是预先计算距离。
    (3)False:永远不预先计算距离。
  • tol:float形,默认值= 1e-4 与inertia结合来确定收敛条件。
  • n_jobs:整形数。 指定计算所用的进程数。内部原理是同时进行n_init指定次数的计算。
    (1)若值为 -1,则用所有的CPU进行运算。若值为1,则不进行并行运算,这样的话方便调试。
    (2)若值小于-1,则用到的CPU数为(n_cpus + 1 + n_jobs)。因此如果 n_jobs值为-2,则用到的CPU数为总CPU数减1。
  • random_state:整形或 numpy.RandomState 类型,可选
    用于初始化质心的生成器(generator)。如果值为一个整数,则确定一个seed。此参数默认值为numpy的随机数生成器。
  • copy_x:布尔型,默认值=True
    当我们precomputing distances时,将数据中心化会得到更准确的结果。如果把此参数值设为True,则原始数据不会被改变。如果是False,则会直接在原始数据
    上做修改并在函数返回值时将其还原。但是在计算过程中由于有对数据均值的加减运算,所以数据返回后,原始数据和计算前可能会有细小差别。

属性:

  • cluster_centers_:向量,[n_clusters, n_features] (聚类中心的坐标)
  • Labels_: 每个点的分类
  • inertia_:float形,每个点到其簇的质心的距离之和。

这个k-means运用了 Lioyd’s 算法,平均计算复杂度是 O(knT),其中n是样本量,T是迭代次数。
计算复杂读在最坏的情况下为 O ( n ( k + 2 p ) ) O(n^{(\frac{k+2}{p}))} O(n(pk+2)),其中n是样本量,p是特征个数。
在实践中,k-means算法时非常快的,属于可实践的算法中最快的那一类。但是它的解只是由特定初始值所产生的局部解。所以为了让结果更准确真实,在实践中要用不同的初始值重复几次才可以。

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import pandas as pd
import numpy as np
Input_file = 'card0705_clustering.csv'
marks_name = 'marks'
params_name = ['carduser_id','latestday','occurtime','org_rate','balance']

df = pd.read_csv(Input_file) 
#print(df)
# KMean聚类
def KMean_analysis(df,cols_names,marks_name,params_name):
    Flag = list(df[marks_name])
    cols = cols_names.copy()
    for id_name in params_name:
        cols.remove(id_name)
    cols.remove(marks_name)
    dd=df[cols]     
    samples=dd.values

    #标准化
    scaler=StandardScaler()

    kmeans=KMeans(n_clusters=2,random_state=1,max_iter=3000)
    pipeline=make_pipeline(scaler,kmeans)
    pipeline.fit(samples) #训练模型
    labels=pipeline.predict(samples)#预测
    dd=df[cols_names]
    dd['flag'] = labels

    df_cluster=pd.DataFrame({'labels':labels,'Flag':Flag})
    ct=pd.crosstab(df_cluster['labels'],df_cluster['Flag'])
    print('K-Means')
    print(ct)
cols_names = ['carduser_id','latestday','balance','balancerate',
    'IntervalSlope','IntervalStd','latestdays','tradecount','BalanceSlope','BalanceStd',
    'AmountSlope','AmountStd','amountmean','VolumnSlope','VolumnStd','recharge_days',
    'balancemean','goodsmean','volumnmean','sumamount','amountrate','volumn','volumnrate','meandays','maxdaysrate','latestdaysrate','daysnum',
    'tradecountSlope','tradecountStd','monthnum','days','Rechargeslope','RechargeStd',
    'maxvolumn','accsumamount','accamount','accgoods','accvolumn','maxrecharge','meanrecharge','lastrecharge','rechargerate',
    'densitymean','MinIntervalByPrice','marks','occurtime','count','pearson','org_rate']  
KMean_analysis(df,cols_names,marks_name,params_name)
K-Means
Flag         0      1      2
labels                      
0       154123  97324  72259
1        68510  19569   9440

6. 小结

在挖掘交易明细数据的基础上,再通过机器学习方法和技术,可以增强特征,这样,使用简单的机器学习算法预测出较好的结果。

参考:

[1] . 肖永威 . Pandas高级数据分析快速入门之三——数据挖掘与统计分析篇,CSDN博客 ,2021年8月
[2] . 肖永威 . Pandas高级数据分析快速入门之四——数据可视化篇,CSDN博客 ,2021年8月

Logo

一站式 AI 云服务平台

更多推荐