THE STANFORDOPEN POLICINGPROJECT part 2

Machine learning model part

A police officer makes a traffic stop in Sacramento. (Rich Pedroncelli / Associated Press)

Credit ข้อมูลจาก https://openpolicing.stanford.edu/

ท่านไหนสนใจภาคแรกไปอ่านกันก่อนได้ที่นี่ครับ

“THE STANFORDOPEN POLICINGPROJECT part1”

ในส่วนนี้จะเป็นการสร้าง model prediction จาก data ที่เราทำการ clean มาระดับนึงแล้ว ก่อนอื่นจึงต้องมาดูกันที่จุดมุ่งหมายก่อนว่าผลลัพธ์ที่ต้องการคืออะไรจาก model ที่จะสร้างขึ้นมา ซึ่งก็คือผลการ predict และการวัดผลความแม่นยำจากวิธีการที่เหมาะสมกับ model ที่สร้างขึ้น

มาลองคิดวิเคราห์ดูกันสนุกๆ ก่อน จากข้อมูลชุดนี้ที่เรามี สามารถนำไปใช้ประโยชน์อะไรได้บ้าง

  1. ด้านมืด ตัว model นี้ ถ้านำไปใช้ในกรณีผู้ต้องการทำสิ่งผิดกฏหมาย ลักลอบนำสิ่งผิดกฏหมายต่างๆ เช่น อาวุธ ยาเสพย์ติด สามารถรู้ได้ว่า ต้องเลือกใช้ transporter ประเภท ลักษณะ เชื้อชาติ เพศ แบบไหนถึงจะหลบเลี่ยงต่อการถูกจับ และถูกตรวจค้นได้มากที่สุด หรือ หลีกเลี่ยงการฝ่าฝืนกฏจราจร อันเพิ่มความเสี่ยงให้เกิดการถูกตรวจค้นและโดนค้นหาสิ่งผิดกฏหมายในยานพาหนะในที่สุด
  2. ด้านสว่าง ฝั่งนี้ก็จะเป็นประโยชน์แก่ตำรวจเอง สองประเด็นย่อย คือ หนึ่ง ทำให้ตำรวจไม่ bias หรือ อคติต่อคนจำพวกไหนจำพวกหนึ่งมากเกินไป และ ไม่ปล่อยปะหละหลวมกับคนอีกจำพวกหนึ่ง ทำให้การปฏิบัติหน้าที่มีความรอบคอบมากขึ้น สอง เมื่อการปฏิบัติหน้าที่มีความรอบคอบ และเท่าเทียมกันต่อทุกคนทุกความหลากหลายของกลุ่มคน ทำให้มีภาพลักษณ์ต่อสาธารณชนดีขึ้นไม่มีการเลือกปฏิบัติต่อกลุ่มคนบางกลุ่ม ป้องกันไม่ให้เกิดปัญหาตามมาเช่น ข่าวดังที่ติด hashtag ไปทั่วเรื่อง #blacklivematter นั่นเอง

ไปดูตามกันได้ตัว coding อย่างละเอียดที่นี่ Colab:

https://colab.research.google.com/drive/1ihKQDRJnbS7nYoQqPMH35X0Km_Gouzif?usp=sharing หรือผ่านทาง

Github: https://gist.github.com/TanabutT/9857971bd014d60efc75bffc3a12641e

ใช้ python ในกระบวนการสร้าง model และเตรียมข้อมูลเช่นเดิมครับ

ทำการดึงไฟล์ข้อมูลที่เราทำการ clean มาแล้ว เข้ามาและแสดงห้าแถวแรกของตาราง

raw = pd.read_csv('/content/drive/MyDrive/DS511 Data Science/ProjectFinalDS711_110_115/PoliceRI2020cleaned.csv',index_col= "date_stop_time")raw.head()
พรีวิวตารางห้าแถวแรก

