บทนำ

ลองนึกภาพว่าเป็นวันเกิดเพื่อนของคุณ และเธอก็ตัดสินใจจัดงานปาร์ตี้ที่บ้านของเธอ ดังนั้นในขณะที่ช้อปปิ้งที่ซูเปอร์มาร์เก็ตและยืนอยู่ที่เคาน์เตอร์เช็คเอาท์ในร้านค้าโดยมีคิวยาวอยู่ข้างหลังเธอ และแคชเชียร์ก็ประกาศอย่างรวดเร็วว่าบัตรของเธอถูกปฏิเสธ

เธอรู้สึกเขินอายเมื่อเต็มไปด้วยขนมและเครื่องดื่มเต็มถุง เธอลองใช้การ์ดอีกครั้ง แต่ผลลัพธ์ก็เหมือนเดิมอย่างน่าเศร้า สักพักก็มีข้อความเข้ามาในมือถือของเธอว่า “กด 1 หากคุณต้องการซื้อของชำจริงๆ มูลค่า 500 ดอลลาร์”

ดังนั้นสิ่งที่เพิ่งเกิดขึ้นระบบตรวจจับการฉ้อโกงของบริษัทตรวจพบธุรกรรมของเธอว่าเป็นธุรกรรมที่ผิดปกติและบล็อกบัตรทันที

ในกรณีนี้ ธุรกรรมที่ถูกกฎหมายได้รับการประกาศว่าเป็นการฉ้อโกง แต่ระบบการฉ้อโกงนี้ช่วยผู้บริโภคประหยัดเงินได้หลายล้านดอลลาร์ต่อปี ธุรกรรมที่ฉ้อโกงมักเป็นเหตุการณ์ความน่าจะเป็นเล็กๆ น้อยๆ ที่ซ่อนอยู่ในข้อมูลจำนวนมาก

ดังนั้น นักวิจัยจาก IEEE Computational Intelligence Society (IEEE-CIS) ต้องการปรับปรุงตัวเลขธุรกรรมการฉ้อโกงนี้ ในขณะเดียวกันก็ปรับปรุงประสบการณ์ของลูกค้าด้วย ด้วยการตรวจจับการฉ้อโกงที่มีความแม่นยำสูง ลูกค้าจึงสามารถช้อปปิ้งได้โดยไม่ต้องยุ่งยาก

ดังนั้น เรามาสร้างโมเดล Machine Learning ที่ช่วยให้เราสามารถจับธุรกรรมการฉ้อโกงได้ล่วงหน้า เพื่อดำเนินการได้ทันที และปรับปรุงประสบการณ์การช็อปปิ้งของลูกค้าด้วย ฉันได้นำชุดข้อมูลนี้มาจาก Kaggle เอาล่ะ มาเริ่มกันเลย

สารบัญ:

  1. การเก็บรวบรวมข้อมูล
  2. ความเข้าใจทางธุรกิจ
  3. การแปลงปัญหาทางธุรกิจเป็นปัญหา ML
  4. การวิเคราะห์ข้อมูลและวิศวกรรมคุณลักษณะ
  5. การปรับโมเดลอาคารและไฮเปอร์พารามิเตอร์และความสำคัญของฟีเจอร์
  6. ผลลัพธ์รวม
  7. ผลการทดสอบ
  8. การปรับใช้
  9. หมายเหตุสิ้นสุด

1.การรวบรวมข้อมูล

ฉันได้รวบรวมชุดข้อมูลนี้จาก Kaggle ด้านล่างนี้คือลิงค์



ชุดข้อมูลประกอบด้วยไฟล์ .csv จำนวน 2 ไฟล์

Transaction.csv — มีคุณสมบัติ 394 รายการ

indentity.csv — มี 41 คุณสมบัติ

ไฟล์ทั้งสองนี้เชื่อมต่อกันด้วยคอลัมน์ TransactionID คำอธิบายเกี่ยวกับแต่ละคอลัมน์สามารถพบได้ที่นี่ — ลิงก์

<แข็งแกร่ง>2. ความเข้าใจทางธุรกิจ

