在資料驅動的時代,理解和預測客戶流失對於企業至關重要。本文將探討如何結合探索性資料分析(EDA)和機器學習技術,特別是 K-Means 分群演算法,分析銀行客戶流失資料,並進一步探討如何利用向量儲存技術 Pinecone 建立可擴充套件的索引,以應對日益增長的資料量。透過 EDA,我們發現客戶投訴與流失率之間存在顯著關聯,而年齡也是影響流失的關鍵因素。根據這些發現,我們運用 K-Means 分群技術將客戶有效地分為兩群:投訴且流失的客戶,以及未投訴且未流失的客戶。此分群結果有助於銀行更有針對性地制定客戶保留策略。此外,文章還詳細介紹瞭如何使用 Pinecone 建立向量儲存索引,以及如何將資料集從 10,000 筆擴充套件至 1,000,000 筆,並討論了在擴充套件過程中可能遇到的成本控制、效能最佳化和錯誤管理等挑戰及應對方案。

2. 探索性資料分析

在進行任何 RAG 技術與向量儲存的應用之前,探索性資料分析(EDA)是至關重要的步驟,因為它幫助我們瞭解資料中的潛在模式和趨勢。以下,我們將使用 pandas 所定義的客戶資料進行 EDA。

初步分析結果

初步分析顯示,客戶投訴與客戶流失率之間存在直接的相關性,意味著提出投訴的客戶更有可能離開銀行。此外,資料還顯示,50 歲及以上的客戶相比年輕客戶較不容易流失。有趣的是,收入水平(尤其是 100,000 美元的門檻)似乎對客戶流失決策的影響並不明顯。

為何不直接使用複雜的機器學習模型?

透過仔細檢視這些洞察,我們將展示為什麼直接跳入複雜的機器學習模型(尤其是深度學習)並不總是必要或有效的。在資料中的關係明顯且模式直接的情況下,更簡單的統計方法或基本的資料分析技術可能更合適且更具資源效率。例如,k-means 聚類別可以是有效的,我們將在訓練機器學習模型的部分實作它。

資料集特徵分析

當我們顯示 DataFrame 的列時,可以看到很難找到模式:

# Column Non-Null Count Dtype
--- ------ -------------- -----
0 CustomerId 10000 non-null int64
1 CreditScore 10000 non-null int64
2 Age 10000 non-null int64
3 Tenure 10000 non-null int64
4 Balance 10000 non-null float64
5 NumOfProducts 10000 non-null int64
6 HasCrCard 10000 non-null int64
7 IsActiveMember 10000 non-null int64
8 EstimatedSalary 10000 non-null float64
9 Exited 10000 non-null int64
10 Complain 10000 non-null int64
11 Satisfaction Score 10000 non-null int64
12 Card Type 10000 non-null object
13 Point Earned 10000 non-null int64

AgeEstimatedSalaryComplain 是可能與 Exited 相關的特徵。我們還可以顯示 DataFrame 以獲得洞察,如下圖所示:

圖 6.3:客戶投訴與銀行客戶流失(Exited)之間的強相關性視覺化

主要的特徵似乎是 Complain,它導致了 Exited(客戶流失),透過對 DataFrame 進行標準計算可以得出:

# 計算投訴與客戶流失的比例
if sum_exited > 0: 
    percentage_complain_over_exited = (sum_complain / sum_exited)
else:
    percentage_complain_over_exited = 0
# 列印結果
print(f"Sum of Exited = {sum_exited}")
print(f"Sum of Complain = {sum_complain}")
print(f"Percentage of complain over exited = {percentage_complain_over_exited}")

輸出結果顯示,投訴與客戶流失之間的比例非常高,達到 100.29%,意味著提出投訴的客戶事實上離開了銀行:

Sum of Exited = 2038
Sum of Complain = 2044
Percentage of complain over exited = 100.29%

只有少數客戶(6 位)在沒有投訴的情況下離開了銀行。

年齡與客戶流失的關係

執行 GitHub 上的 Python 函式,可以得到以下輸出結果:

  • 年齡與客戶流失(以 age=50 為門檻)顯示,50 歲以上的人似乎較不容易離開銀行:

