下采樣(處理資料不平衡問題)
阿新 • • 發佈:2018-11-28
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的資料太多了。
目的:
用來處理資料不平衡問題。