1. หากเกิดการฉ้อโกงกับธุรกรรม บริษัทควรบล็อคบัตรทันทีเพื่อเพิ่มรายได้ให้กับบริษัท และเพื่อช่วยลูกค้าจำนวนมากที่ใช้เงินทุนในทางที่ผิด

2. เนื่องจากธุรกรรมหลายล้านรายการเกิดขึ้นในแต่ละวินาที ดังนั้นงานทำนายสถานะของธุรกรรมจึงควรรวดเร็วที่สุดเท่าที่จะทำได้

3. โมเดลควรหลีกเลี่ยงการทำธุรกรรมที่ถูกกฎหมายว่าเป็นการฉ้อโกง และธุรกรรมที่ฉ้อโกงว่าไม่ฉ้อโกง ดังนั้นตัวแบบควรจะแข็งแกร่งในเรื่องนี้

4. แบบจำลองควรให้การประมาณความน่าจะเป็นของธุรกรรมการฉ้อโกงเพื่อให้ธุรกรรมไม่ยุ่งยาก

ตอนนี้ เรามีข้อกำหนดทางธุรกิจแล้ว เรามาจัดการกับปัญหานี้โดยใช้การเรียนรู้ของเครื่องกันดีกว่า

<แข็งแกร่ง>3. วัตถุประสงค์และข้อจำกัด

มีสองประเภทในการทำนายการฉ้อโกงและถูกกฎหมาย ซึ่งบ่งชี้ว่าเป็นปัญหาการจำแนกประเภทไบนารี

ข้อกำหนดด้านเวลาแฝงต่ำ —ตรวจจับธุรกรรมการฉ้อโกงทันทีและด้วยเหตุนี้จึงดำเนินการกับธุรกรรมที่ผิดปกติ

การตีความได้— โมเดลควรให้ผลลัพธ์ที่น่าจะเป็น (ความน่าจะเป็นของธุรกรรมอยู่ในประเภทการฉ้อโกง)

ต้นทุนของการจัดประเภทที่ไม่ถูกต้องอาจสูง —ลดทั้งผลบวกลวงให้เหลือน้อยที่สุด (ประกาศว่าธุรกรรมที่ถูกกฎหมายเป็นการฉ้อโกง) และค่าลบลวง (ประกาศธุรกรรมการฉ้อโกงที่เกิดขึ้นจริงว่าไม่มีการฉ้อโกง)

Pตัวชี้วัดประสิทธิภาพ:ผู้จัดงานตัดสินใจประเมินการส่งผลงานในพื้นที่ใต้เส้นโค้ง ROC ระหว่างความน่าจะเป็นที่คาดการณ์ไว้และเป้าหมายที่สังเกตได้ ดังนั้น ROC-AUC จะเป็นตัวบ่งชี้ประสิทธิภาพหลัก (KPI) ของเรา

“คะแนน AUC คือระดับ/การวัดความสามารถในการแยกส่วน และเราต้องการให้แบบจำลองของเราแยกธุรกรรมที่ถูกกฎหมายออกจากธุรกรรมการฉ้อโกงอย่างดี”

เราจะใช้ เมทริกซ์ความสับสน เพิ่มเติมเพื่อเพิ่มความสามารถในการตีความให้กับโมเดลต่างๆ

<แข็งแกร่ง>4. การวิเคราะห์ข้อมูลและคุณลักษณะวิศวกรรม

ประการแรก ฉันได้โหลดไฟล์ข้อมูล Transaction.csv และ Identity.csv และรวมไว้ในคอลัมน์ TransactionID

train_df = pd.merge( train_transaction, train_identity, how ='left')
test_df = pd.merge(test_transaction, test_identity, how='left')

ชุดข้อมูล Train ประกอบด้วยจุดข้อมูล 590540 จุด และการทดสอบประกอบด้วย 506691 เมื่อรวมกันแล้วเรามี 433 คอลัมน์ รวมถึงตัวแปรเป้าหมาย “is_fraud” ซึ่งมีค่าไบนารี 0 หมายถึงธุรกรรมที่ถูกกฎหมาย และ 1 หมายถึงธุรกรรมที่ฉ้อโกง

อย่างที่คุณเห็น ธุรกรรม 96.50% นั้นถูกต้องตามกฎหมาย และธุรกรรมเพียง 3.50% เท่านั้นที่เป็นการฉ้อโกง นี่แสดงว่ามันเป็นชุดข้อมูลที่ไม่สมดุลอย่างมาก

