import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.preprocessing import StandardScaler#去均值,方差归一化,类似于特征缩放
from sklearn.model_selection import train_test_split#分为训练集和测试集
from sklearn.model_selection import GridSearchCV#自动调参,并行参数搜索
from sklearn.linear_model import LogisticRegression#逻辑回归
from sklearn.metrics import classification_report#精确度、召回率
def load_and_analyse_data():
data = pd.read_csv('./data/creditcard.csv')
# ----------------------查看样本分布情况----------------------------------
count_classes = pd.value_counts(data['Class'])#也可以pd.value_counts(data['Class'],sort=False).sort_index(axis=0)其中,pd.valueC_counts对数据分类并计算,class为对数据中的标注"class"进行分类并计算,sort表布尔值,表计算结果按升序排序还是降序排序,sort_index是按索引进行排序,这里axis = 1不行
# print(count_classes)# negative 0 :284315 positive 1 :492
count_classes.plot(kind='bar')#柱状图画图
plt.title('Fraud class histogram')
plt.xlabel('Class')
plt.ylabel('Frequency')
plt.show()
# --------------------------------------------------------------------------
# ----------------------预处理---------------------------------------------
# ----------------------标准化Amount列---------
data['normAmout'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1))#增加一列标注为"normAmount",内容为Amount中数据的标准归一化,值的范围设为(-1,1),在原数据文件中不会增加这一列,但可以在代码中引用“normAmount”中的值。
data = data.drop(['Time', 'Amount'], axis=1)#去掉Time和Amount列,原数据文件不会改变,但程序中改了
#print(data['normAmout'])
# ----------------------------------------------
X = data.ix[:, data.columns != 'Class']#ix表数据搜索到的位置
y = data.ix[:, data.columns == 'Class']#ix表数据搜索到的位置,y为class这一列
positive_number = len(y[y.Class == 1]) # 492
negative_number = len(y[y.Class == 0]) # 284315
# print(y.Class==1)#输出布尔语句
# print(y[y.Class==1])#布尔语句也可以当索引,输出的是y中类别被1的数据
positive_indices = np.array(y[y.Class == 1].index)#.index是取出y=1对应的索引,并转化成np形式
# print(positive_indices)
negative_indices = np.array(y[y.Class == 0].index)#.index是取出y=0对应的索引,并转化成np形式
# ----------------------采样-------------------
random_negative_indices = np.random.choice(negative_indices, positive_number, replace=False)#从negative_indices中选择出positive_number个数来,replace=false表没有重复替换的随机采样,也就是采出来的数据如果是一样的,不替换,也就是独立的。
random_negative_indices = np.array(random_negative_indices)#选出来的数做成np格式
under_sample_indices = np.concatenate([positive_indices, random_negative_indices])#把两个数组串联起来
#print(positive_indices)
#print(random_negative_indices)
#print(under_sample_indices)
under_sample_data = data.iloc[under_sample_indices, :]#取出数据中标签对应的样本
X_sample = under_sample_data.ix[:, under_sample_data.columns != 'Class']#将取出的样本划分
y_sample = under_sample_data.ix[:, under_sample_data.columns == 'Class']#将取出的样本划分
print(y)
print(np.array(y))
print(np.array(y).reshape(len(y)))
print(X)
print(np.array(X))
return np.array(X), np.array(y).reshape(len(y)), np.array(X_sample), np.array(y_sample).reshape(len(y_sample))
if __name__ == '__main__':
X, y, X_sample, y_sample = load_and_analyse_data()
_, X_test, _, y_test = train_test_split(X, y, test_size=0.3, random_state=30)#random_state为随机数种子,用来测试最后最好参数的模型,其中_表空,不用这个数据。
X_train, X_dev, y_train, y_dev = train_test_split(X_sample, y_sample, test_size=0.3, random_state=1)
print("X_train:{} X_dev:{} X_test:{}".format(len(y_train),len(y_dev),len(y_test)))
model = LogisticRegression()#引入逻辑回归
parameters = {'C': [0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10]}#字典,所有的超参数
gs = GridSearchCV(model, parameters, verbose=5,cv=5)#model是模型,paramaters是参数,cv是5-fold交叉验证,verbose表输出训练过程。
gs.fit(X_train, y_train)#训练数据导入模型
print('最佳模型:', gs.best_params_, gs.best_score_)
print('在采样数据上的性能表现:')
print(gs.score(X_dev, y_dev))
y_dev_pre = gs.predict(X_dev)
print(classification_report(y_dev, y_dev_pre))
print('在原始数据上的性能表现:')
print(gs.score(X_test, y_test))
y_pre = gs.predict(X_test)
print(classification_report(y_test, y_pre))
数据集:
链接: https://pan.baidu.com/s/1OlZ-nkS4sbjSgoaetqqOGg 提取码: ggr8
缺点:
丢失大量数据,浪费。
优点:
更加均衡,把类别0和1都考虑的比较完整,如果直接用原始数据而不采样,则会偏向0,因为类别为0的数据太多了。
目的:
用来处理数据不平衡问题。