【 專案:信用卡客戶使用者畫像 及 貸款違約預測模型 】
In [ ]:
# -*- coding:utf-8 -*-import pandas as pd # 用於 資料清洗 和 資料整理import os # 工作路徑 及 資料夾操作import datetimepd.set_option('display.max_columns',None)# 分別設定好 資料集路徑 和 之後儲存生成的檔案 的路徑data_path = r'D:\Data_Sets_of_Analysis\Project_1_Analysis_of_Credit_Card_User_Portrait_and_Personal_Loan_Overdue\Data_Set_of_Credit_Card_User_Portrait_and_Personal_Loan_Overdue'save_file_path = r'D:\Data_Sets_of_Analysis\Project_1_Analysis_of_Credit_Card_User_Portrait_and_Personal_Loan_Overdue'os.chdir(data_path)load_file = os.listdir()print('\n' + '-'*25 + '列印目錄列表' + '-'*25) # 提示性分割線,方便閱讀print(load_file) # 列印目錄列表print('\n'*2 + '='*100) # 列印模組分割線,方便閱讀
In [2]:
'''【 #%% 】 開啟 View → Scientific Model 後點選其左邊的綠色剪頭 可分塊執行'''# # 因檔案較多,故採用for迴圈結合locals函式動態生成多個變數table_name = []columns_name_express = []columns_name = []sql_statement = []dataframe_table_columns_name = pd.DataFrame(columns=['表名','列名']) # 生成一個空的DataFrame,其列名為'表名'和'列名'for i in load_file:
# 僅讀取字尾為csv的表
if i.split('.')[1] == 'csv':
# locals()方法動態生成多個變數
locals()[i.split('.')[0]] = pd.read_csv(i,encoding='gbk',error_bad_lines=False,low_memory=False)
# 將 每一個表的名字 都新增到 table_name 列表中
table_name.append(i.split('.')[0])
# 將 每一個表的名字 連同 每一列的名字都新增到 columns_name_express 和 columns_name 列表中
columns_name.append(list(locals()[i.split('.')[0]]))
columns_name_express.append([i.split('.')[0] + '表的列名如下:' + str(list(locals()[i.split('.')[0]])) + '\n' + '-'*125])
''' i.split('.')[0] → 每一個表的名字 str(list(locals()[i.split('.')[0]])) → 1.locals[]中填入表示 表名 的i.split('.')[0],表示選中該locals中的該表 2.list(DataFrame)表示DataFrame的列名,故list(locals()[i.split('.')[0]]) 表示的是 取 表名 為i.split('.')[0] 的 表 的 列名 3.最後因為要連線字串,所以用str()函式將以上進行轉換 '\n' → 表示換行 '-'*125 → 將字串- 乘以125 表示列印 - 125次 作用為畫一個分割線,方便觀察,不易序列 最後將以上欄位轉換為列表,用append新增到 columns_name 中 '''
# 為方便用線上工具畫ER圖,在此順便生成sql語句
tn_str =''
for j in range(len(list(locals()[i.split('.')[0]]))):
tn_str += '\n' + list(locals()[i.split('.')[0]])[j] + ' ' + 'TEXT' + ','
sql_statement.append('CREATE TABLE' + ' ' + i.split('.')[0] + '\n' + '(' + tn_str.strip(',') + '\n' + ');')
# 生成一個 表格、列名透視表 並輸出excel檔案 方便作 列名分析
dataframe_table_columns_name = dataframe_table_columns_name.append(pd.DataFrame({'表名':i.split('.')[0],'列名':columns_name[-1]}))
In [ ]:
# 生成sql語句,複製後進入freego透過匯入MySQL DDL自動生成ER表格,再新增關係線即可生成ER圖# # 註釋:列屬性在此統一設定為【 TEXT 】僅為方便觀察使用print('線上MySQL語句繪製ER圖連結:複製以下生成的sql語句')for i in sql_statement:
print(i)
In [ ]:
dataframe_table_columns_name['列名含義分析'] = 0 # 為作pivot圖,增加全為0的數值列,之後再用replace(),將0全部替換為空warning = '? 注意:.to_excel重複執行會覆蓋原有表,故在正式編輯excel時應注意另存為新表,或建立一個副本' # 增加一列提示,方便表格使用pivot_table_column_name = pd.pivot_table(dataframe_table_columns_name,index=['表名','列名']).replace(0,'').append(pd.DataFrame(columns=[warning]))print('\n'*2 + '='*100) # 列印模組分割線,方便閱讀# 將以上得到的表格儲存到路徑為最開始已經設定好的【 save_file_path 】中,表格名稱為【 列名含義分析表(請另存).xls 】try:
pivot_table_column_name.to_excel(save_file_path +r'\列名含義分析表(請另存).xls')
print('表格已儲存完畢')except Exception:
print('錯誤,‘列名含義分析表(請另存).xls’未能成功儲存,請檢查報錯原因(如:重複執行時,原先檔案開啟未關閉,則後一次執行程式碼時,無法覆蓋原檔案報錯)')
In [ ]:
print('\n'*2 + '='*100) # 列印模組分割線,方便閱讀print('所有表格的名稱如下:' + str(table_name))
In [ ]:
print('\n'*2 + '='*100) # 列印模組分割線,方便閱讀for i in range(len(columns_name_express)):
print(columns_name_express[i][0])
In [ ]:
print('\n'*2 + '='*100) # 列印模組分割線,方便閱讀for tn in load_file:
col_num = len(list(locals()[tn.split('.')[0]]))
pd.set_option('display.max_columns', col_num) # 設定顯示最大列數為 表的列數
print('\n' + '-'*25 + '以下為%s表'% tn.split('.')[0] + '-'*25)
print(locals()[tn.split('.')[0]].head()) # 預設列印前五行
print(locals()[tn.split('.')[0]].count()) # 列印各列資料數
In [ ]:
# 建立一個函式用於 有選擇性地 查詢 某個表 中 某個列 的 可選取值(透過該函式還能檢視是否有空值)# # 1) 因def中無法直接引用local,故將所有的表格儲存到一個字典中,鍵 為 表名,值 為 表dict_of_tables = dict()for i in load_file:
dict_of_tables[i.split('.')[0]] = locals()[i.split('.')[0]] # 使用for迴圈將每一個表都增加到dict_of_tables中# # 2) 進行函式定義def check_distinct_column_value():
while True:
t_name = input('請輸入 表名 :')
c_name = input('請輸入 列名 :')
try:
import sqlite3
con = sqlite3.connect(':memory:')
dict_of_tables[t_name].to_sql(t_name,con)
c_value = pd.read_sql_query('select distinct %s from %s' % (c_name, t_name), con)
print(c_value)
break
except Exception:
print('發生錯誤,請檢查所輸入的 表名 和 列名 及其對應關係 是否正確,並重新輸入')# # 3) 選擇是否呼叫該查詢函式while True:
answer = input('是否呼叫“列名取值檢視”函式?回答 Y 或 N:')
if answer == 'Y':
check_distinct_column_value() #函式呼叫
elif answer == 'N':
break
else:
print('輸入有誤,請重新輸入回答,僅可回答Y 或 N')
In [ ]:
'''透過 信用卡客戶畫像 的 目標拆解 和 ER圖,需要用到 card、clients、disp(連線關係用)、trans根據之前的資料檢視,這三個表中均無缺失的情況'''import sqlite3con = sqlite3.connect(':memory:')locals()['card'].to_sql('card',con)locals()['clients'].to_sql('clients',con)locals()['disp'].to_sql('disp',con)locals()['trans'].to_sql('trans',con)
In [ ]:
sql_card_client = '''SELECT cd.*,ctdp.birth_date,ctdp.district_id,ctdp.sexFROM card AS cd JOIN (SELECT ct.birth_date,ct.district_id,ct.sex,dp.disp_id FROM clients AS ctJOIN disp AS dp ON ct.client_id = dp.client_id WHERE dp.type == "所有者")AS ctdpON cd.disp_id = ctdp.disp_id'''card_client = pd.read_sql_query(sql_card_client,con)print(card_client)
In [ ]:
# # 因作圖可能涉及到中文,在此先設定字型from pylab import mplmpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定預設字型mpl.rcParams['axes.unicode_minus'] = False # 解決儲存影像負號'-'顯示為方塊的問題# # # 探究信用卡總量 不同年份 的總量變化import datetimeimport matplotlib.pyplot as plt# # # 新增一列‘issue_year’,提取出年份card_client['issue_year'] = pd.to_datetime(card_client['issued']).map(lambda x:x.year)# # # 建立一個交叉表,顯示不同類別卡,不同年份的發行數量cross_tab = pd.crosstab(card_client.issue_year,card_client.type)print(cross_tab)# # # 畫趨勢面積圖labels = ['青年卡','普通卡','金卡']y1 = cross_tab.loc[:,'青年卡'].astype('int') # 將'青年卡'這列的每行的字元都轉換成inty2 = cross_tab.loc[:,'普通卡'].astype('int')y3 = cross_tab.loc[:,'金卡'].astype('int')x = cross_tab.index # 將index列,也就是issue_year轉換成intplt.stackplot(x,y1,y2,y3,labels=labels,colors=['#f89588','#3b6291','#f8cb7f'])plt.title('信用卡髮卡量隨年份的時間變化趨勢圖')plt.legend(loc = 'upper left') # 設定圖例位置在左上角plt.ylim(0,500) # 設定y軸刻度最大值# # # 設定 數字標籤,表明對應的髮卡量for a,b in zip(x,y1):
plt.text(a,0.5*b-10,b,ha='center', va= 'bottom',fontsize=7)for a,b in zip(x,y2):
plt.text(a,0.5*b+list(y1)[list(x).index(a)]-10,b,ha='center', va= 'bottom',fontsize=7)for a,b in zip(x,y3):
plt.text(a,0.5*b+list(y1)[list(x).index(a)]+list(y2)[list(x).index(a)]-10,b,ha='center', va= 'bottom',fontsize=7)plt.show()'''設定 數字標籤,格式示例: for a,b in zip(x,y): plt.text(a, b+0.05, '%.0f' % b, ha='center', va= 'bottom',fontsize=7) a:數字標籤的橫軸座標 b+0.05:數字標籤的縱軸座標 '%.0f' % b:格式化的數字標籤(保留一位小數) ha='center':horizontalalignment(水平對齊) va= 'bottom':verticalalignment(垂直對齊)的方式 fontsize:文字大小本案例中的例項說明: 因本例為堆疊圖,故對數字標籤的縱軸座標相應做了值疊加 y1對應的數字標籤的縱座標放中間,並下移10(下移10是為了看起來更美觀) y2對應的數字標籤的縱座標,要使其同樣放中間,則需用y2對應的b值乘以0.5再加上y1對應的b值,再下移10 y3對應的數字標籤的縱座標,要使其同樣放中間,則需用y3對應的b值乘以0.5再加上y1和y2對應的b值,再下移10'''
In [ ]:
cross_tab1 = cross_tabcross_tab1.loc['Sum'] = 0for i in list(cross_tab):
cross_tab1.loc['Sum'][i] = sum(cross_tab1[i])print(cross_tab1)plt.pie(cross_tab1.loc['Sum'],labels=list(cross_tab1),autopct='%1.1f%%',startangle=100,colors=['#3b6291','#f8cb7f','#f89588'])plt.title('不同種類卡的佔比情況')plt.show()
In [ ]:
# 如遇中文顯示問題可加入以下程式碼from pylab import mplmpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定預設字型mpl.rcParams['axes.unicode_minus'] = False # 解決儲存影像是負號'-'顯示為方塊的問題def stack2dim(raw, i, j, rotation=0, location='upper right'):
''' 此函式是為了畫兩個維度標準化的堆積柱狀圖 raw為pandas的DataFrame資料框 i、j為兩個分類變數的變數名稱,要求帶引號,比如"school" rotation:水平標籤旋轉角度,預設水平方向,如標籤過長,可設定一定角度,比如設定rotation = 40 location:分類標籤的位置,如果被主體圖形擋住,可更改為'upper left' '''
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import math
data_raw = pd.crosstab(raw[i], raw[j])
data = data_raw.div(data_raw.sum(1), axis=0) # 交叉錶轉換成比率,為得到標準化堆積柱狀圖
# 計算x座標,及bar寬度
createVar = locals()
x = [0] # 每個bar的中心x軸座標
width = [] # bar的寬度
k = 0
for n in range(len(data)):
# 根據頻數計算每一列bar的寬度
createVar['width' + str(n)] = list(data_raw.sum(axis=1))[n] / sum(data_raw.sum(axis=1))
width.append(createVar['width' + str(n)])
if n == 0:
continue
else:
k += createVar['width' + str(n - 1)] / 2 + createVar['width' + str(n)] / 2 + 0.05
x.append(k)
# 以下是透過頻率交叉表矩陣生成一串對應堆積圖每一塊位置資料的陣列,再把陣列轉化為矩陣
y_mat = []
n = 0
y_level = len(data.columns)
for p in range(data.shape[0]):
for q in range(data.shape[1]):
n += 1
y_mat.append(data.iloc[p, q])
if n == data.shape[0] * data.shape[1]:
break
elif n % y_level != 0:
y_mat.extend([0] * (len(data) - 1))
elif n % y_level == 0:
y_mat.extend([0] * len(data))
y_mat = np.array(y_mat).reshape(-1, len(data))
y_mat = pd.DataFrame(y_mat) # bar圖中的y變數矩陣,每一行是一個y變數
# 透過x,y_mat中的每一行y,依次繪製每一塊堆積圖中的每一塊圖
from matplotlib import cm
cm_subsection = [level for level in range(y_level)]
colors = [cm.Pastel1(color) for color in cm_subsection]
bottom = [0] * y_mat.shape[1]
createVar = locals()
for row in range(len(y_mat)):
createVar['a' + str(row)] = y_mat.iloc[row, :]
color = colors[row % y_level]
if row % y_level == 0:
bottom = bottom = [0] * y_mat.shape[1]
if math.floor(row / y_level) == 0:
label = data.columns.name + ': ' + str(data.columns[row])
plt.bar(x, createVar['a' + str(row)],
width=width[math.floor(row / y_level)], label=label, color=color)
else:
plt.bar(x, createVar['a' + str(row)],
width=width[math.floor(row / y_level)], color=color)
else:
if math.floor(row / y_level) == 0:
label = data.columns.name + ': ' + str(data.columns[row])
plt.bar(x, createVar['a' + str(row)], bottom=bottom,
width=width[math.floor(row / y_level)], label=label, color=color)
else:
plt.bar(x, createVar['a' + str(row)], bottom=bottom,
width=width[math.floor(row / y_level)], color=color)
bottom += createVar['a' + str(row)]
plt.title(j + ' vs ' + i)
group_labels = [str(name) for name in data.index]
plt.xticks(x, group_labels, rotation=rotation)
plt.ylabel(j)
plt.legend(shadow=True, loc=location)
plt.show()
In [ ]:
from stack2dim import *stack2dim(card_client,'type','sex')
In [ ]:
import seaborn as snsimport timecard_client['age']=(pd.to_datetime(card_client['issued'])-pd.to_datetime(card_client['birth_date']))card_client['age1']=card_client['age'].map(lambda x:x.days/365)ax_age = sns.boxplot(x = 'type', y = 'age1', data = card_client,palette=sns.xkcd_palette(['gold','windows blue','coral']))ax_age.set_title('不同卡型別的 年齡 比較')plt.show()
In [ ]:
sql_card_client_trans = '''select a.card_id,a.issued,a.type,c.type as t_type,c.amount,c.balance,c.date as t_date from card as a left join disp as b on a.disp_id=b.disp_id left join trans as c on b.account_id=c.account_id where b.type="所有者" order by a.card_id,c.date'''card_client_trans = pd.read_sql_query(sql_card_client_trans,con)# print(card_client_trans.head())# # 標準化日期card_client_trans['issued']=pd.to_datetime(card_client_trans['issued'])card_client_trans['t_date']=pd.to_datetime(card_client_trans['t_date'])print(card_client_trans)# # 對帳戶餘額進行清洗:去掉金額單位和逗號分隔,便於計算card_client_trans['balance_1'] = card_client_trans['balance'].map(lambda x:int(x.strip('$').replace(',','')))print(card_client_trans)# # 篩選出開卡前一年的資料card_client_trans_1 = card_client_trans[card_client_trans.issued > card_client_trans.t_date][
card_client_trans.t_date >= card_client_trans.issued-datetime.timedelta(days=365)]print(card_client_trans_1)# # 分組計算餘額均值card_client_trans_1['avg_balance'] = card_client_trans_1.groupby('card_id')['balance_1'].mean()card_client_trans_2 = card_client_trans_1.groupby(['type','card_id'])['balance_1'].agg([('avg_balance','mean')])# print(card_client_trans_1)# print(card_client_trans_2)card_client_trans_2.to_sql('card_client_trans_2',con)card_client_trans_3 = card_client_trans_2.reset_index()card_client_trans_3 = pd.read_sql('select * from card_client_trans_2', con)colors = ['windows blue','gold','coral']ax_balance = sns.boxplot(x='type',y='avg_balance',data=card_client_trans_3,palette=sns.xkcd_palette(colors))ax_balance.set_title('不同型別卡的持卡人在辦卡前一年內的 平均帳戶餘額 對比')plt.show()
In [ ]:
# # # # # 先將 借、貸 轉換成 更易理解的 out、incometype_dict = {'借':'out','貸':'income'}card_client_trans_1['type_1'] = card_client_trans_1.t_type.map(type_dict)# # # 將amount金額列的 金額單位 和 逗號分隔 去掉card_client_trans_1['amount_1'] = card_client_trans_1['amount'].apply(lambda x:int(x.strip('$').replace(',','')))card_client_trans_4 = card_client_trans_1.groupby(['type','card_id','type_1'])[['amount_1']].sum()card_client_trans_4.head()card_client_trans_4.to_sql('card_client_trans_4',con)card_client_trans_5 = card_client_trans_4.reset_index()card_client_trans_5.to_sql('card_client_trans_5',con)card_client_trans_6 = pd.read_sql_query('select * from card_client_trans_5 where type_1 = "income"',con)ax_amount_income = sns.boxplot(x='type',y='amount_1',data=card_client_trans_6,palette=sns.xkcd_palette(['gold','windows blue','coral']))ax_amount_income.set_title('不同型別持卡人在辦卡前一年內的 平均收入 對比')plt.show()card_client_trans_7 = pd.read_sql_query('select * from card_client_trans_5 where type_1 = "out"',con)ax_amount_out = sns.boxplot(x='type',y='amount_1',data=card_client_trans_6,palette=sns.xkcd_palette(['gold','windows blue','coral']))ax_amount_out.set_title('不同型別持卡人在辦卡前一年內的 平均支出 對比')plt.show()
In [ ]:
'''【信用卡客戶畫像總結分析】:(一)總體趨勢(近六年): 1.逐年髮卡量:金卡、普通卡均呈逐年上升趨勢,青年卡在1997年的發行量同比降低,但總體為上升趨勢; 逐年發行量佔比排名為:普通卡 > 青年卡 > 金卡 2.總髮卡量:總體髮卡量佔比排名為:普通卡 > 青年卡 > 金卡,其中普通卡佔比接近總髮卡量的3/4(二)基本屬性特徵 1.不同卡型別的 性別 比較: 普通卡和青年卡 男女性比例較為均衡,基本為1:1;金卡的男性持有者比例相較女性持有者明顯更多 2.不同卡型別的 年齡 比較: 普通卡和金卡的持有者年齡主要集中在30~60歲之間;而青年卡則普遍集中在25歲以內,卡型別設計與目標物件相符 3.不同型別卡的持卡人在辦卡前一年內的 平均帳戶餘額 對比: 金卡持有者的辦卡前一年的 平均餘額 是要顯著高於 普通卡 和 青年卡 的,卡型別設計與目標物件相符 4.不同型別持卡人在辦卡前一年內的 平均收入和平均支出 對比: 三種型別的 平均收入、平均支出 排序均符合:金卡 > 普通卡 > 青年卡,金卡的持有人群為收入較高的群體, 同樣其支出情況也相應高於普通持卡人群,而青年卡,由於其持卡人群多為年齡層較小的人群,收入支出均較低, 卡型別設計與目標物件情況相符'''
In [ ]:
# # 1)在loans表中增加一列,用數字來代替貸款狀態,方便後續分析loan_status = {'B':1,'D':1,'A':0,'C':2}locals()['loans']['loan_status'] = locals()['loans']['status'].map(loan_status)print(locals()['loans'])# # 2) 進行列新增'''透過disp表連線loans表和clients表'''data_1 = pd.merge(locals()['loans'],locals()['disp'],>
In [ ]:
# # 1)新增地區狀態資訊data_5 = pd.merge(data_4,locals()['district'],left_on='district_id',right_on='A1',how='left')# # # 將需要的列篩選出來trans_clients_district = data_5[['account_id','amount','duration','payments','loan_status','type_y','sex',
'age', 'district_id','GDP','A4','A10','A11','A12','A13','A14','A15','a16']]# # 2) 客戶個人經濟狀況資訊trans_loans = pd.merge(locals()['trans'],locals()['loans'],on='account_id')print(trans_loans.head())print(list(trans_loans))'''合併後出現的列名後帶_x和_y是因為合併的兩張表中有有相同的列名,為示區分加上的字尾;_x表示的是合併前'trans'表中的列,_y表示的是合併前'loans'表中的列'''
In [ ]:
# # 篩選出貸款前一年的交易資料trans_loans['date_x'] = pd.to_datetime(trans_loans['date_x'])trans_loans['date_y'] = pd.to_datetime(trans_loans['date_y'])# # 將 amount_x 和 balance 由字串型別,去掉$符號和逗號分隔,轉化為數值型別trans_loans['amount_x'] = trans_loans['amount_x'].apply(lambda x:int(x.strip('$').replace(',','')))trans_loans['balance'] = trans_loans['balance'].apply(lambda x:int(x.strip('$').replace(',','')))# # 篩選出放款日期按1年內至前一天的交易記錄trans_loans = trans_loans[(trans_loans['date_x']<trans_loans['date_y'])&((trans_loans['date_x']+datetime.timedelta(days=365))>trans_loans['date_y'])]# # 篩選使用者前一年內結息總額trans_loans_1 = trans_loans[trans_loans['k_symbol']=='利息所得']trans_loans_1 = pd.DataFrame(trans_loans_1.groupby('account_id')['amount_x'].sum())trans_loans_1.columns = ['interest']# # 篩選在本行是否由養老金和房屋貸款trans_loans_2 = trans_loans[(trans_loans['k_symbol']=='養老金')|(trans_loans['k_symbol']=='房屋貸款')]# # 標記是否在本行有房屋貸款trans_loans_2 = pd.DataFrame(trans_loans_2.groupby('account_id')['k_symbol'].count())trans_loans_2['house_loan'] = '1'del trans_loans_2['k_symbol']# # 篩選客戶一年內收入和支出(總和)print(trans_loans_2.head())trans_loans_3 = pd.DataFrame(trans_loans.pivot_table(values='amount_x',index='account_id',columns='type'))trans_loans_3.columns = ['out','income']# # 篩選客戶一年內餘額的均值和標準差trans_loans_4 = pd.DataFrame(trans_loans.groupby('account_id')['balance'].agg(['mean','std']))trans_loans_4.columns = ['balance_mean','balance_std']# # 合併資料data_temp = pd.merge(trans_loans_1,trans_loans_2,how='left',left_index=True,right_index=True)data_temp = pd.merge(data_temp,trans_loans_3,left_index=True,right_index=True)data_temp = pd.merge(data_temp,trans_loans_4,left_index=True,right_index=True)print(len(data_temp)) # 檢視資料條數是否與貸款表條數一致data_model = pd.merge(trans_clients_district,data_temp,left_on='account_id',right_index=True)print(data_model)
In [ ]:
print(data_model.isnull().sum()/len(data_model))'''分析缺失情況、原因及處理: 總共有 列存在缺失資訊 type_y:缺失資訊接近75%,資訊缺失過多,刪除列; A12 和 A15:A12 1995年失業率 和 A15 1995犯罪率(千人) 有極小部分資料缺失,因為是連續資料,使用中位數填充; house_loan:是否有房屋貸款,缺失值為沒有房屋貸款,填充字元‘0’'''
In [ ]:
del data_model['type_y']data_model['A12'].fillna(data_model['A12'].median(),inplace=True)data_model['A15'].fillna(data_model['A15'].median(),inplace=True)data_model['house_loan'].fillna('0',inplace=True)
In [ ]:
# # # <1> 因變數y = 'loan_status'# # # <2> 連續變數var_c = ['amount', 'duration', 'payments', 'GDP',
'A4', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'a16', 'age',
'interest', 'out', 'income', 'balance_mean',
'balance_std']# # # <3> 分類變數var_d = ['sex','house_loan']# # # # 對 sex 和 house_loan 兩個分類變數二值化,方便分析data_model['sex_kind'] = data_model['sex'].map({'男':1,'女':0})data_model['house_loan_kind'] = data_model['house_loan'].map({'1':1,'0':0})
In [ ]:
import matplotlib.pyplot as pltimport seaborn as snscorr = data_model[var_c+var_d].corr()plt.figure(figsize=(12,9)) # 指定寬和高(單位:英寸)sns.heatmap(corr,vmax=1,annot=True) # vmax設定熱力圖顏色取值的最大值;annot設定是否顯示格子數字plt.show()
In [ ]:
'''從熱力圖觀察可知: 貸款資訊、居住地資訊、經濟狀況資訊內各變數具有高相關性,對變數進行篩選及轉換 1. 貸款資訊中:保留amount 2. 居住地資訊: 1) 採用人均GDP,即對變數進行轉換; 2) 採用失業增長率 3. 經濟狀況資訊: 1) 客戶放款前近一年總結息(反應實際存款數額) 2) 收支比(反應客戶消費水平) 3) 可用餘額變異係數(反應客戶生活狀態穩定係數)'''data_model['GDP_per'] = data_model['GDP']/data_model['A4'] # 人均GDP人民生活水平的一個標準data_model['unemployment'] = data_model['A13']/data_model['A12'] # 失業增長率一定程度上反應經濟增長率data_model['out/in'] = data_model['out']/data_model['income'] # 消費佔收入比重,一定程度反應客戶消費水平data_model['balance_a'] = data_model['balance_std']/data_model['balance_mean'] # 可用餘額變異係數var = ['account_id','sex_kind','age','amount','GDP_per','unemployment','out/in','balance_a']# print(data_model)# print(list(data_model))
In [ ]:
data_model = data_model[var+[y]]for_predict = data_model[data_model[y]==2] # loan_status 為2表示狀態C,即:待定data_model = data_model[data_model[y]!=2]# # 定義自變數和因變數import numpy as npX = data_model[var]Y = data_model[y]# # 將樣本資料建立訓練集和測試集,測試集取20%的資料from sklearn.model_selection import train_test_splitx_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.2, random_state = 1234)
In [ ]:
from sklearn.linear_model import LogisticRegressionLR = LogisticRegression(penalty='l1',solver='liblinear')var_temp = ['sex_kind','age','amount','GDP_per','unemployment','out/in','balance_a']x_train_temp = x_train[var_temp]clf = LR.fit(x_train_temp,y_train) # 擬合x_test_temp = x_test[var_temp]y_pred = clf.predict(x_test_temp) # 預測測試集資料test_result = pd.DataFrame({'account_id':x_test['account_id'],'y_predict':clf.predict(x_test_temp)})new_test_result = test_result.reset_index(drop=True)print(test_result) # 輸出測試集中 account_id 對應的貸款狀態預測print(new_test_result) # 輸出測試集中 account_id 對應的貸款狀態預測print(clf.coef_) #檢視各變數的迴歸係數
In [ ]:
from sklearn.metrics import classification_reportprint(classification_report(y_test, y_pred))'''模型的精確率0.87,召回率0.84,f1_score為0.82'''
In [ ]:
from sklearn.metrics import roc_curve, aucfpr, tpr, threshold = roc_curve(y_test, y_pred)roc_auc = auc(fpr, tpr)plt.plot(fpr, tpr, color='darkorange',label='ROC curve (area = %0.2f)' % roc_auc)plt.plot([0, 1], [0, 1], color='navy', linestyle='--')plt.xlim([0.0, 1.0])plt.ylim([0.0, 1.0])plt.xlabel('False Positive Rate')plt.ylabel('True Positive Rate')plt.title('ROC_curve')plt.legend(loc="lower right")plt.show()
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69977871/viewspace-2700681/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 貸款違約預測專案-資料分箱
- 資料競賽入門-金融風控(貸款違約預測)五、模型融合模型
- 零基礎入門金融風控之貸款違約預測—模型融合模型
- 金融風控-貸款違約預測-Task04 建模與調參
- 天池金融風控-貸款違約挑戰賽 Task5 模型融合模型
- 資料競賽入門-金融風控(貸款違約預測)四、建模與調參
- 資料探勘實踐(金融風控):金融風控之貸款違約預測挑戰賽(上篇)[xgboots/lightgbm/Catboost等模型]--模型融合:stacking、blendingboot模型
- 零基礎入門金融風控-貸款違約預測-Task04——建模與調參
- 零基礎入門金融風控之貸款違約預測挑戰賽——簡單實現
- 大資料專案實戰之 --- 使用者畫像專案分析大資料
- 數字營銷(一)客戶畫像淺談
- Nacos - 客戶端心跳續約及客戶端總結客戶端
- 美聯邦學生貸款基於收入還款佔比擴大 仍有11%出現違約
- 使用者畫像
- 客戶端專案管理的挑戰及解決方法客戶端專案管理
- 專案2:運營商客戶流失分析與預測
- 數分專案-基於Cox風險比例模型的流失會員使用者預測模型
- 國美金融是“持牌大戶”還是“違規大戶”:國美易卡貸超出現套路貸APPAPP
- 一款功能簡約到可憐的SQL 客戶端SQL客戶端
- Acxiom:2024年客戶體驗預測報告
- 利用SAP F&R高效預測客戶需求
- AgeClub:2020中高階養老機構客戶畫像深度洞察研究
- 實戰專案| 7天掌握神經網路預測模型神經網路模型
- 使用者畫像產品化——從零開始搭建實時使用者畫像(六)
- Android客戶端專案元件化實踐Android客戶端元件化
- 倍智人才研究院:銀行業客戶經理人才畫像報告行業
- 使用者畫像標籤體系——從零開始搭建實時使用者畫像(三)
- 貸款借錢平臺 貸款原始碼 小額貸款系統 卡卡貸原始碼 小額貸款原始碼 貸款平臺開發搭建原始碼
- DPM如何規劃使用者畫像
- 專案功能--批次匯入預約設定
- 批次做成畫像dummy檔案
- 機器學習專案實戰----信用卡欺詐檢測(二)機器學習
- 機器學習專案實戰----信用卡欺詐檢測(一)機器學習
- MobData:華為手機使用者畫像
- 甲骨文推出針對銀行違約債務人的雲解決方案,提升客戶體驗
- 在OwinSelfHost專案中獲取客戶端IP地址客戶端
- 在SelfHost專案中獲取客戶端IP地址客戶端
- 專案管理中如何更好的控制客戶的需求?專案管理