ตอนนี้ให้ตรวจสอบแถวที่ซ้ำกันและค่าว่าง คุณลักษณะการระบุตัวตนจำนวนมากมีค่าที่ขาดหายไปมากกว่า 99% ดีกว่าที่จะลบคอลัมน์เหล่านั้นออก

ฉันได้ทำการวิเคราะห์ข้อมูลในแต่ละคุณสมบัติอย่างละเอียดแล้ว คุณสามารถค้นหารหัสทั้งหมดได้ที่นี่ ลิงค์

เนื่องจากไม่สามารถอธิบายคุณสมบัติแต่ละอย่างได้ที่นี่ ฉันจะอธิบายคุณสมบัติที่น่าสนใจและข้อสังเกตที่นั่น

ธุรกรรมDT

นี่แสดงถึงเดลต้าเวลาจากวันที่และเวลาอ้างอิงที่กำหนด ค่าต่ำสุดอันดับแรกของ TransactionDT คือ 86400 ซึ่งสอดคล้องกับจำนวนวินาทีในหนึ่งวัน (60 นาที * 60 วินาที * 24 ชั่วโมง = 86400) ดังนั้น เราสามารถพิจารณาคอลัมน์ TransactionDT นี้เป็นเวลาในหน่วยวินาที ที่นี่เราจะเห็นว่าข้อมูลการทดสอบอยู่ก่อนข้อมูลรถไฟ ดังนั้นเราจะไม่ทำการแยกแบบสุ่ม นอกจากนี้ ข้อสังเกตประการหนึ่งคือในช่วงเวลาเริ่มต้นของธุรกรรมรถไฟและเวลาทดสอบข้อมูลครั้งล่าสุด ธุรกรรมมีมากกว่า 12,500 รายการ

ตอนนี้เรามาดูธุรกรรมการฉ้อโกงในสัปดาห์และวันที่แตกต่างกัน

เราสามารถสังเกตได้ที่นี่ว่าวันแรกของสัปดาห์มีธุรกรรมสูงสุดและวันที่สามของสัปดาห์มีธุรกรรมต่ำที่สุด จากแผนภาพชั่วโมงสรุปได้ว่าธุรกรรมการฉ้อโกงในชั่วโมงที่ 5 ถึง 10 มีมากกว่า และธุรกรรมที่ถูกกฎหมายตั้งแต่ 13 ถึง 18 รายการนั้นค่อนข้างสูง

Transaction_Amt

นี่คือจำนวนเงินที่เกี่ยวข้องกับแต่ละธุรกรรมในสกุลเงิน USD

plt.figure(figsize = (20,6))

plt.subplot(1,2,1)
sns.distplot(train_df[train_df['isFraud']==0]['TransactionAmt'])
sns.distplot(train_df[train_df['isFraud']==1]['TransactionAmt'])
plt.ylabel('Probability Density')
plt.legend(['legit','fraud'])
plt.title('Train')
plt.suptitle('TransactionAmt Distribution' , fontsize = 14)
plt.subplot(1,2,2)
sns.distplot(test_df['TransactionAmt'])
plt.ylabel('Probability Density')
plt.title('Test')

plt.show()

เราจะสังเกตได้ว่ามีค่าผิดปกติอยู่ไม่กี่ค่าซึ่งมีค่าเป็น › 30000 ควรลบค่าเหล่านี้ออกจะดีกว่าเนื่องจากจะส่งผลต่อแบบจำลองตามระยะทาง และค่าผิดปกติเช่นนี้อาจทำให้เกิดปัญหาการโอเวอร์ฟิตได้ การกระจายจำนวนเงินของธุรกรรมมีข้อมูลที่เบ้ขวา (หางยาว) ดังนั้นเราจึงสามารถทำการเปลี่ยนแปลงบันทึกในคุณลักษณะนี้ และสร้างคุณลักษณะใหม่ชื่อ LogTransactionAmtซึ่งมีการแจกแจงแบบปกติ

ซีดีผลิตภัณฑ์

รหัสผลิตภัณฑ์ที่เกี่ยวข้องกับแต่ละธุรกรรม

