简单机器学习入门

113 阅读13分钟

Linear Regression

1.对于初导入的数据处理

1.拿到一堆训练数据,一般会我们需要先将数据打乱,使数据随机排序,然后在进行切分,需要将数据切分成训练集、交叉验证集和测试集,在监督学习中还要切分出属性集和标签集。

2.在给的数据当中要选取0.1、0.2的数据集来作为测试的数据,否则无法保证拟合的效果

1.导入数据

import pandas as pd
# 两种比较常用的读取数据的方法
df = pd.read_csv("path", names=['index','...'])
df = pd.read_fwf("path", names=['index','...'])

2.设置索引,索引数据的排序

''' 
多级索引,inplace=True 覆盖的情况下,
直接使用 df_1 访问.

注意:在 inplace=True 覆盖原数据情况下,运行第 2 或多次,
      就会出现报错的情况,同时代码并没有语法错误,
      原因是原数据被覆盖了。解决方法是:重新运行所有代码,
      如果不是很必要,尽量不要执行覆盖原数据的操作
'''

df_1.set_index(keys=['地区', '年份'], inplace=True)  # 设置多级索引,覆盖原数据
print(df_1.iloc[: , :4].head())  

df_1.reset_index(inplace=True)  # 取消索引
df_1.iloc[: , :4].head()

# 通过索引排列,升序排列、不覆盖原数据、如有缺失值则放在前面
data.sort_index(ascending=True, inplace=False, na_position='first')

''' 通过指定列的值排序 '''

# 先以 "升序" 模式排完 "地区" 这一列,"年份" 这列再以 "地区" 列来排序
df_1.sort_values(by=['地区', '年份'], ascending=[True, False],inplace=False, na_position='first')

3.处理数据&&填充数据

  1. 删除属性(特征)
    如果某一个特征中存在大量的缺失值(缺失量大于总数据量的40%~50%及以上),
    那么我们可以认为这个特征提供的信息量非常有限,这个时候可以选择删除掉这一维特征。

  2. 删除样本
    如果整个数据集中缺失值较少或者缺失值数量对于整个数据集来说可以忽略不计的情况下
    那么可以直接删除含有缺失值的样本记录。

  3. 对于特征的缺失值,可以根据缺失值所对应的那一维特征的统计值来进行填充, 统计值一般泛指平均值、中位数、众数、最大值、最小值等,具体使用哪一种统计值要根据具体问题具体分析

  4. 插值法: 1.多项式插值:

    2.Lagrange插值

    3.预测插值

  5. 具体的一些示例:

    1. 年收入”:商品推荐场景下填充平均值,借贷额度场景下填充最小值;
    2. “行为时间点”:填充众数;
    3. “价格”:商品推荐场景下填充最小值,商品匹配场景下填充平均值;
    4. “人体寿命”:保险费用估计场景下填充最大值,人口估计场景下填充平均值;
    5. “驾龄”:没有填写这一项的用户可能是没有车,为它填充为0较为合理;
    6. ”本科毕业时间”:没有填写这一项的用户可能是没有上大学,为它填充正无穷比较合理;
    7. “婚姻状态”:没有填写这一项的用户可能对自己的隐私比较敏感,应单独设为一个分类,如已婚1、未婚0、未填-1。

6.离群值处理

1.拉依大准则(标准差法) :适用于较多组数据的时候,工作原理:它是先假设一组检测数据只含有随机误差,对其进行计算处理得到标准偏差, 按一定概率确定一个区间,认为凡超过这个区间的误差,就不属于随机误差而是粗大误差, 含有该误差的数据应予以剔除

公式为:

μ=i=1nxin,σ=i=1n(xiμ)2n\mu=\frac{\sum_{i=1}^{n}x_i}{n},\sigma=\sqrt\frac{\sum_{i=1}^{n}(x_i-\mu)^2}{n}

将区间,[μ−3σ,μ+3σ]的值视为正常值范围,在,[μ−3σ,μ+3σ]外的值视为离群值

