跳到主要內容
工程的博客

使用SHAP和機器學習檢測數據偏差

機器學習和SHAP可以告訴我們開發者工資和性別工資差距之間的關係

2019年6月17日 數據科學與機器學習

分享這篇文章

StackOverflow年度開發者調查今年早些時候結束,他們大方地公布了2019年(匿名)的分析結果。它們為世界各地的軟件開發人員提供了豐富的體驗——他們最喜歡的編輯器是什麼?有多少年的工作經驗?製表符或空格?最關鍵的是,薪水。軟件工程師的薪水是不錯的,有時還會讓人熱淚盈眶,成為新聞。

科技行業也痛苦地意識到,它並不總是能實現其所謂的精英理想。薪酬並不是一個純粹的能力函數,一個又一個故事告訴我們,名牌學校、年齡、種族和性別等因素都會對薪酬等結果產生影響。

機器學習能做的不僅僅是預測嗎?它能否解釋工資,從而突出這些因素可能造成不受歡迎的工資差異的情況?本例將概述如何使用SHAP (SHapley加法解釋)為了發現其預測可能令人擔憂的個別實例,然後深入挖掘數據導致這些預測的具體原因。

模型偏倚還是數據偏倚?

雖然這個主題通常被描述為檢測“模型偏差”,但模型隻是它所訓練的數據的鏡像。如果模型是“有偏見的”,那麼它是從數據的曆史事實中學習到的。模型本身不是問題;它們是一個分析數據以尋找偏見證據的機會。

解釋模型並不新鮮,大多數庫都可以評估模型輸入的相對重要性。這些是對投入效果的總體看法。然而,一些機器學習模型的輸出具有高度的個人效應:你的貸款被批準了嗎?你會得到經濟援助嗎?你是一個可疑的旅行者嗎?

事實上,StackOverflow提供了一個方便的計算器根據其調查估計自己的期望工資。我們隻能推測這些預測的總體準確性,但開發者特別關心的是他或她自己的前景。

正確的問題可能不是,數據是否暗示了整體的偏見?而是,數據是否顯示了偏見的個別實例?

評估StackOverflow調查數據

值得慶幸的是,2019年的數據是幹淨的,沒有數據問題。它包含了大約8.8萬名開發人員對85個問題的回答。

本例隻關注全職開發人員。數據集包含大量相關信息,如工作年限、教育程度、角色和人口統計信息。值得注意的是,該數據集不包含獎金和股權信息,隻包含工資信息。

此外,它還收集了對區塊鏈、fizz buzz以及調查本身的態度等廣泛問題的回答。這些因素在這裏被排除在外,因為它們不太可能反映經驗和技能應該確定補償。同樣,為了簡單起見,它也隻關注美國的開發者。

在建模之前,數據需要進行更多的轉換。有幾個問題允許多種回答,比如“作為開發者,你對工作效率最大的挑戰是什麼?”這些單一的問題會產生多個是/否的回答,需要分解成多個是/否的特征。

一些選擇題,比如“你所在的公司或組織大約有多少員工?”做出這樣的回應“2 - 9員工”.這些是有效的連續值,將它們映射回推斷的連續值(如“2”)可能是有用的,這樣模型就可以考慮它們的順序和相對大小。不幸的是,這種翻譯是手動的,需要一些判斷。

Apache火花可以完成此操作的代碼在附帶的筆記本,為感興趣的人。

使用Apache Spark選擇模型

有了機器學習更友好的數據形式,下一步是擬合一個回歸模型,根據這些特征預測工資。經過Spark過濾和轉換後的數據集本身隻有4MB,包含來自大約12,600名開發人員的206個特性,可以輕鬆地放入內存中手表上的數據幀,更不用說服務器了。

xgboost(一個流行的梯度增強樹包)可以在幾分鍾內在一台機器上為這些數據擬合一個模型,而不需要Spark。xgboost提供許多影響模型質量的可調“超參數”:最大深度、學習率、正則化等等。與其猜測,簡單的標準實踐是嚐試這些值的大量設置,並選擇產生最準確模型的組合。

幸運的是,這正是Spark重新發揮作用的地方。它可以並行地構建數百個這樣的模型,並收集每個模型的結果。因為數據集很小,所以很容易將其廣播給工作者,創建這些超參數的一堆組合進行嚐試,並使用Spark應用相同的簡單非分布式xgboost可以使用每個組合在本地為數據構建模型的代碼。

