一般数据处理

版权声明:来一来,看一看,有钱的捧个人场,没钱的你不得捧个人场 https://blog.csdn.net/wait_for_eva/article/details/81987707
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cross_validation import train_test_split, KFold, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, recall_score, classification_report

# 读取数据
data = pd.read_csv('data.csv')
# 去空
data = data.dropna()
# 归一化
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1))
'''
有些数据,在分布范围上十分离散,“间距”比较大
这种差异,在测试过程中对数据表现有很大的影响
通过归一化,把数据按比例投射到定点区间
保留差异的比例,但是缩小了“间隔”
削弱样本数据的差异化,却真实的保留了影响
能够更准确的测试数据表现
'''
# 移除不需要的数据
data.drop(['Time', 'Amount'], axis=1)
'''
如果对测试没有太大影响,也可以fillna(0)填充默认值
'''
# 下采样
'''
一般分类任务,正例和反例样本均等是最好的
但是故意挑选的不具有普适性,为了避免差异化,一般都是均等采样,于是导致了数据的分布差异
为了正确的测试模型,需要使得正反例数据就均等,且不胡乱采样破坏数据的普遍性
这就出现了对采样数据的二次采样

下采样
    以小数量级的样本为限,在样本中大数量级的数据中随机采样,达到两种样本的均等
上采样
    以一个适合的样本数量,从大数量样本中随机抽取该数量,从小数量样本中随机选择复制填充,达到样本均衡

所以,除非条件有限或者影响不大,不能轻易手动填充或修改样本属性值
'''
# 反例的个数和索引
n_number = len(data[data.Class == 1])
n_index = np.array(data[data.Class == 1].index)

# 正例的全索引
y_index = data[data.Class == 0].index

# 需要抽取的对应的反例的个数
# 通过抽取索引进行抽取
# 转换为np.array方便进行Series操作

# y_index   :数据集
# n_number  :抽取个数
# replace   :抽取后是否放回再进行抽取
'''
采取不放回采样,避免数据的重复影响,尽量使数据真实
'''
under_y_index = np.random.choice(y_index, n_number, replace=False)
under_y_index = np.array(under_y_index)

# 正例索引加反例索引,抽取所需数据全部索引
'''
拼接数据,记得是列表内组合,传入的是一个组合列表,而不是两个列表参数
'''
under_index = np.concatenate([n_index, under_y_index])
# 通过索引取数
# pandas的数据分两层
# 1. 样本层    : 区分不同的个体表现
# 2. 维度层    : 区分不同的维度属性
# 指定个体的全维度信息
'''
关于loc, iloc, ix可以参看一下  https://blog.csdn.net/wait_for_eva/article/details/81913950
'''
under_data = data.iloc[under_index, :]

# 数据集和结果集
# 抽取全部样本的不同属性
# 数据集
'''
把因、果分开,保证一对一就好
'''
x_under_data = under_data.ix[:, under_data.columns != 'Class']
y_under_data = under_data.ix[:, under_data.columns == 'Class']
'''
数据模型需要测试和验证,同时也要保证因、果,因此,至少需要四组数据
         因         果
测试   测试数据集   测试结果集
训练   训练数据集   测试数据集
'''
# 数据分割

# x_data        : 数据集
# y_data        : 结果集
# test_size     : 取数率
# random_state  : 随机率
# x_train       : 训练数据集
# x_test        : 测试数据集
# y_train       : 训练结果集
# y_test        : 测试结果集
x_under_train, x_under_test, y_under_train, y_under_test = train_test_split(x_under_data, y_under_data, test_size=0.3,
                                                                            random_state=0)
'''
train_test_split主要是随机的把数据分成两部分,分别用作训练和测试用
传入的是基本数据,返回的是分割数据,一一对应
test_size       表示测试数据的总体样本占比,通过该参数调整两部分参数的比例
random_state    test_size一样的话,相同random_state生成的数据始终相同
                可以保证test_size相同,通过调节random_state得到不同分布的数据
                从各种数据分布上检验模型以及参数的合理性
'''