def std_(df):
    item, N = 'sepal_length', df.shape[0]
    M = np.sum(df[item])/N
    assert (M == np.mean(df[item])), 'mean is error' 
    S = np.sqrt(np.sum((df[item]-M)**2)/N)
    L, R = M-3*S, M+3*S
    return '正常区间值为 [%.4f, %.4f]' % (L, R)

2.绝对值差中位数法,是一种先需计算所有因子与中位数之间的距离总和来检测离群值的方法,适用大样本数据

公式为:

α=i=1n(xixm)2n\alpha=\sqrt{\frac{\sum_{i=1}^{n}(x_i-x_m)^2}{n}}

则正常值范围为,[xmedian−3α,xmedian+3α],在区间,[xmedian−3α,xmedian+3α]外视为离群值

# MAD法
def MAD(df):
    item, N = 'sepal_length', df.shape[0]
    M = np.median(df[item])
    A = np.sqrt(np.sum((df[item]-M)**2)/N)
    L, R = M-3*A, M+3*A
    return '正常区间值为 [%.4f, %.4f]' % (L, R)
# 异常数据的处理
data.replace(to_replace="?",value=np.nan)
# 空值数据的处理
data.dropna(replace=True,axis=)  # axis可以不指定,默认行全删
data.isnull().any()  # 判断是否还有空值

'''数据填充的方法,因为数据前后可能都是缺失的所以就要前后填充一起使用来解决这个问题'''
df.fillna(method='ffill') # 用缺失值的前一个值进行填充
df.fillna(method='bfill') # 用缺失值的后一个值进行填充

''' 平均值填充(所有列填充) ''' df.fillna(value=df.mean())
df['index'].fillna(value=df['index'].mean()) # 对每一列进行相对应的列平均填充                             

'''统一值填充'''
df.fillna(value=data_toinsert)

"""重复值的处理"""
# 查找重复值
df.duplicated(subset=['index'], keep='first')
# 删除重复值
df.drop_duplicates(subset=['index'],keep='first',inplace=False)
# 查找重复索引
df.index.duplicated()

4.数据分组&&合并数据

# '地区作为索引分组','年份'与分组列地区聚合
# 第一种方法
df_1.groupby(by=['地区'], as_index=True).agg({'年份': ['max', 'min', 'median']}).head()
# 第二种方法
df_1.groupby(by=['地区'], as_index=True).年份.agg(['max', 'min', 'median']).head()

''' 指定多列列是聚合列,如:年份、国内生产总值 '''

df_1.groupby(by=['地区'], as_index=True).agg({'年份': 'max', '国内生产总值': 'describe'}).head()

''' 没有指定聚合列,则代表选择所有列 '''
# 返回所有列中的最大值
df_1.groupby(by=['地区'],as_index=True).max().head()

'''合并数据'''
# 这里默认df1为数据源1,df2为数据源2....
contact_df1 = pd.concat(objs=[df1, df2, df3],axis=0)
# 合并数据,以行的维度合并
contact_df2 = pd.merge(left=df1, right=df2, on='index', how='outer')  # 指定值合并

5.打乱数据

#  数据抽样
data = df.sample(n=5,replace=False) # 不放回随机抽样

df=df.sample(frac=1.0)#打乱所有数据
df=df.reset_index(drop=True)#打乱后的数据index也是乱的,用reset_index重新加一列index,drop=True表示丢弃原有index一列

6.切割数据

# 利用隐式索引进行数据的切片
train=df.iloc[:a] # 取数据的前a行为训练集
x_train=train.iloc[:,:b] # 取训练集的前b列为属性集
y_train=train.iloc[:,b:] # 取训练集的最后一列标签集
# 利用显示索引进行切片
y_train = df.loc[:110000 ,['satisfaction']] # 适用于当目标值不是在首位置或者末位置的情况