จากกราฟด้านบน เราจะเห็นว่าหากธุรกรรมเป็นการฉ้อโกง มีโอกาสประมาณ 40% จะเป็น Product C เมื่อพิจารณาว่ามีเพียง 10% เท่านั้นที่เป็นธุรกรรม Legit ใน C โอกาสที่ธุรกรรมจะถูกฉ้อโกงมีสูงหากเป็นของ Product C ส่วนใหญ่ ของธุรกรรมที่ได้กระทำแล้วสำหรับ ProductCD “W”

การ์ด

สรุปได้ว่าธุรกรรมส่วนใหญ่เกิดขึ้นผ่าน Visa และ Mastercard คุณสมบัติ card6 ระบุประเภทของบัตรเดบิตหรือเครดิต และพบว่าผู้ถือบัตรเครดิตมี % ของการฉ้อโกงที่สูงกว่าผู้ถือบัตรเดบิต

อีเมล — P_emaildomain และ R_emaildomain

เหล่านี้เป็นโดเมนอีเมลของผู้ซื้อและผู้รับตามลำดับ ในโดเมนอีเมลของผู้ซื้อ อีเมลทั่วไปส่วนใหญ่จะมาจาก gmail.com ในบรรดาเหล่านั้นไม่มี ของธุรกรรมการฉ้อโกงมาจากโดเมน protonmail.com R_emaildomain ประกอบด้วยค่าที่หายไปมากกว่า 70%

C_คุณลักษณะ

การนับเช่นจำนวนที่อยู่ที่เกี่ยวข้องกับบัตรชำระเงิน ฯลฯ ความหมายที่แท้จริงถูกปกปิด สิ่งเหล่านี้เหมือนกับการนับหมายเลขโทรศัพท์ ที่อยู่อีเมล ชื่อที่เชื่อมโยงกับผู้ใช้ อุปกรณ์ ที่อยู่ที่เรียกเก็บเงินสำหรับทั้งผู้ซื้อและผู้รับที่เพิ่มเป็นสองเท่า

ค่าคุณสมบัติเหล่านี้ส่วนใหญ่อยู่ใกล้กับ 1 มีค่าผิดปกติเพียงไม่กี่ค่าในคุณสมบัติบางอย่าง และคุณสมบัติบางอย่างดูเหมือนว่าจะมีการใช้งานร่วมกันอย่างมาก

M_คุณลักษณะ

คุณสมบัติ M ส่วนใหญ่มีค่า T, F M4 มีค่าต่างกันเช่น M2, M0

จากเนื้อเรื่อง ชัดเจนว่าฟีเจอร์ M1 ไม่มีประโยชน์ เนื่องจากไม่ได้มีส่วนช่วยในการจำแนกธุรกรรมที่ถูกกฎหมาย/ฉ้อโกง M7 มีส่วนร่วมน้อยมากในการค้นหาว่าธุรกรรมเป็นการฉ้อโกงและถูกกฎหมายหรือไม่ เนื่องจากคุณสมบัติเหล่านี้ไม่ได้แยกแยะความแตกต่างระหว่างธุรกรรมที่ถูกกฎหมายและการฉ้อโกงอย่างชัดเจน

ประเภทอุปกรณ์และข้อมูล

แสดงถึงประเภทของอุปกรณ์ที่ใช้ในการทำธุรกรรมและประเภทของระบบปฏิบัติการ

อุปกรณ์เช่น Windows, iOS, MacOS ถูกนำมาใช้กันอย่างแพร่หลายในการทำธุรกรรม จากประเภทอุปกรณ์สรุปได้ว่าธุรกรรมผ่านอุปกรณ์มือถือมีการฉ้อโกงมากกว่า

คุณลักษณะ “DeviceInfo” มีข้อมูล โดยที่ธุรกรรมอุปกรณ์เกิดขึ้น คุณลักษณะนี้เป็นการผสมผสานระหว่างชื่อคุณลักษณะและเวอร์ชันอุปกรณ์ ดังนั้นเราจึงสร้างคุณลักษณะสองประการขึ้นมา ได้แก่ ชื่ออุปกรณ์และอีกเวอร์ชันคือเวอร์ชันอุปกรณ์ จากนั้นจึงแมปชื่ออุปกรณ์แต่ละชื่อกับชื่อแบรนด์ที่เกี่ยวข้อง ที่นี่ เป็นข้อมูลโค้ดที่เหมือนกัน