Sum of Age 50 and Over among Exited = 634 Sum of Exited = 2038 Percentage of Age 50 and Over among Exited = 31.11%

    相反,年輕客戶如果不滿意,似乎更有可能離開銀行。

*   薪水與客戶流失(以 salary\_threshold=100000 為門檻)似乎不是一個重要的特徵,如下輸出所示:
    ```
Sum of Estimated Salary over 100000 among Exited = 1045
Sum of Exited = 2038
Percentage of Estimated Salary over 100000 among Exited = 51
可以嘗試不同的門檻值來進一步分析資料集,以確認或反駁這一趨勢。

相關性熱圖

讓我們根據 data1 pandas DataFrame 建立一個熱圖:

import seaborn as sns
import matplotlib.pyplot as plt

# 只選擇數值列進行相關性熱圖分析
numerical_columns = data1.select_dtypes(include=['float64', 'int64']).columns

# 相關性熱圖
plt.figure(figsize=(12, 8))
sns.heatmap(data1[numerical_columns].corr(), annot=True, fmt='.2f')
plt.title('相關性熱圖')
plt.show()

圖表翻譯:

此圖表展示了資料集中每個特徵(變數)之間的相關性。相關係數範圍從 -1(低相關性)到 1(高相關性),0 表示無相關性。

我們可以看到,ComplainExited 之間的相關性最高。

透過上述分析,我們已經探索了幾個特徵。接下來,我們將建立一個機器學習模型,以進一步探索這些洞察。

3. 訓練機器學習模型

讓我們繼續進行 EDA,並透過機器學習模型進一步深入資料集。本部分將使用聚類別技術(具體來說是 k-means 聚類別)來探索資料集中的模式。我們將準備和處理資料進行分析,應用聚類別,並使用不同的指標評估結果。這種方法對於提取洞察非常有價值,而無需立即訴諸更複雜的深度學習方法。

k-means 聚類別簡介

k-means 聚類別是一種無監督的機器學習演算法,它透過最小化每個簇內的方差,將資料集劃分為 k 個不同的、非重疊的簇。該演算法迭代地根據最近的均值(質心)將資料點分配到 k 個簇之一,並在每次迭代後重新計算質心,直到收斂。

資料準備和聚類別

首先,我們將本章的資料集 data1 複製到 data2,以便在需要嘗試其他機器學習模型時可以傳回到 data1:

# 將 data1 複製到 data2
data2 = data1.copy()

您可以探索具有不同特徵集的各種場景。在這種情況下,我們將選擇 'CreditScore''Age''EstimatedSalary''Exited''Complain''Point Earned'

程式碼詳解:

此段程式碼將 data1 複製到 data2,確保在需要時可以傳回原始資料進行其他分析。這樣的操作允許在不修改原始資料的情況下對資料進行多種不同的處理和分析。

下一步是選擇特定的特徵欄位來進行後續的聚類別分析,所選欄位包括信用評分、年齡、預估薪水、是否離開銀行、是否有投訴以及獲得的積分。

#### 詳細內容解說:

  • 選擇特定特徵欄位的目的:在進行 k-means 聚類別或其他機器學習任務之前,選擇合適的特徵欄位是非常重要的。這是因為不同的特徵對於模型的影響不同,而且某些特徵可能與預測目標高度相關。
  • 'CreditScore''Age''EstimatedSalary''Exited''Complain''Point Earned' 的重要性:這些欄位被選中可能是因為它們在初步分析中顯示出與客戶流失或其他重要業務指標的相關性。例如,年齡和信用評分可能與客戶信用行為有關,而投訴和積分可能與客戶滿意度直接相關。
  • 資料準備:在進行聚類別之前,對資料進行適當的預處理也是非常重要的,包括但不限於處理缺失值、標準化或正規化資料等,以確保模型的準確性和可靠性。

透過仔細選擇和分析相關特徵,可以更有效地利用 k-means 聚類別來發現資料中的隱藏模式和洞察,為業務決策提供支援。

客戶流失分析與K-Means分群實踐

在客戶流失分析中,K-Means分群是一種有效的無監督學習方法,能夠根據客戶特徵將其分組,從而幫助銀行找出可能流失的客戶。本文將介紹如何使用K-Means分群技術對銀行客戶資料進行分析,並探討其與客戶投訴之間的關聯。

特徵選擇與資料預處理

首先,我們需要選擇與客戶流失相關的特徵。在本案例中,我們選取了CreditScore(信用評分)、Age(年齡)、EstimatedSalary(預估薪水)等變數作為分析特徵。這些特徵能夠反映客戶的財務狀況和人口統計特徵。

# 匯入必要的函式庫
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score, davies_bouldin_score

# 選取相關特徵
features = data2[['CreditScore', 'Age', 'EstimatedSalary', 'Exited']]

# 標準化特徵
scaler = StandardScaler()
features_scaled = scaler.fit_transform(features)

內容解密:

  • 使用StandardScaler對特徵進行標準化,以消除不同單位和尺度對分群結果的影響。
  • fit_transform方法結合了擬合和轉換步驟,將原始特徵縮放到均值為0、方差為1的標準正態分佈。

K-Means分群與評估

接下來,我們使用K-Means演算法對客戶資料進行分群,並評估不同分群數量下的分群品質。

# 試驗不同的分群數量
for n_clusters in range(2, 5):
    kmeans = KMeans(n_clusters=n_clusters, n_init=20, random_state=42)
    cluster_labels = kmeans.fit_predict(features_scaled)
    silhouette_avg = silhouette_score(features_scaled, cluster_labels)
    db_index = davies_bouldin_score(features_scaled, cluster_labels)
    print(f'For n_clusters={n_clusters}, the silhouette score is {silhouette_avg:.4f} and the Davies-Bouldin index is {db_index:.4f}')

內容解密:

  • 使用silhouette_score評估分群的輪廓係數,該係數越高,表示分群效果越好。
  • 使用davies_bouldin_score評估分群的Davies-Bouldin指數,該指數越低,表示分群效果越好。
  • 透過比較不同分群數量下的評估指標,選擇最佳的分群數量。

分群結果分析

根據評估結果,我們選擇了2個分群作為最佳分群數量。進一步分析發現,第一個分群(class=0)主要包含投訴並且流失的客戶,而第二個分群(class=1)則包含未投訴且未流失的客戶。

# 執行K-Means分群
kmeans = KMeans(n_clusters=2, n_init=10, random_state=0)
data2['class'] = kmeans.fit_predict(features_scaled)

# 統計每個分群的客戶數量
sum_class_0 = (data2['class'] == 0).sum()
sum_class_0_complain_1 = data2[(data2['class'] == 0) & (data2['Complain'] == 1)].shape[0]
sum_class_0_exited_1 = data2[(data2['class'] == 0) & (data2['Exited'] == 1)].shape[0]

print(f"Sum of 'class' == 0: {sum_class_0}")
print(f"Sum of 'class' == 0 and 'Complain' == 1: {sum_class_0_complain_1}")
print(f"Sum of 'class' == 0 and 'Exited' == 1: {sum_class_0_exited_1}")

內容解密:

  • 統計結果表明,class=0的分群中絕大多數客戶都投訴並且流失,進一步證實了投訴與客戶流失之間的強烈關聯。
  • class=1的分群中,極少數客戶投訴且流失,表明該分群的客戶對銀行服務較為滿意。

Pipeline 2:擴充套件 Pinecone 索引(向量儲存)

本章節的目標是利用我們的資料集建立 Pinecone 索引,並將其從 10,000 筆記錄擴充套件到 1,000,000 筆記錄。雖然我們是在前幾章的基礎上繼續發展,但擴充套件的實質內容與管理樣本資料集是不同的。

向量儲存管理的挑戰

在開始寫程式碼之前,我們需要先面對專案管理的挑戰。擴充套件與小規模資料處理不同,因為錯誤會被指數級放大。讓我們列出在執行任何程式碼之前必須面對的痛點:

  • OpenAI 模型選擇:持續檢查最新的嵌入模型,包括速度、成本、輸入限制和 API 呼叫率。
  • 計費管理:即時監控使用情況和成本。
  • Pinecone 約束:雲端和區域選擇、讀取單位、寫入單位和儲存成本。

安裝環境

首先,我們安裝所需的環境:

!pip install openai==1.40.3
!pip install pinecone-client==5.0.1

並初始化 API 金鑰:

f = open("drive/MyDrive/files/pinecone.txt", "r")
PINECONE_API_KEY=f.readline()
f.close()
f = open("drive/MyDrive/files/api_key.txt", "r")
API_KEY=f.readline()
f.close()
import os
import openai
os.environ['OPENAI_API_KEY'] =API_KEY
openai.api_key = os.getenv("OPENAI_API_KEY")

處理資料集

載入 Bank Customer Churn 資料集:

!cp /content/drive/MyDrive/files/rag_c6/data1.csv /content/data1
import pandas as pd
# 載入 CSV 檔案

內容解密:

  1. 資料集準備:將資料集載入 pandas DataFrame 中,為後續的 chunking 做準備。
  2. API 金鑰管理:將 API 金鑰儲存在安全的位置,並在程式中讀取和使用。
  3. 環境安裝:安裝 OpenAI 和 Pinecone 的客戶端函式庫,以進行嵌入和向量儲存的操作。

建立 Pinecone 索引

建立 Pinecone 索引是擴充套件向量儲存的關鍵步驟。我們將按照以下步驟進行:

  1. 資料準備和分塊:準備資料並將其分成適合嵌入的區塊。
  2. 嵌入處理:對分塊後的資料進行嵌入處理。
  3. 上傳到 Pinecone 索引:將嵌入後的資料上傳到 Pinecone 索引。
  4. 查詢 Pinecone 索引:執行查詢以檢索相關檔案,為 Pipeline 3 做準備。

擴充套件挑戰與解決方案

在擴充套件過程中,我們面臨的主要挑戰包括成本控制、效能最佳化和錯誤管理。透過選擇適當的 OpenAI 模型和監控 Pinecone 的使用情況,我們可以有效地應對這些挑戰。

圖表翻譯:

此圖示描述了 Pipeline 2 的主要步驟,包括資料準備、嵌入處理、上傳到 Pinecone 索引和查詢檢索。

資料準備與處理

在進行資料處理之前,首先需要載入所需的函式庫並讀取資料集。本文使用 pandas 函式庫來讀取 CSV 檔案。

資料載入與驗證

import pandas as pd

file_path = '/content/data1.csv'
data1 = pd.read_csv(file_path)

# 計算資料的行數
number_of_lines = len(data1)
print("資料行數:", number_of_lines)

輸出結果確認資料集包含 10,000 行資料。

內容解密:

  • 使用 pd.read_csv 函式讀取 CSV 檔案。
  • len(data1) 用於計算 DataFrame 中的行數,以驗證資料是否完整載入。

資料轉換與準備

接下來,將每行客戶記錄轉換為特定的文字格式,並儲存在 output_lines 列表中。

output_lines = []

for index, row in data1.iterrows():
    row_data = [f"{col}: {row[col]}" for col in data1.columns]
    line = ' '.join(row_data)
    output_lines.append(line)

# 顯示前 5 行資料
for line in output_lines[:5]:
    print(line)

輸出範例如下:

CustomerId: 15634602 CreditScore: 619 Age: 42 Tenure: 2 Balance: ...

內容解密:

  • 使用 iterrows() 方法遍歷 DataFrame 的每一行。
  • 將每列的名稱和值組合成 “欄位名稱: 值” 的格式,並用空格連線成一個字串。
  • 將這些字串新增到 output_lines 列表中。

資料複製與驗證

output_lines 複製到 lines,並驗證資料完整性。

lines = output_lines.copy()
number_of_lines = len(lines)
print("資料行數:", number_of_lines)

輸出結果再次確認有 10,000 行資料,確保資料在複製過程中未遺失。

內容解密:

  • 使用 copy() 方法複製列表,以避免原始資料被意外修改。
  • 再次檢查資料行數以確保資料完整性。