''' 按条件来选择 

# 筛选出符合条件的列
df_1[df_1['国内生产总值'] > 15678]
df_1.loc[:, (df_1>1).any()]  # 选择任一值大于1的列
df_1.loc[:, (df_1>1).all()]  # 选择所有值大于1的列
df_1.loc[:, df_1.isnull().any()]  # 选择含 NaN值的列
df_1.loc[:, df_1.notnull().all()]  # 选择不含NaN值的列

# 选择指定的列,类似于 df[['某列', '某列']]
df_1.filter(items=['地区', '年份'])  # 选择指定的列
df_1.filter(like='产业', axis=1)  # 选择含有 "产业" 的列

# 筛选出符合条件的指定的列,并对其进行"替换修改"
df_1.loc[df_1['地区'] == '北京', '地区'] = 10  
'''

7.就算某一列的方差标准差相关性

df['index'].var(),df.var() # 探索某一列或全部样本的方差
df['index'].std(),df.std() # 探索某一列或全部样本的标准差
df.cov().iloc[:4, :4] # 探索变量间的协方差
df.corr().iloc[:4, :4] # 探索变量之间的相关性

8.汇总统计

df.sum() # 每一列求和
df['index'].cunsum().head() # 某列逐行累加(可以全部样本每一列都累加)
df.max() , df.min()  # 最大最小值对应
# ------ 找到最大最小值的索引号  --------
df['index'].idxmax(), df['index'].idxmin()
# 中位数,平均数
df.median() , df.mean() 
df.describe().T  # 汇总所有统计信息,转置方便看数据

9.pandas中的应用函数apply

def fun(x):
    x = int(x)
    return x
f = lambda x: x + 'QQ'
data1 = df['index1'].apply(fun)  # 利用这个可以将浮点数全部转化为整形
data2 = df['index2'].apply(f) # 可以将所有的变量后面加上QQ这个后缀, eg: sample: 天津  after: 天津QQ

10.pandas可视化(箱型图..)

'''
1.条形图--探索趋势走势 DataFrame.plot()
2.直方图--探索集中分布情况  DataFrame.hist(bins=size, figsize=(,))
3.箱型图--探索集中分布以及异常值情况
DataFrame.boxplot()
'''
# 1.
df[['index']].plot(color='r')  # 画出指定索引的图像
plt.ylabel('...') # 设置标签
plt.xlabel('...')
# 2.
df[['index']].hist(bins=50,figsize=(12,8))
#3.
df[['index']].boxplot(figsize=(16,8))
df.bosplot(figsize=(16,8)) # 所有数据的箱型图

最小二乘法的代码实现

def standranger(x_arr, y_arr):   # 最小二乘法来获取theat的值
    x_mat = np.mat(x_arr)   # 将特征变量x数据源转为矩阵
    y_mat = np.mat(y_arr)   # 将y值转化为矩阵的形式
    x_is = x_mat.T * x_mat
    if np.linalg.det(x_is) == 0.0:
        print("矩阵是奇异矩阵")
        return 0
    ws = x_is.I * (x_mat.T * y_mat)
    return ws

梯度下降法的代码实现

def cost_function(X,y,theat):   # 代价函数
    inner = np.power((X @ theat - y),2)
    return  np.sum(inner)/(2*len(X))

def grand(X,y, theta):   # 梯度
    inner = 2*X.T(X@theta - y)
    return inner

def gradint_descent(X,y,theat,altha,iters): # 梯度下降法
    costs = []
    for item in range(iters):
        theat = theat-(X.T @ (X @ theat - y))*altha/len(X)
        cost = cost_function(X,y,theat) # 获取损失值可以绘制图像
        costs.append(cost)
    return theat,costs

学习率α的取值问题(较难去获取一个确切的数值)

  • 这得确保每一次的迭代的过程当中,变化率都是稳步下降的,不应有较大的增幅,同时也要确保下降的速率不能太慢,从而影响效率. 当α太大的时候可能会导致代价函数不收敛!
  • choose α ...... 0.001,0.003,0.01,0.03,0.1 ,0.3,1........