ขั้นแรก เราต้องการให้ผลลัพท์คือ ค่า y_pred (ค่าการทำนายจาก model) จากข้อมูลของการปฏิบัติงานของตำรวจใน Rhode Island ที่เกิดขึ้นจริงและเก็บ record ไว้ ในครั้งนี้จะมาสนใจในการทำ model ว่าจากพื้นฐานข้อมูลที่มีอยู่นี้ลักษณะการปฏิบัติงานของตำรวจส่งผลต่อการ ตรวจค้นยานพาหนะในท้ายที่สุดหรือไม่ นั่นก็คือ เราให้ label ที่ต้องการจะ model บอกเราครับ เพราะฉะนั้น จากตารางที่เรามีข้างล่างจะเห็นว่า ควร drop เรื่องของการถูกจับกุมหลังตรวจค้นยานพาหนะทิ้งไปเนื่องจากเป็นผลที่เกิดหลังจากพบเจอสิ่งผิดกฏหมาย

ให้ label หรือผลลัพธ์ที่ต้องการจาก model ที่ได้คือ search_conducted ก็คือการตรวจค้นยานพาหนะ

ข้อมูลเป็นแบบตารางที่ทำการ clean มาเรียบร้อยแล้วแต่ยังต้องมีการจัดเรียงให้ง่ายต่อการป้อนเข้าสู่ model ของ ML: machine learning ต่อไป เราจะกำหนดจากจุดมุ่งหมายได้บน

ทำการสลับ column ให้ search_conducted ไปอยู่ column สุดท้ายโดยใช้ code

raw = raw[['district', 'driver_race', 'driver_gender', 'arrest_made','citation_issued', 'warning_issued', 'contraband_drugs','contraband_weapons', 'contraband_alcohol', 'frisk_performed','reason_for_stop', 'search_conducted']]raw.head()
search_conduct ไปไว้ column สุดท้ายแล้ว และ ยังมี arrest_madeคอลัมน์อยู่

ต่อไป คือการทำการ drop column “arrest_made” ควร drop เรื่องของการถูกจับกุมหลังตรวจค้นยานพาหนะทิ้งไปเนื่องจากเป็นผลที่เกิดหลังจากพบเจอสิ่งผิดกฏหมายโดยใช้ code ดังนี้

raw.drop('arrest_made', axis=1, inplace= True)raw.head()

ังจากที่ drop ผลการจับกุมไปแล้วก็จะมีตารางข้อมูลหน้าตาแบบนี้

เอาคอลัมน์ arrest_made ออก

ทดลองดึงข้อมูลออกมาดูจากแถวที่ 25 โดยไม่รวมเอา column ที่เป็น Label (ผลลัพธ์) ออกมาด้วย ว่าข้อมูลมีลักษณะอย่างไร

raw.iloc[25, :-1].valuesได้ output ดังนี้array(['X3', 'white', 'male', True, False, False, False, False, False, 'Speeding'], dtype=object)

ตาม output ที่ได้คือมาจะเรียงตาม column โดยเป็นรูปแบบของ array

โดยกำหนดค่า X จาก column แรกจนถึง column รองสุดท้าย

กำหนดค่า y คือ column สุดท้าย (search_conducted)

และทำการ print ค่าของ X และ y ออกมา และ print ขนาดของ X เพื่อดูจำนวน feature (หรือ จำนวน column นั่นแหละ) ที่ใช้ในการ train model

X = raw.iloc[:, :-1].valuesy = raw.iloc[:, -1].valuesprint("X :", X)print("y :", y)print("X shape :", X.shape)
ขนาดของ feature X มีทั้งหมด 10 feature

ขั้นตอนนี้เป็นการทำการแปลงข้อมูลของค่า X ที่เป็นข้อมูลไว้สำหรับเป็น Train Model โดยจะแปลงที่ column “district”, “driver_race”, “driver_gender”,
“reason_for_stop” ที่เป็นข้อมูล Categorical Data ให้แตกเป็น Column ย่อย ๆ
และเก็บข้อมูลเป็นแบบ Binary (เก็บค่าที่เป็น 0 หรือ 1 เท่านั้น)