import gc
# Maping each device to their corresponding brand.
def device_to_brand(dataframe):
    dataframe['device_name'] = dataframe['DeviceInfo'].str.split('/', expand=True)[0]
    dataframe['device_version'] = dataframe['DeviceInfo'].str.split('/', expand=True)[1]

    dataframe.loc[dataframe['device_name'].str.contains('SM', na=False), 'device_name'] = 'Samsung'
    dataframe.loc[dataframe['device_name'].str.contains('SAMSUNG', na=False), 'device_name'] = 'Samsung'
    dataframe.loc[dataframe['device_name'].str.contains('GT-', na=False), 'device_name'] = 'Samsung'
    dataframe.loc[dataframe['device_name'].str.contains('Moto G', na=False), 'device_name'] = 'Motorola'
    dataframe.loc[dataframe['device_name'].str.contains('Moto', na=False), 'device_name'] = 'Motorola'
    dataframe.loc[dataframe['device_name'].str.contains('moto', na=False), 'device_name'] = 'Motorola'
    dataframe.loc[dataframe['device_name'].str.contains('LG-', na=False), 'device_name'] = 'LG'
    dataframe.loc[dataframe['device_name'].str.contains('rv:', na=False), 'device_name'] = 'RV'
    dataframe.loc[dataframe['device_name'].str.contains('HUAWEI', na=False), 'device_name'] = 'Huawei'
    dataframe.loc[dataframe['device_name'].str.contains('ALE-', na=False), 'device_name'] = 'Huawei'
    dataframe.loc[dataframe['device_name'].str.contains('-L', na=False), 'device_name'] = 'Huawei'
    dataframe.loc[dataframe['device_name'].str.contains('Blade', na=False), 'device_name'] = 'ZTE'
    dataframe.loc[dataframe['device_name'].str.contains('BLADE', na=False), 'device_name'] = 'ZTE'
    dataframe.loc[dataframe['device_name'].str.contains('Linux', na=False), 'device_name'] = 'Linux'
    dataframe.loc[dataframe['device_name'].str.contains('XT', na=False), 'device_name'] = 'Sony'
    dataframe.loc[dataframe['device_name'].str.contains('HTC', na=False), 'device_name'] = 'HTC'
    dataframe.loc[dataframe['device_name'].str.contains('ASUS', na=False), 'device_name'] = 'Asus'

    dataframe.loc[dataframe.device_name.isin(dataframe.device_name.value_counts()[dataframe.device_name.value_counts() < 200].index), 'device_name'] = "Others"
    
    gc.collect()
    
    return dataframe

id_30, 31, 33

Id_30 ดูเหมือนฟีเจอร์ที่น่าสนใจและประกอบด้วยระบบปฏิบัติการและเวอร์ชันที่ผู้คนเคยทำธุรกรรม Id_31 แสดงว่าผู้ใช้ใช้เบราว์เซอร์เวอร์ชันใด Id_33 แสดงถึงความสูงและความกว้างของหน้าจอ ซึ่งสามารถแยกออกเป็นคุณลักษณะต่างๆ ในภายหลังได้

ตอนนี้เราได้ทำการวิเคราะห์ข้อมูล สร้างคุณลักษณะใหม่ ลบค่าผิดปกติและคุณลักษณะที่ไม่มีประโยชน์ออก รวมทั้งลบคอลัมน์ที่มีค่าที่หายไปมากกว่า 90% ซึ่งส่วนใหญ่เป็นคอลัมน์ id และลบค่าลบที่ไม่คาดคิดบางส่วนออก

5. การปรับโมเดลอาคารและไฮเปอร์พารามิเตอร์

ตอนนี้ให้ลบคุณลักษณะที่มีความสัมพันธ์กันสูงออกก่อน มีความสัมพันธ์ระหว่างคุณสมบัติ C และ D