损失函数的可视化

def picture_cost(iters,cost):   # 绘制代价函数的曲线
    fig,ax = plt.subplots(figsize=(12,8))
    ax.plot(np.arange(iters),cost)
    ax.set_xlabel("iters")
    ax.set_ylabel("cost")
    ax.set_title("Linner Cost Function")
    plt.show()

预测函数以及rmse方差

预测函数的基础是得有一定的数据集,所以我们要将原始数据打乱,然后去最后面的百分之0.1、0.2的数据来作为测试样本,其它的作为训练的样本

def predcit(x_text,pre_theat):  # 预测函数
    y = x_text @ pre_theat
    return y

def rmse(y_pre, y_text):   # rmse方差去拟合预测的效果
    inner = np.sum(np.power(y_text-y_pre,2))/len(y_text)
    return np.sqrt(inner)    

2.字符数据的处理

  • 对于数据中的字符型数据,如果他们之间是由关联的那么就可以使用标签编码,比如说幼儿,中年,青年,老年人就可以赋值成0,1,2,3
# 标签编码
def LabelEncoding(df, index):
    x,dfc = 'index',df
    key = dfc[x].unique() # 将唯一值作为关键字
    value = [i for i in range(len(key))] # 键值
    Dict = dict(zip(key, value))  # 字典,即键值对
    for i in range(len(key)):
        for j in range(dfc.shape[0]):
            if key[i] == dfc[x][j]:
                dfc[x][j] = Dict[[key[i]]]
    dfc[x] = dfc[x].astype(np.float32)
    return dfc[:5]
  • 而当数据之间是没有关联的时候,几乎是正交的时候,可以采用独热编码,比如水果中的香蕉和苹果,但是如果用标签编码的话会让算法觉得苹果会优于香蕉
  • (1)在独热编码下,特征向量只有某一维取值为1,其余值均为0,因此可以利用向量的稀疏来节省空间
    (2)如果类别型的唯一类别元素较多,可能会造成维度灾难,因此需要利用特征选择来降低维度

​ s[1,0,0] q[0,1,0] p[0,0,1] 下面为独热编码的函数

调用函数 pd.get_dummies(data, prefix=[])

在这里面data为数据源,prefix为你要独热编码的列数据

5.多元数据变量线性回归的时候,可以对数据进行归一化处理

一、min-max归一化

只适合精确的小数据场景,无法对有异常值的数据进行处理

x=xminmaxminx' = \frac{x-min}{max-min}
X=X(mxmi)+miX''=X'(mx-mi)+mi

作用于每一列,max为一列的最大值,min为一列的最小值,X''为最小值

  • 自己实现归一化的数据处理
def MinMaxScaler(house_df):  # 传入数据源 进行归一化
    colums = house_df.columns
    for item in colums:
         house_df[item]=(house_df[item]-               house_df[item].min())/(house_df[item].max()-house_df[item].min())
  • 调用sklearn中的模块进行归一化处理
import sklearn
sklearn.preprocessing.MinMaxScaler(feature_range=(0,1))
MinMaxScaler.fit_transform(X)
# X:numpy array格式的数据类型[n_samples,n_features]
# 返回值:转化后的形状相同的array

二、Z-score标准化方法

x=xuσx = \frac{x-u}{\sigma}

u = 所有样本的均值,σ为所有样本的标准差

自己实现Z-score的方法

def StandardScaler(data):
    columns = data.columns
    for item in columns:
        data[item]=(data[item]-data[item].mean())/data[item].std()
  • 均方根误差RMSE
    (1n(yiy)2)\sqrt{(\frac{1}{n} \sum(yi - y)^2)}
  • 残差Residuals 应该是散点图位于0的附近
    yyiy-yi

残差图

以残差€为纵坐标,以拟合值y或对应的数据观测序号i或者数据观测时间为横坐标的散点图统称为残差图