# 召回率
# 样本 : 正P   反N
# 预测 : 正T   反F
'''
分类任务,最重要的就是判别,通过事实分类和预测分类,共组合为四种
其中需要提高的是    TP, FN
需要降低的是       TN, FP
分别是正判和误判的区别,我们应该尽量提高正判,尽量降低误判
其中正例正判和事实正例的比例,称作召回率
现实中大部分活动中,总需要我们尽量少出错,因此常用召回率衡量
不过代价就是提高了误判的占比,枪法不好,为了数量,多打几枪而已
本质上还是等价交换,并没有提高模型的预测能力,毕竟才四分之一,始终是比较片面
需要全面的进行评价才是王道
'''
# 交叉验证
'''
前面说了,为了让模型有较好的适应性,需要从各数据角度进行测试
训练数据和测试数据本身都是事实数据,本质上没有因果关系
需要反复的打乱和调换角色,才能够得到接近真实的结论
数据乱序,角色颠倒,重复测试,这就是所谓的交叉验证
避免了一时数据切分导致的偶然性,会让结论具有比较好的适应性和表现
'''
def print_kflod_scored(x, y):
    # KFlod
    # 指定长度
    # 份数
    # shuffle   数据是否打乱
    # 生成切分索引,[[data_index], [train_index,test_index]]
    # 是批次索引和数据切分索引的zip组合
    flod = KFold(len(y), 5, shuffle=False)
    '''
    虽然可以手动拆分,但是重复步骤太多太繁琐,不停调整random_state也不是比较合理
    KFold提供了自动切分的功能,虽然可以直接切分数据,不过切分索引的话更合适,对于各种数据都适用
    三个参数分别是数据长度,切分的份数,和数据是否打乱
    数据切分的份数取决于数据长度,当数据过少,得到的也是“合理”切分过的,只是不是自己想的那样
    而所谓的shuffle,是作为测试集索引过的是否可以再次出现,也相当于是是否“放回”
    具体的理解,结尾专门测试一下
    '''
    # 逻辑回归可传入的正则惩罚参数
    c_params = [0.01, 0.1, 1, 10, 100]
    '''
    不论是分类或者是其他学习办法,都是“循序渐进”,徘徊中前进
    “损失函数”就是其中的打狗棒,反复的调教,然后学会“规矩”
    而一些额外的“小措施”,让“糖”不那么甜,让“棒”不那么狠
    也就是不一概而论,加上一些比较“实际”?“实用”的措施
    让“调教”更加人性化,更具普适性,避免过拟合
    要不只能“此狗有效”,而不能成为“调教宝典”
    
    除去损失函数,常用的额外限制就是范数了,也就是n方和的n方根
    不过常用的就是一范和二范,也就是一维距离和二维距离
    更高的范数(三维距离?四维距离)目前我还没能参悟
    '''
    # 结论存储结构,记录不同的参数下,各种交叉验证中的recall值
    result_table = pd.DataFrame(index=range(len(c_params), 2), columns=['c_param', 'mean_recall'])
    ''''''
    # 先填充正则参数列
    result_table['c_param'] = c_params
    # 记录结果参数行,便于记录对应的行结果
    j = 0
    # 遍历参数,观察不同参数的不同表现
    for c_param in c_params:
        print("========================")
        print('c_param: {}'.format(c_param))
        print("=========================")

        # 交叉验证,相同的参数需要经过多轮交叉验证的考量
        # 通过计算平均recall值,进行综合的评价
        recalls = []
        # 通过KFold得到的交叉索引迭代取数,进行交叉验证
        for iteration, indices in enumerate(flod, start=1):
            # 创建模型,指定惩罚类型和传入惩罚参数
            lr = LogisticRegression(C=c_param, penalty='l1')
            # 训练
            lr.fit(x.iloc[indices[0], :], y.iloc[indices[0], :].values.ravel())
            # 测试
            y_pred = lr.predict(x.iloc[indices[1], :].values)
            # 计算recall值
            recall = recall_score(y.iloc[indices[1], :].values, y_pred)
            # 添加进入recalls集合,便于后续求平均进行评价
            recalls.append(recall)
            # 提示打印
            print("iteration : {} \t\t recall : {}".format(iteration, recall))
        # 结果总集记录,针对c_param进行记录,不针对每次交叉验证
        result_table.ix[j, 'mean_recall'] = np.mean(recalls)
        # c_param游标,指定结果记录集位置
        j += 1
        print("============================")
        print("mean recall : {}".format(np.mean(recalls)))
        print("============================")
    # 提取最大平均recall值最大的结果值对应的c_param,样本表现最好
    best_c = result_table.loc[result_table['mean_recall'].idxmax()]['c_param']
    print("******************************************************************")
    print("best c is : {}".format(best_c))
    print("******************************************************************")
    return best_c


print_kflod_scored(x_under_data, y_under_data)
'''
iteration : 1 		 recall : 0.817258883248731
iteration : 2 		 recall : 0.883248730964467
iteration : 3 		 recall : 0.8775510204081632
iteration : 4 		 recall : 0.0
iteration : 5 		 recall : 0.0
============================
mean recall : 0.5156117269242723
============================
========================
c_param: 100
=========================
iteration : 1 		 recall : 0.8883248730964467
iteration : 2 		 recall : 0.8781725888324873
iteration : 3 		 recall : 0.8673469387755102
iteration : 4 		 recall : 0.0
iteration : 5 		 recall : 0.0
============================
mean recall : 0.5267688801408889
============================
******************************************************************
best c is : 100.0
******************************************************************
'''

KFold

from sklearn.cross_validation import KFold

data_index = KFold(10, 10, shuffle=False)

for iteration, indices in enumerate(data_index, start=1):
    print(iteration, ":", indices)


'''
    不填写start=1,迭代默认从0开始计数
0 : (array([4, 5, 6, 7, 8, 9]), array([0, 1, 2, 3]))
1 : (array([0, 1, 2, 3, 7, 8, 9]), array([4, 5, 6]))
2 : (array([0, 1, 2, 3, 4, 5, 6]), array([7, 8, 9]))


    shuffle=True,后面的验证集会随机取值,不重复,但是每次计算会变化
1 : (array([4, 5, 6, 7, 8, 9]), array([0, 1, 2, 3]))
2 : (array([0, 1, 2, 3, 7, 8, 9]), array([4, 5, 6]))
3 : (array([0, 1, 2, 3, 4, 5, 6]), array([7, 8, 9]))


    data_index = KFold(data_count, split_count, shuffle=False)
    当spilt_count <= data_count时,会尽量切分满足要求的样本
    但是split_count > data_count时, 无法满足切分需求,会报错
'''

猜你喜欢

转载自blog.csdn.net/wait_for_eva/article/details/81987707