โดยปกติเราสามารถใช้ ฟังก์ชั่น getdummy() ได้ แต่ในที่นี้ขอใช้เป็น preprocessing ใน sklearn มาอำนวยความสะดวกในการทำ คือการใช้ ColumnTranformer และ
OneHotEncoder

และจะเห็นได้ว่าหลังจากผ่านกระบวนการนี้ ตัว feature ของค่า X จะมีขนาดเพิ่มจาก 10 เป็น 31 features

โดยใช้ code ดังนี้

from sklearn.compose import ColumnTransformerfrom sklearn.preprocessing import OneHotEncoderct = ColumnTransformer(transformers=[('encoder', OneHotEncoder(), [0,1,2,9])], remainder='passthrough')X = np.array(ct.fit_transform(X))
ขนาด features ที่เพิ่มขึ้นของ X

ทดลองดึง row ที่ 25 เช่นเดิมเพื่อดูว่าข้อมูลเป็นอย่างไรหลังจากทำผ่านการใช้ OneHotencoder ลองนำไปเทียบกับ ที่เราดึงจากตารางก่อนผ่านกระบวนการดูได้

ลองนำไปเที่ยบกับ row ที่ 25 ที่เราดึงจากตารางก่อนผ่านกระบวนการดูได้

ขั้นตอนนี้เป็นการทำการแปลงข้อมูลของค่า y ที่เป็นข้อมูลไว้สำหรับเป็น Label model จากเดิมเป็นค่า boolean คือ True, False ให้เป็นค่า Binary (คือ 0 และ 1) โดยที่ 0 คือการไม่โดนตรวจค้นยานพาหนะ และ 1 คือโดนตรวจค้นยานพาหนะ

ใช้ code ดังนี้

from sklearn.preprocessing import LabelEncoderle = LabelEncoder()y = le.fit_transform(y)

ทำการแยกส่วนของ Training set และ Test set ด้วยการใช้ ฟังก์ชั่น train_test_split ในที่นี้ใช้ test_size 20 เปอร์เซ็นต์ของข้อมูลที่มี 80 เปอร์เซ็นต์ใช้ในการ train model

และลอง print ค่าของ X_train, X_test, y_train, y_test ออกมาดู และ ขนาดของค่าต่างๆ ก็สำคัญ ไว้ดูว่า มี feature ที่ป้อนไปถูกต้องเท่ากันหรือไม่ เมื่อมีปัญหามาดูในภายหลังจะง่ายต่อการหาวิธีการแก้ไข

from sklearn.model_selection import train_test_splitX_train, X_test , y_train, y_test = train_test_split(X,y, test_size=0.20, random_state= 1)
จากขนาดของข้อมูลแต่ละคู่ จะเห็นว่าจำนวน row ของ ตัวข้อมูลที่คู่กันระหว่าง X_train และ y_train นั้นเท่ากัน เช่นเดียวกับคู่ของ X_test และ y_test

การทำ Scaling ช่วยเพิ่มประสิทธิภาพให้กับการ train model ได้ การทำการ scaling ทำที่ขั้นตอนหลังจากแยกชุดข้อมูล ระหว่าง test และ train แล้วเพื่อป้องกันการรั่วของข้อมูล หรือ data leakage

และเช่นเดิม ลอง print ค่าของ X_train, X_test ออกมาดู และ ขนาดของค่าต่างๆ ก็สำคัญ ใช้ code ในการทำ scaling ดังนี้

from sklearn.preprocessing import StandardScalersc = StandardScaler()X_train = sc.fit_transform(X_train)X_test = sc.fit_transform(X_test)
จากขนาดของข้อมูลแต่ละคู่ จะเห็นว่าจำนวน feature ยังเท่าเดิมคือ31 และจำนวน row ยังเท่าเดิมกับก่อนหน้าการทำ scaling ทั้งของ X_train และ X_test