ลบคุณลักษณะคอลลิเนียร์อย่างใดอย่างหนึ่งออกก่อนที่จะฝึกโมเดลให้เป็นประโยชน์ต่อกระบวนการเรียนรู้ และจะส่งผลให้มีประสิทธิภาพใกล้เคียงกับโมเดลเต็ม และการลดคุณลักษณะต่างๆ จะส่งผลให้โมเดลมีความซับซ้อนน้อยลงในที่สุด และค่าใช้จ่ายในการจัดเก็บคุณลักษณะเหล่านี้ก็จะน้อยลง

เราเห็นว่าฟีเจอร์ 'C2', 'C6', 'C10', 'C11', 'C12', 'C14' มีความสัมพันธ์อย่างมากกับคุณสมบัติอื่น ๆ คุณสมบัติ D บางอย่างในทำนองเดียวกัน 'D2', 'D6', 'D7', 'D12' มีความสัมพันธ์กันสูง เราจะลบคุณลักษณะเหล่านี้ออกก่อนการฝึกโมเดล

ตอนนี้ ให้เราใส่ค่าที่หายไปสำหรับคุณสมบัติเชิงตัวเลขและหมวดหมู่โดยใช้โหมดและค่ามัธยฐานตามลำดับ

# impute numerical value by median for each feature
for i in train_df.columns:
    if train_df[i].dtypes == 'int64' or train_df[i].dtypes == 'int32' or
       train_df[i].dtypes == 'int16' or train_df[i].dtypes == 'int8' or 
       train_df[i].dtypes == 'float64' or train_df[i].dtypes == 'float32' or
       train_df[i].dtypes == 'float16' :
        train_df[i].fillna(train_df[i].median(), inplace = True )
# imputation of categorical features by mode 
for i in train_df.columns:
    if train_df[i].dtypes == 'object':
        train_df[i].fillna(train_df[i].mode()[0], inplace = True)

โพสต์ว่าเราต้องเข้ารหัสคุณสมบัติที่เป็นหมวดหมู่ก่อนที่จะส่งคุณสมบัติไปยังโมเดลของเรา เนื่องจากเราจำเป็นต้องมีคุณสมบัติทั้งหมดที่เป็นตัวเลข

ขณะนี้คุณสมบัติทั้งหมดพร้อมสำหรับการส่งต่อไปยังโมเดลแล้ว ต่อไปฉันได้แบ่งข้อมูลเป็นอัตราส่วน 70:30 เพื่อการฝึกอบรมและการตรวจสอบ แต่การแยกที่นี่ไม่ใช่การสุ่ม แต่เป็นการแยกตามเวลาเนื่องจากเรารู้ว่าข้อมูลอนุกรมเวลาและข้อมูลการทดสอบทั้งหมดมาหลังจากข้อมูลรถไฟ หลังจากแยกแล้ว ฉันจะสร้างมาตรฐานข้อมูลของฉันโดยใช้ฟังก์ชัน StandardScaler() เพื่อกำหนดมาตรฐานค่าชุดข้อมูลให้อยู่ในรูปแบบมาตรฐาน ขั้นตอนนี้จะช่วยเราในการทำค่าเฉลี่ยของศูนย์กลางและมาตราส่วนความแปรปรวน โดยที่ค่าเฉลี่ยจะเป็น 0 และ std จะเป็น 1

ตอนนี้เรามาเริ่มกันที่การฝึกโมเดล ตามการรักษาข้อจำกัดทางธุรกิจ ฉันได้ใช้ 4 โมเดล: 1) การถดถอยโลจิสติก 2) แผนผังการตัดสินใจ 3) ฟอเรสต์สุ่ม และ 4) LGBM

ขั้นแรก ฉันฝึกโมเดลโดยใช้ Logistic การถดถอย เนื่องจากโมเดลนี้ทำงานได้ดีกับข้อมูลมิติสูงและให้ความน่าจะเป็นในการจำแนกประเภทไบนารี

parameters = {"alpha":[10**-4, 10**-3, 10**-2, 10**-1, 10**0, 10**1, 10**2, 10**3, 10**4]}
clf = SGDClassifier(loss = "log", class_weight = 'balanced', penalty = "l2")
rand_clf = RandomizedSearchCV(clf, parameters, scoring = "f1", n_iter = 500, n_jobs = -1, cv = 5, random_state = 1, return_train_score = True)
rand_clf.fit(sc_x_train, y_train)
print(rand_clf.best_params_)
print(rand_clf.best_estimator_)