根据虾哥的解释 x轴是range(样本数),y轴是(预测值-实际值)

# 依旧传入的是训练样本  y_pre, y_text
def residuals(y_pre, y_text):
    y_axis = y_pre - y_text.reshape((1715,1))   # 获取y值
    x_axis =np.arange(y_text.shape[0])
    y_axis.shape,x_axis.shape,y_pre.shape,y_text.shape
    fig, ax = plt.subplots(figsize=(12,8))
    ax.scatter(x_axis,y_axis)
    ax.set_xlabel("sample")
    ax.set_ylabel("residuals")
    ax.set_title("Res")
    plt.show()  

6.特征降维

什么是降维,具体的概念

  • 降维-降低维度 维数:嵌套的层数

    • 举例: 0-维:标量 1维:向量 2维:矩阵 3维 n维
  • 二维数组:此处的降维主要是值降低特征的个数 效果:特征于特征之间不相关

降维的两种方式

1.特征选择

概念

减少特征数量、降维,使模型泛化能力更强,减少过拟合;增强对特征和特征值之间的理解。

  • 特征是否发散:如一个特征不发散,例如方差接近0,也就是样本在这个特征上没有差异,这个特征对于样本的区别也就没有什么用
  • 特征与目标的相关性:与目标相关性高的特征,应当优先选择
方法
1.Filter过滤式

1.方差选择法:低方差特征过滤

  • 特征方差小:某个特征大多样本的值比较相近特征方差大:某个特征很多样本的值都有差别

    # 补充知识点,pandas删除数据的操作
    df.drop(labels=["",""],axis = 1) # 删除多列的数据
    df.drop([''],axis=)  # 删除一行的数据  axis =1 是列数据
    
    # 低方差数据的筛选
    def lowstd(data,threshold):    #简单的一个低方差筛选器
      colums = data.colums
      for item in colums:
          if data[item].std() <= threshold:
              data.drop([item],axis=1)
    
sklearn.feature_selection_VarianceThreshold(threshold=0.0)
# 删除所有低方差特征的值
Variance.fit_transform(X)
# 训练集低于threshold的特征将会呗删除,默认值是保留所有非零方差特征,即删除样本中具有相同值的特征

2.相关系数:特征与特征之间的相关程度

皮尔逊相关系数:反映变量之间相关关系密切程度的统计指标

公式计算案例(了解,不用记忆)

r=nxyxynx2(x)2ny2(y)2r = \frac{n\sum{xy}-\sum{x}\sum{y}}{\sqrt{n\sum{x^2}-(\sum{x}})^2\sqrt{n\sum{y^2}-(\sum{y})^2}}

相关系数的值介于-1<=r0时,表示两变量正相关,r<0时,两变量为负相关**

  • 当|r|=1时,表示两变量完全相关,当r=0时,表现两变量间无相关关系
  • 当0<|r|<1,表示两变量存在一定程度的相关,且|r|越接近1,两变量线性关系越密切;同类. ..
  • **一般可以分为三级|r|<0.4为低度相关;0.4<=|r|<=0.7为显著相关;0.7<=|r|thresold}\0,if\quad{X\leq{thresold}}\end{cases}

8.分箱(简单离散化方法):

等宽分箱,将范围分成大小相等的N个区间(均匀网格)

等深度(频率)分箱,将范围划分为 N 个区间,每个区间包含大约相同数量的样本

离散区间的大小影响支持度和置信度

– 如果间隔太小,可能没有足够的支持

– 如果间隔太大,可能没有足够的置信度

可能的解决方案:使用所有可能的间隔

  1. 等宽分箱法(基于属性/特征值大小区间来划分):按照相同宽度将数据分成几等份。
  2. 等频分箱法(基于样本数量区间来划分):将数据分成几等份,每等份数据里面的个数(数量/频数)是一样的

设 X 属性值的xmin=a,xmax=b,将连续数据按照等宽法定义离散为 k 等份,则:
离散值为