ลอง ใช้ KNN model เนื่องจากในทางทฤษฏีแล้วตัวโมเดลตัวนี้ทำงาน และ predict ช้า จึงแยกมาทำตัวเดียวก่อนครับ สร้าง KNN model ด้วย code ดังนี้

from sklearn.neighbors import KNeighborsClassifierknnclf = KNeighborsClassifier(n_neighbors=5)knnclf.fit(X_train, y_train)

และวัดผลจากคะแนนต่างๆ เช่น accuracy score และ F1_score ของ KNN model

from sklearn.metrics import confusion_matrix, accuracy_score, ConfusionMatrixDisplay, f1_scorey_pred = knnclf.predict(X_test)cm_knn = confusion_matrix(y_test, y_pred)print(cm_knn)print("accuracy_score model KNN :",accuracy_score(y_test, y_pred))print("f1_score model KNN :",f1_score(y_test, y_pred))cmd = ConfusionMatrixDisplay(confusion_matrix=cm_knn, display_labels=['No','Yes'])cmd.plot()
KNN ทำงานได้ช้ามากเมื่อขนาดของข้อมูลใหญ่มากแบบนี้ ใช้เวลา predict ประมาณ 1 ชั่วโมง

การใช้ KNN ใช้เวลาในการรัน train และเมื่อ train เสร็จ การ predict ก็ทำงานได้ช้ามากเมื่อขนาดของข้อมูลใหญ่มากแบบนี้ ประมาณ 1 ชั่วโมง

ต่อมาจึงลองใช้ หลาย model เพื่อดูผลคร่าวๆ ของการเรียนรู้ ที่ค่า hyperparameter ยังเป็นค่าเริ่มต้นอยู่ (default) ด้วย code ดังนี้

รูป output แบ่งตามชื่อ model ที่ใช้

จากการวัดผลค่าต่างๆ เนื่องจากคะแนนต่างๆ มีความใกล้เคียงกัน และ ด้วยความที่ logistic regression มีความซับซ้อนน้อยกว่า หลังจากนี้จะเลือกใช้ Logistic Regression model เพื่อทำการ Tune hyperparameter และวัดผลของ model ต่อไปครับ

Training the Logistic Regression model on the Training set

ทำการ fit เพื่อ train model ดังนี้

from sklearn.linear_model import LogisticRegressionclassifier = LogisticRegression(random_state=1)classifier.fit(X_train, y_train)

ลองใส่ชุดข้อมูลใหม่จากคนขับใหม่ที่ลองสร้างเองขึ้นมาครับว่า model ของเราใช้งานได้ และ ทำนายออกมาว่าจะโดนตรวจค้นยานพาหนะหรือไม่ และเมื่อสร้างข้อมูลขึ้นมาใหม่ จะต้องทำการ OneHotencoder กับข้อมูลใหม่นี้ด้วยให้ตรงกับ shape ของการป้อนเข้าไปใส่ให้ model

สมมติคนขับขึ้นมาใหม่และทำการ OneHotencoder

ต้องทำการ scaling ก่อนเข้า model ด้วย

ทำการ scaling ก่อนป้อนเข้าโมเดล

แล้วก็ทำการ ป้อนไปให้ model ที่ผ่านการ train มาแล้ว predict

ค่าเป็น 0 แสดงว่า predict ว่าไม่โดนตรวจค้น ถ้าดูจากความน่าจะเป็นที่ได้ที่จะโดนตรวจค้น มีเพียง 0.0001939 เท่านั้น

Predicting the Test set results

มาลองทดสอบวัดผลของ model โดยใช้ Test set ที่แยกไว้ตั้งแต่แรก ซึ่งเรามีผลลัพธ์ที่เกิดขึ้นจริงมาเปรียบเทียบกับโมเดล ทำให้เราสามารถวัดประสิทธิภาพความแม่นยำ ความเที่ยงตรง และค่าการวัดผลรูปแบบต่างๆ ได้จาก Test set นี้ ดังภาพด่านล่าง