ดังนั้น ที่นี่ สำหรับการปรับแต่งไฮเปอร์พารามิเตอร์ ฉันส่งค่าอัลฟา โดยใช้การทำให้เป็นมาตรฐาน L2 และยังกำหนด class_weight ให้เป็นสมดุล เนื่องจากข้อมูลของเราไม่สมดุลอย่างมาก และแบบจำลองของเราไม่ควรลำเอียงไปยังคลาสส่วนใหญ่ ฉันพบว่า alpha = 0.01 ดีที่สุด และด้วยค่า alpha นี้ ฉันได้ CV AUC เป็น 85.79 และ Train AUC เป็น 85.86

เราสามารถสรุปได้ว่าแบบจำลองนี้ไม่พอดีเกินไป เนื่องจากไม่มีความแตกต่างระหว่างคะแนน Train และ CV AUC มากนัก เราไม่ได้รับ AUC สูงเมื่อใช้โมเดลนี้ มาลองกับรุ่นอื่นบ้าง

รุ่นที่สองที่ฉันลองคือ การตัดสินใจ ต้นไม้ โมเดลนี้ถูกตีความและสามารถมองเห็นต้นไม้ได้ ไฮเปอร์พารามิเตอร์เช่น max_deep และเกณฑ์และใช้

parameter = {          
             "max_depth":[3, 5, 7, 9, 11, 13, 15],
             "criterion": ["gini", "entropy","log_loss"],                       
            }
clf = DecisionTreeClassifier(class_weight = 'balanced')
rand_clf = RandomizedSearchCV(clf, parameter, scoring = 'f1', n_jobs = -1)
rand_clf.fit(x_train, y_train)
print(rand_clf.best_params_)
print(rand_clf.best_estimator_)

ระหว่างฝึกซ้อม ฉันได้คะแนน AUC ที่ดีที่สุดโดยมีค่า max_deep เท่ากับ 15 และมีเกณฑ์เท่ากับ Gini CV-AUC มาถึงที่นี่คือ 83.30 และฝึก AUC = 94.65

แต่ CV-AUC ต่ำไปหน่อยเมื่อใช้รุ่นนี้ ดังที่เราทราบ ต้นไม้การตัดสินใจอาจไม่เสถียรในบางครั้ง เนื่องจากการเปลี่ยนแปลงเล็กน้อยของข้อมูลอาจส่งผลให้มีการสร้างแผนภูมิที่แตกต่างกันโดยสิ้นเชิง และแบบจำลองตามต้นไม้มีแนวโน้มที่จะพอดีเกินไปได้ง่าย ดูเหมือนว่ามีสัญญาณรบกวนและรีดักชั่นในข้อมูลและแบบจำลองก็จับภาพได้ ข้อมูลประเภทนี้สามารถลบออกได้โดยใช้เทคนิคความสำคัญของคุณลักษณะ (การเลือกไปข้างหน้าหรือการกำจัดย้อนหลัง) ตอนนี้ให้ลองใช้รุ่นอื่นที่ให้ผลลัพธ์ที่ดีกว่า

โมเดลถัดไปที่ฉันลองใช้คือโมเดล สุ่ม ป่าไม้ ที่นี่ฉันใช้พารามิเตอร์ที่แตกต่างกันดังนี้

random_parameter = {
 'bootstrap': [True, False],
 'max_depth': [3, 5, 7, 9, 11, 13, None],
 'max_features': ['auto', 'sqrt'],
 'n_estimators': [25, 50, 100, 200, 300, 500, 700, 900, 1000]
}

ไฮเปอร์พารามิเตอร์ที่ดีที่สุดที่ฉันได้รับที่นี่คือ n_estimator เป็น 25 CV AUC สุดท้ายที่ได้รับคือ 89.71 และคะแนน Train AUC คือ 99.99 โมเดลนี้ทำงานได้ดีเมื่อเปรียบเทียบกับโมเดลแบบต้นไม้อื่นๆ เนื่องจากโมเดล Random Forest ได้รับผลกระทบจากสัญญาณรบกวนน้อยลงและมีความทนทานต่อค่าผิดปกติ