...deftrain_model參數個數):(max_depth, learning_rate, reg_alpha, reg_lambda, gamma, min_child_weight) = paramsxgb_regressor = xgbregresor (objective=“注冊:squarederror”、max_depth = max_depth \Learning_rate = Learning_rate, reg_alpha=reg_alpha, reg_lambda=reg_lambda, gamma=gamma,\min_child_weight = min_child_weight n_estimators =3000、base_score = base_score \importance_type =“total_gain”random_state =0xgb_model = xgb_regresor .fit(b_X_train. fit)值、b_y_train.value \eval_set = [(b_X_test。價值,b_y_test.value)] \eval_metric =“rmse”early_stopping_rounds =30.n_estimators =len(xgb_model.evals_result () (“validation_0”] [“rmse”])y_pred = xgb_model.predict(b_X_test.value)Mae = mean_absolute_error(y_pred, b_y_test.value)Rmse = sqrt(mean_squared_error(y_pred, b_y_test.value))返回(params + (n_estimators,), (mae, rmse), xgb_model)
              ...Max_depth = np.unique(np.geomspace(3.7num =5, dtype = np.int32)) .tolist ()Learning_rate = np.unique(np.around(np.geomspace(0.010.1num =5),小數=3.) .tolist ()Reg_alpha = [0+ np.unique(np.around(np.geomspace(150num =5),小數=3.) .tolist ()Reg_lambda = [0+ np.unique(np.around(np.geomspace(150num =5),小數=3.) .tolist ()Gamma = np.unique(np.around(np.geomspace(520.num =5),小數=3.) .tolist ()Min_child_weight = np.unique(np.geomspace(530.num =5, dtype = np.int32)) .tolist ()並行性=128Param_grid = [(choice(max_depth), choice(learning_rate), choice(reg_alpha),\選擇(reg_lambda),選擇(gamma),選擇(min_child_weight))_範圍(並行)Params_evals_models = sc.parallelize(param_grid, parallelism)。地圖(train_model) .collect ()

這將創造出許多模型。為了跟蹤和評估結果,mlflow可以記錄每一個指標和超參數,並在筆記本的實驗中查看它們。在這裏,將多次運行中的一個超參數與得到的精度(平均絕對誤差)進行比較:

模型誤差與超參數<br />的MLflow散點圖

在保留的驗證數據集上顯示最小誤差的單個模型是值得關注的。在平均工資約為11.9萬美元的情況下,該研究得出的平均絕對誤差約為2.8萬美元。並不可怕,盡管我們應該意識到模型隻能解釋大多數關於工資的變化。

解釋xgboost模型

雖然這個模型可以用來預測未來的工資,但問題是這個模型對數據說了什麼。在準確預測薪水時,哪些特征最重要?的xgboost模型本身計算特征重要性的概念:

進口mlflow.sklearnbest_run_id =“…”Model = mlflow.sklearn.load_model(“運行:/+ best_run_id +“/ xgboost”排序((郵政編碼(模型。feature_importances_, X.columns)), reverse=真正的):6

對機器學習預測nxgboost模型中各因素的重要性進行排序。< br / >

諸如專業編碼年限、組織規模和使用Windows等因素是最“重要的”。這很有趣,但很難解釋。這些價值反映的是相對的重要性,而不是絕對的重要性。也就是說,這種影響不是用美元來衡量的。這裏的重要性(總收益)的定義也具體到如何構建決策樹,並且很難映射到直觀的解釋。這些重要的特征甚至不一定與薪水呈正相關。

更重要的是,這是一種“全局”的觀點,即總體上功能有多重要。性別和種族等因素直到後來才出現在這個列表上。這並不意味著這些因素不重要。首先,特征可以相互關聯或相互作用。性別等因素可能與樹選擇的其他特征相關,這在一定程度上掩蓋了它們的影響。

更有趣的問題不是這些因素在整體上是否重要——它們的平均影響可能相對較小——而是它們在某些個別情況下是否有顯著影響。在這些例子中,模型告訴我們一些關於個人經驗的重要信息,而對這些人來說,經驗才是最重要的。

為開發人員級解釋應用包SHAP

幸運的是,在過去五年左右的時間裏,在個體預測水平上出現了一套理論上更合理的模型解釋技術。他們都是"上海apley一個dditive交貨p,並且方便地在Python包中實現世鵬科技電子

對於任何模型,這個庫都會從模型中計算“SHAP值”。這些值很容易解釋,因為每個值都是一個特征對預測的影響。這裏的SHAP值為1000表示“解釋工資+ 1000美元的預測工資”。計算SHAP值的方法也試圖隔離相關性和交互。

進口世鵬科技電子explainer = shape . treeexplainer(模型)Shap_values =解釋器。shap_values(X, y=y.values)

SHAP值也是為每個輸入計算的,而不是整個模型,因此這些解釋可單獨用於每個輸入。對於每個預測,它還可以從每個特征的主要影響中單獨估計特征相互作用的影響。

可解釋的AI:揭示特征的整體效果

開發人員級別的解釋可以通過簡單地平均它們的絕對值,聚合成對整個數據集中的特性對工資影響的解釋。SHAP對總體最重要特性的評估是類似的:

根據絕對SHAP值評估特征重要性。< br / >

SHAP值也說明了類似的情況。首先,SHAP能夠用美元來量化對工資的影響,這大大改善了對結果的解釋。上麵是一個圖絕對每個功能對開發者預期工資的影響。多年的專業編碼經驗仍然占主導地位,平均約1.5萬美元的薪酬效應。

用SHAP值檢驗性別的影響

我們專門研究了性別、種族和其他因素的影響,這些因素本身可能根本不能預測工資。這個例子將研究性別的影響,盡管這並不意味著這是唯一或最重要的偏見類型。

性別並不是二元的,調查中分別出現了“男性”、“女性”、“非二元、性別酷兒或性別不一致”以及“跨性別”的回答。(請注意,雖然調查也單獨記錄了關於性的回答,但這裏不考慮這些。)SHAP計算了這些因素對預期工資的影響。對於男性開發者(隻認為自己是男性)來說,性別的影響不僅僅是男性的影響,還包括不認為自己是女性、變性人等等。

SHAP值讓我們可以讀出這些影響的總和,為開發人員識別為四個類別中的每一個:

舉例SHAP值解釋性別對預測工資的影響<br />

男性開發者的收入範圍從230美元到890美元不等,平均收入約為225美元,而女性開發者的收入範圍則更大,從4260美元到690美元不等,平均收入為1320美元。跨性別和非二元開發者的結果是相似的,盡管沒有那麼消極。

在評估這意味著什麼時,重要的是要回顧這裏的數據和模型的局限性:

  • 相關性不是因果關係;“解釋”預測的薪資隻是暗示,但不能證明某個特征直接導致薪資升高或降低
  • 這個模型並不完全準確
  • 這隻是1年的數據,且僅來自美國開發者
  • 這隻反映了基本工資,不包括獎金或股票,後者的變化可能更大

使用SHAP可視化與性別交互的功能

SHAP庫提供了有趣的可視化,利用其隔離特性交互效果的能力。例如,上麵的數值表明,男性開發人員的薪水預計會比其他人略高,但還有其他原因嗎?像這樣的依賴關係圖可以有所幫助:

使用SHAP可視化與性別交互的特征<br />

點是開發者。左邊是那些不認為自己是男性的開發者,右邊是那些認為自己是男性的開發者,主要是那些認為自己隻是男性的開發者。(為了清晰起見,這些點是水平隨機分布的。)y軸是SHAP值,即男性或非男性對每個開發人員預期薪酬的解釋。如上所述,那些不認為自己是男性的人總體上表現出負的SHAP值,而且變化很大,而其他人則始終表現出小的正SHAP值。

方差背後是什麼?給定的值,SHAP可以選擇第二個影響最大的特征,在這裏,識別為男性或非男性。它在“你的工作有多大的結構和計劃?”的問題上選擇了“我做最重要或最緊急的事情”的答案。在男性開發者中,以這種方式回答問題的人(紅點)的SHAP值略高。在其他類型中,效果比較複雜,但似乎具有較低的SHAP值。

解釋留給讀者,但也許是這樣的:在這種意義上感到賦權的男性開發人員也享受著略高的薪水,而其他開發人員則享受著低薪工作?

探索具有巨大性別影響的實例

調查那些薪水受到最大負麵影響的開發者怎麼樣?就像我們可以從整體上看到與性別相關的功能所產生的影響一樣,我們也可以搜索那些擁有與性別相關功能的開發者最大對預期工資的影響。這個人是女性,效果是負麵的。根據該模型,由於性別原因,她的年收入預計會減少約4260美元:

使用Python SHAP來可視化一個開發人員<br />的預測工資的解釋

她的預期工資略高於15.7萬美元,在這種情況下是準確的,因為她實際報告的工資是15萬美元。

影響預期工資的三個最積極和最消極的特征是:

  • 大學學曆(僅限)(+ 18,200美元)
  • 有10年專業經驗(+ 9,400美元)
  • 東亞人(+$9,100)
  • ...
  • 每周工作40小時(- 4000美元)
  • 非男性(- 4,250美元)
  • 在100-499人的中型企業工作(- 9,700美元)

考慮到非男性身份對預期薪酬的影響程度,我們可能會在此停止,並在線下調查該案例的細節,以更好地了解該開發人員周圍的環境,以及她的經驗或薪酬,或兩者都需要改變。

使用SHAP值解釋交互

有更多的細節可在- 4260美元。SHAP可以將這些特性的效果分解為交互。認定為女性對預測的總影響可以分解為認定為女性的影響而且作為一名工程經理,而且使用Windows等。

性別因素本身對預測工資的影響加起來隻有大約- 630美元。相反,SHAP將性別的大部分影響分配給與其他特征的交互作用:

Gender_interactions = interaction_values[gender_feature_locs]。總和(軸=0Max_c = np.argmax(gender_interactions)Min_c = np.argmin(性別交互)打印(X.columns [max_c])打印(gender_interactions [max_c])打印(X.columns [min_c])打印(gender_interactions [min_c])
              DatabaseWorkedWith_PostgreSQL110.64005Ethnicity_East_Asian-1372.6714

認定自己是女性並在PostgreSQL工作對薪資預測有輕微的積極影響,而認定自己是東亞人則對薪資預測有更消極的影響。在這個上下文中,在這種粒度級別上解釋這些值是困難的,但是,這種額外級別的解釋是可用的。

使用Apache Spark應用SHAP

給定模型,每一行的SHAP值都是獨立計算的,所以這也可以與Spark並行完成。下麵的示例並行計算SHAP值,並類似地定位與性別相關的SHAP值過大的開發人員:

X_dfpruned_parsed_df.drop(“ConvertedComp”).repartition (16X_columnsX_df.columnsdef add_shap ():rows_pdpd。DataFrame (、列X_columns)shap_valuesexplainer.shap_values (rows_pd。((“被告”),軸下降1))返回([int(rows_pd["被"][我]))+浮動(f)fshap_values[我]]))範圍(len (shap_values)))shap_dfX_df.rdd.mapPartitions (add_shap) .toDF (X_columns)effects_dfshap_df。\withColumn(“gender_shap坳(“Gender_Woman”)+坳(“Gender_Man”)+坳(“Gender_Non_binary__genderqueer__or_gender_non_conforming”)+坳\(“反式”))選擇(“被”、“gender_shap”)top_effects_dfeffects_df.filter (腹肌(坳(“gender_shap”))> =2500) .orderBy(“gender_shap”)

與性別相關的SHAP值為負的開發人員的示例表,與Spark並行計算。

聚類SHAP值

當有大量的預測需要用SHAP進行評估時,應用Spark是有利的。有了這樣的輸出,還可以使用Spark將結果與以下內容聚類:角平分線k - means

彙編程序VectorAssembler (inputCols[ccto_review_df。列如果c! =“被申請人”),\outputCol“特性”)assembled_dfassembler.transform (shap_df) .cache ()clusterer運算BisectingKMeans () .setFeaturesCol(“特性”).setK (50) .setMaxIter (50) .setSeed (0cluster_modelclusterer.fit (assembled_df)transformed_dfcluster_model.transform (assembled_df)。選擇(“被”,“預測”)

與性別相關的總體SHAP影響最為負麵的群集可能需要進一步研究。集群中這些應答者的SHAP值是什麼?集群的成員相對於整個開發人員群體是什麼樣子的?

min_shap_cluster_dftransformed_df。f我lter("prediction = 5").\加入(effects_df,“被申請人”)。\加入(X_df,“被申請人”)。\選擇(gender_cols) .groupBy (gender_cols)。() .orderBy (gender_cols)all_shap_dfX_df.select (gender_cols) .groupBy (gender_cols)。() .orderBy (gender_cols)expected_ratiotransformed_df。f我lter("prediction = 5").()/X_df。()顯示器(min_shap_cluster_df.join (all_shap_dfgender_cols)。\withColumn(“比率”(min_shap_cluster_df(“計數”)/all_shap_df["數"])/expected_ratio)。\orderBy(“比例”))

示例表顯示了在與性別相關的SHAP值最負的集群中性別身份的相對流行率。

例如,在這一群體中,女性開發人員的比例幾乎是整體開發人員比例的2.8倍。考慮到前麵的分析,這並不令人驚訝。可以進一步調查這一群體,以評估導致整體預期工資較低的其他特定因素。

結論

使用SHAP的這種類型的分析可以用於任何模型,也可以在一定規模上運行。作為一種分析工具,它把模型變成了數據偵探,讓個體實例浮出水麵,這些實例的預測表明它們值得更多的研究。SHAP的輸出很容易解釋,並產生直觀的圖形,業務用戶可以逐個評估這些圖形。

當然,這種分析並不局限於檢查性別、年齡或種族偏見的問題。更簡單地說,它可以應用於客戶流失模型。在這裏,問題不僅僅是“客戶會流失嗎?”而是“客戶為什麼流失?”由於價格原因而取消服務的客戶可能會得到折扣,而由於使用量有限而取消服務的客戶可能需要追加銷售。

最後,這種分析可以作為驗證過程的一部分運行,為機器學習模型帶來更大的透明度。模型驗證通常關注模型的整體準確性。它還應該關注模型的“推理”,或者哪些特征對預測貢獻最大。使用SHAP,它還可以幫助檢測個體數量過多預測的解釋與整體特征的重要性不一致。

免費試用Databricks

相關的帖子

看到所有數據科學與機器學習的帖子
Baidu
map