ตัวแรกคือ predict และ ตัวที่สองคือค่าจริง ที่คนโดนตรวจค้นในรถหรือไม่โดน
0 คือไม่โดน
1 คือโดนตรวจค้นรถ

แบบนี้จะเทียบกันก็ดูยาก ต้องใช้วิธีการวัดผลแบบอื่นเพราะค่าที่ predict มีจำนวนเยอะมากหลาย row เลยทีเดียว

Making the Confusion Matrix

ใช้ Confusion Matrix มาช่วยในการ evaluation

Confusion Matrix ดูมีประสิทธิภาพดีกับ Test set

Display classification performance metrics

หาค่าประสิทธิภาพอื่นๆของ classification model ของตัวนี้เพิ่มเติม

accuracy และ precision ดีมาก

Visualizing the ROC curve

เป็นการวัดประสิทธิภาพที่ดีตัวหนึ่งของ binary classification

ROC curve ของการตรวจค้นยานพาหนะ เป็นการนำเอา True Positive rate plot with False Positive Rate

In fact, any point on the blue line corresponds to a situation where True Positive Rate is equal to False Positive Rate.

All points above this line correspond to the situation where the proportion of correctly classified points belonging to the Positive class is greater than the proportion of incorrectly classified points belonging to the Negative class.

หมายความว่า ยิ่งเส้นสีส้มของเราห่างออกจากเส้นสีฟ้าไปข้างบนมากเท่าไหร่ก็แสดงว่า model ของเรา ทำการแยกแยะ ได้อย่างถูกต้องกว่า เช่น สมมติว่า มีของผิด กฏหมายในรถ ถ้าทำนายว่าโดนตรวจค้นแน่ๆ ก็จะกลัวก็อาจจะไม่ขับรถวันนี้ แต่ถ้า ทำนายว่าไม่โดนจับแน่แต่ทำนายผิด สุดท้ายแล้วเป็นความหวังที่คิดว่าไม่โดนตรวจค้น พอไปขับรถจริงโดนเรียกตรวจค้นก็เจอสิ่งผิดกฏหมายในรถ False Positive นั้นน่ากลัว

ดังคำกล่าวของ “False hopes are more dangerous than fears.”–J.R.R. Tolkein

ดูได้จากการรัน code และ ภาพข้างล่างดังนี้

ROC curve ของการตรวจค้นยานพาหนะ เป็นการนำเอา True Positive rate plot with False Positive Rate

Applying k-Fold Cross-Validation

เพื่อดูว่าการแบ่งชุดข้อมูลในการ train model ดีหรือไม่ โดยจะได้ออกมาเป็นค่าเฉลี่ยของ Accuracy ที่ 98.80 % และ Standard deviation น้อยมาก 0.03 %

Applying Grid Search to find the best model and the best parameters

ทำเพื่อหาค่า ปรับจูน hyperparameter ให้ได้ model ที่ดีที่สุด ใช้ code ดังนี้ และต้องการจะวัดค่าประสิทธิภาพของ model ด้วย ROC curve แทนการใช้ Accuracy จึ่งแทนค่า ที่ scoring = “roc_auc”

from sklearn.model_selection import GridSearchCVparameters = {'C': [0.0001, 0.0002, 0.0004, 0.0006, 0.0008, 0.001], 'penalty':['l1','l2','elasticnet']}grid_search = GridSearchCV(estimator = classifier,param_grid = parameters,scoring = 'accuracy',cv = 10,n_jobs = -1)grid_search.fit(X_train, y_train)best_accuracy = grid_search.best_score_best_parameters = grid_search.best_params_print("Best accuracy: {:.2f} %".format(best_accuracy*100))print("Best Parameters:", best_parameters)