ในที่สุดก็มาลองใช้โมเดลที่ทรงพลังที่สุด LGBM

parameter_lgbm = {
             'max_depth':[1, 3, 4, 5],
             'learning_rate':[0.001, 0.01, 0.1], 
             'n_estimators': [100, 300, 500, 600, 800, 1100],
             'min_child_samples': sp_randint(100, 400), 
             'min_child_weight': [1e-5, 1e-3, 1e-2, 1e-1, 1, 1e1],
             'subsample': sp_uniform(loc = 0.2, scale = 0.8), 
             'reg_alpha': [0, 1e-1, 1, 2, 5, 7],
             'reg_lambda': [0, 1e-1, 1, 5, 10, 12]
             }
# training model with hypertuned lgbm
clf = LGBMClassifier(class_weight = 'balanced')
rand_clf = RandomizedSearchCV(clf, parameter_lgbm, return_train_score = True)
rand_clf.fit(x_train, y_train)
print(rand_clf.best_params_)
print(rand_clf.best_estimator_)

ฉันปรับไฮเปอร์พารามิเตอร์โมเดลนี้ด้วยพารามิเตอร์ที่แตกต่างกัน และได้ผลลัพธ์ที่ดีที่สุดด้วย n_estimators เป็น 1100 CV AUC ได้รับโดยใช้โมเดลนี้คือ 94.77 และ Train AUC เป็น 98.91 ซึ่งเป็นคะแนนที่ค่อนข้างดี

<แข็งแกร่ง>6. ผลลัพธ์รวม

ดังที่เราเห็นได้ชัดเจนว่าโมเดล LGBM ทำงานได้ดีที่สุด

<แข็งแกร่ง>7. ทดสอบการทำนาย

ในที่สุดทุกคน หลังจากทำงานมาทุกอย่างแล้ว การเดินทางของเราก็สิ้นสุดลงแล้ว ถึงเวลาสำหรับผลลัพธ์แล้ว เนื่องจากโมเดล LGBM ให้ผลลัพธ์ที่ดีที่สุดแก่เรา ฉันใช้สิ่งนี้เป็นโมเดลสุดท้ายของฉันในการส่งและการปรับใช้

<แข็งแกร่ง>8. การปรับใช้

ฉันได้ปรับใช้โมเดลสุดท้ายของฉันโดยใช้เฟรมเวิร์กเว็บ Flask รหัสที่สมบูรณ์สามารถพบได้ในบัญชี GitHub ของฉัน

งานในอนาคตและหมายเหตุ

การสร้างโมเดลในโลกแห่งความเป็นจริงเป็นกระบวนการวนซ้ำซึ่งจะมีการสรุปและปรับใช้โมเดลหลังจากดำเนินการขั้นตอนที่จำเป็นทั้งหมดเพื่อป้อนข้อมูลไปยังโมเดล ที่นี่ฉันได้รับคะแนน AUC ที่ดีโดยใช้โมเดล LGBM และคะแนนนี้สามารถเพิ่มขึ้นได้ วิทยาศาสตร์ข้อมูลเป็นเรื่องเกี่ยวกับการทดลอง สามารถเพิ่มคะแนนได้โดยทำการวิเคราะห์เพิ่มเติม สร้างคุณสมบัติใหม่จากคุณสมบัติที่มีอยู่ การเปลี่ยนแปลงคุณสมบัติ วิธีกำจัดคุณสมบัติที่แตกต่างกัน และไปที่ฟอรัมสนทนาบน Kaggle และใช้โมเดลการเพิ่มประสิทธิภาพที่แตกต่างกัน นอกจากนี้ เพื่อปรับปรุงคะแนนการเรียนรู้เชิงลึกให้ดียิ่งขึ้น สามารถใช้ทำการทดลองได้ ซึ่งจะช่วยในการปรับปรุงแบบจำลองเพื่อให้ได้ผลลัพธ์ที่ดีขึ้นอย่างต่อเนื่อง

หางานฉบับเต็มบน GitHub repo ของฉัน ที่นี่

ขอบคุณที่อ่านบล็อกของฉัน ฉันหวังว่าคุณจะชอบมัน

ข้อมูลอ้างอิง