​ value=[1,2,3,...,k]

划分属性值宽度为

​ width=(b−a)/k

代码实现:

'''传入的数据为一列的数据,list形状'''
def equal_width_bos(data):
    # 划分的等份数,储存等宽分箱后的数据
    k,data_width_box = 3, data
    # 分箱的宽度,区间起始值(最小值)、(离散值)
    width, start, value = (max(data)-min(data))/k,min(data),list(range(1, k+1))
    for i in range(1, k+1):
        left = start + (i-1)*width
        right = start + (i*width)
        print('第 %d 个区间:[%.2f, %.2f]'%(i, left, right))
    for j in range(len(data)):
        if(data[j]>=left) and (data[j]<=right):
            data_width_box[j] = value[j-1]
    return data_width_box

回归评价指标MSE,RMSE,MAE,R-Squared

均方误差(MSE)

1/mi=1m(yiyi)21/m\sum_{i=1}^{m}({yi-yi'})^2

代码的实现

def mse(y_pre,y_text):
    inner = np.sum(np.power(y_text - y_pre,2))/len(y_text)
    return inner

均方根误差(RMSE)

(1/mi=1m(yiyi)2\sqrt(1/m\sum_{i=1}^{m}({yi-yi'})^2

代码的实现

def rmse(y_pre, y_text):
    inner = np.sum(np.power(y_text-y_pre,2))/len(y_text)
    return np.sqrt(inner)

平均绝对误差(MAE)

1/mi=1m\absyiyi1/m\sum_{i=1}^{m}\abs{yi-yi'}

R-Squared

R2=1i=1(yiyi)2/mi=1(yiyiˉ)2/mR^2=1-\frac{\sum_{i=1}^{}({yi-yi’})^2/m}{\sum_{i=1}^{}({yi-\bar{yi}})^2/m}

分子就成为了均方误差MSE,分母就成了方差

1MSE(y,y)Var(y)1-\frac{MSE(y',y)}{Var(y)}

分类算法

sklearn转化器和估计器

转换器-特征工程的父类

估计器(sklearn机器学习算法的实现)

  • 用于分类的估计器

    • sklearn.neighbors k-近邻算法
    • sklearn.naive_bayes 贝叶斯
    • sklearn.linear_model.LogisticRegression 逻辑回归
    • sklearn.tree 决策树与随机森林
  • 用于回归的估计器

    • sklearn.linear_model.LinearRegression 线性回归
    • sklearn.linear_model.Ridge 邻回归
  • 用于无监督学习的估计器

    • sklean.cluster.KMeans 聚类

K-近邻算法

  • 如果一个样本在特征空间中的k个最近似(即特征空间中最邻近)的样本中的大多数属于一个类别,则这个样本也属于这个类别
  • 首先得对数据进行标准化处理(调用函数即可)
  • 距离公式(欧拉公式)
(a1b1)2+(a2b2)2+(a3b3)2+.....\sqrt{(a1-b1)^2+(a2-b2)^2+(a3-b3)^2+.....}

优点:简单,易于理解,易于实现,无需训练

缺点:

​ 1.必须指定K值,K值选择不当则分类精度不能保证

​ 2.懒惰算法:对于测试样本分类时的计算量很大,内存开销大

自己实现

# 等待实现....

调用sklearn

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

def knn_iris():
    ifis = load_iris()
    # 划分数据集
    x_train,x_test,y_train,y_test = train_test_split(iris.data,iris.target,random_start=6)
    transfer = StandScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.transform(x_text)
    # KNN算法
    estimator = KNeighborsClassifier(n_neighbors=3)
    estimator.fit(x_train,y_train)
    # 模型评估
    # 直接比对真实值和预测值
    y_predict = estimator.predict(x_test)
    print("y_predict\n",y_predict)
    print("直接比对真实值喝预测值",y_test==y_predict)
    #计算准确率
    score = estimator.score(x_test,y_test)
    print("准确率",score)
    return None