จากการทำ Grid Search เพื่อปรับจูน hypermeter ที่เหมาะสมเพื่อการใช้งาน
ทำให้ผลที่ออกมาถูกต้องแม่นยำ และมีประสิทธิภาพมากยิ่งขึ่น โดย hypermeter เหมาะสมที่ได้คือ ‘C’ = ‘0.001’ และ penalty = ‘L2’

the best_parameters for best roc_auc is here!

ได้ค่าปรับจูนสำหรับ classifier model ออกมาแล้ว ลองนำไป train ให้กับ logistic regression model ของเราอีกรอบ

ดูจากรูปจะเห็นว่าค่า hyperparameter เปลี่ยนแล้ว

ใช้ Confusion Matrix มาช่วยในการ evaluation

จะเห็นว่ารูป Confusion Matrix และผลลัพธ์ที่ทำนาย y_pred2 เมื่อเทียบกับที่ทำนาย y_pred ไว้ ผลออกมาเท่ากันเลย

หากดูเส้นกราฟนี้แล้วจะสามารถพิจารณาได้ว่าผลการทำนายของเรานั้นดีแค่ไหนโดยทั่วไปจะถือว่าหากกราฟยิ่ง ชิดด้านบนมากก็ยิ่งแปลว่าทำนายได้ดี แต่หากกราฟเป็นเส้นตรงจะแสดงว่าไม่ดี กราฟชิดด้านบนมากหมายความว่าพื้นที่ใต้กราฟมาก ค่าพื้นที่ใต้กราฟ ROC นี้ถูกเรียกว่า AUC (area under curve)

ตัวโมเดล roc_auc ทำได้ดีที่สุดตาม best_parameters ที่ได้ปรับจูนแล้ว

ประโยชน์จากจุดมุ่งหมายข้างบน และ finding ที่ได้จากข้อมูลการปฏิบัติหน้าที่ของตำรวจใน Rhode Island State

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

ดังเช่นการเรียกตรวจจากการฝ่าฝืนความเร็วนั้น คนขับที่เป็นคนผิวดำจะโดนเขียนใบสั่งมากกว่า 20% ของคนผิวขาว และเป็นคนขับเชื้อสายละตินก็จะโดนเขียนใบสั่งมากกว่า 30 % ของคนผิวขาวในข้อหาฝ่าฝืนความเร็ว

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

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

ส่วนอัตราการตรวจค้นจากเชื้อชาติที่มีอิทธิพลในการอคติทำให้อัตราการตรวจค้นพ้นสิ่งที่ผิดกฏหมายก็มากขึ้นด้วย ซึ่งไม่ได้หมายความว่าสิ่งที่ผิดกฏหมายจะอยู่กับคนผิวดำเป็นอัตราส่วนมากกว่า เพียงแต่ว่าอัตราการตรวจค้นที่กระทำต่อคนผิวขาวนั้นน้อยกว่า จากตรงนี้ ข้อมูลทำให้เราเห็นได้ชัดเจนว่า สองมาตรฐานในการปฏิบัติงานของตำรวจนั้นมีอยู่จริง

1.ถ้านำไปใช้ที่ผิดศีลธรรม ทำให้ผู้ที่ต้องการกระทำผิดกฎหมายสามารถเลือกใช้ Transporter ตามประเภท, ลักษณะ, เชื้อชาติ, เพศแบบไหนที่จะสามารถหลีกเลี่ยงการจับกุม หลีกเลี่ยงการถูกตรวจค้น หรือแม้กระทั่งหลีกเลียงการฝ่าฝืนกฏจราจรให้ได้มากที่สุด เพื่อลดความเสี่ยงที่จะทำให้เกิดการถูกตรวจค้นหรือโดนค้นหาสิ่งผิดกฎหมายในยานพาหนะในที่สุุด

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

Data Journey : Self developing and learning on new technology about AI, automation and data related.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store