一種基於群體特徵的比例偏差糾正方案
前言:
2018年10月,TalkingData組織了面向內部員工的第二屆黑客鬆大賽。其中一個賽題是“如何消除資料的各類偏差,從而產生無偏差的洞察?”針對該題目,本文作者所在的參賽小組提出了一個利用群體特徵進行預測的方案,並獲得了良好的泛化效果。該方案的重點在於將個體特徵轉化為群體特徵,利用群體特徵直接對群體屬性進行預測,達到簡化問題的目的。
本文將對這個方案進行分享,同時儘量採用通俗易懂的措辭和舉例,來降低理解問題的門檻,所以非資料科學專業的朋友也可以放心大膽地閱讀下去。
題目描述
由於網際網路使用者行為本身的差異,我們平常收集的移動端資料也會產生各種偏差,比如男性的數量要比女性多得多,青年/中年人的數量要比老人多得多。另一方面,在很多場景下,我們需要對某一個企業提供的人群包的人口屬性進行精準的洞察。 那麼,該如何基於自身帶有偏差的資料,來提供對於某個人群包的無偏差的描述?
題目翻譯
上面的描述可能過於專業,我們可以這麼理解:我們已經有一個人群的資料,而且知道這個人群的性別分佈,這部分資料稱為資料集A。某個企業呢,也有一個人群的資料,他們希望瞭解這個人群的男女比例,於是請我們來進行猜測,這些資料稱為資料集B。
一個比較常用的做法就是, 求A和B兩個資料集的交集,得到一個數據集C。 然後我們認為C就是A和B的一個取樣,可以用取樣中的男女比例去估計整體的男女比例,也就是說用C的男女比例去當做B的男女比例。
但這樣的估計結果往往不準。 首先,獲得這個取樣的方式太風騷,無法判定C是B的一個隨機取樣,而經過驗證C中的男女比例則更接近A中的男女比例。其次A中的男女比例和B中的男女比例往往差異很大,比如A中可能是0.7,但是B中可能是0.2,而在取樣C更接近A的情況下,我們得到的結果就與B相去甚遠了—— 即有偏差的洞察。
題目需求
比賽中已經提供3個數據集A、B、C。資料集A裡面的裝置我們都瞭解其性別;資料集B裡面我們不知道具體裝置的性別,但是知道該集合裡面的男女比例。我們的任務是推斷出資料集C中的男女比例。對於每一個數據集,都會提供資料集裡各裝置的特徵資訊,我們可以對這些裝置進行建模。
最樸素(Naïve)的解決思路:
1. 篩選裝置資訊特徵。
2. 由於已經知曉A中的性別情況,可以直接建模預測各裝置的性別。
3. 模型除錯(調參、交叉驗證、Averaging、Stacking等各種風騷操作)。
4. 預測資料集B各裝置的性別,求得男女比例,然後與給定值進行比較,不準確的話回到第三步進行除錯。
5. 預測C中的性別,算出比例,然後去睡覺。
評價
這個方法的優點很明顯,思路清晰,編碼方便,但是缺點也是非常顯著的。 首先是計算量較大,資料集A中有220,000人和超過400,000裝置特徵,在經過篩選後往往還有超過1,000+的特徵,於是有220,000 × 1000個entry。如果僅僅是做一次訓練的話還好,實際情況是我們還要多次訓練做交叉驗證來避免過擬合等,所以效率是一個大問題。在這裡我們僅考慮用Python scikit-learn的實現,不用Spark等炫技。
其次,個體的泛化能力有限。 像app很難去區別人的性別,也許存在一些app是和性別強相關的,但是覆蓋人數也很有限。更可怕的是,資料集A中的性別也不一定是準確的,資料探索表明其中包含500多個相同的TDID有不同的性別(安能辨我是雄雌),說明資料來源中肯定有髒資料和異常值。異常值就是比如使用者是男性,但為了玩“絕地求生”有人帶,於是將性別改成了女。這種異常值還是沒法檢測的,訓練出來的模型很可能就把玩“絕地求生”的人都當成了小姐姐。
於是(重點來了,敲黑板), 我們設想,能不能跳過對個體的性別預測,直接利用群體的男女比例去預測群體的男女比例呢?
我們現在只知道兩個群體的男女比例,一個是資料集A,還有一個是資料集B,也就是我們只有兩條訓練資料,這必然是遠遠不夠的。但是,我們知道資料集A中的各裝置的性別情況,我們可以利用抽樣的方式從A中得到各種各樣的群體,從而擴充我們的訓練集。 對於每一個群體,我們把裝置特徵從0或1的編碼轉變成該裝置特徵在這個人群中的佔比。 比如以前我們的訓練集是十個人,十個人中有七個人裝了某app,於是這七個人中的特徵“某app”為1,其他三個人為0。但是現在我們把這十條訓練資料壓成一條,特徵“某app”變成0.7,即安裝該app的人在這十個人中的佔比。
於是這個問題就轉換成了, 我們採用什麼抽樣方式,能夠獲得一個訓練集,使得訓練出來的模型能夠在資料集B上得到完美驗證?
一個更好的解決方案
隨機抽樣
隨機抽樣是最不靠譜的。 抽樣出來的各個群體的男女比例一定都是相同,且都等於A的男女比例。因為這些群體都來自於A,且獨立同分布。所以不管我們抽樣多少次,我們都只會有一個y值,這樣訓練出來的模型效果註定不好(我們猜測的,不信邪的勇士可以嘗試一下)。
按照比例對男女進行隨機抽樣
既然我們直接隨機抽樣的男女比例始終是一定的,那我們為什麼不能自己生成1000個不同的男女比例,然後根據這個男女比例去獲得對應的男女樣本呢?比如我們想形成一個男女比例為0.5的群體,群體大小定為10,000,那麼我們就需要5000個男性和5000個女性,於是我們就從A中的男性中隨機抽樣5000次,然後從A中的女性中隨機抽樣5000次,最後組合得到所需的群體,壓縮成一條訓練集。
這個辦法基本上可以迴避最樸素的辦法的缺點,第一,我們只抽取1000-2000個群體,所以我們訓練集的大小控制在1000*1000的範圍,可以切換著不同的姿勢隨意除錯訓練模型。預測的時候也只需要預測一行資料,而不必對個體進行預測,速度嗖嗖的加快。
第二,雖然每次抽樣出來的群體中可能包含異常值,但是這個過程會稀釋掉異常值,異常值的特徵在總體中的佔比必然是少數,所以對訓練模型的影響可以降到最小。當然不排除當時人品不好抽樣出了一堆玩“絕地求生”的“小姐姐”,這種情況下只需要在驗證集上測試一下效果即可,效果不好的話重新抽樣就行了。
特徵篩選
每個TDID都有一個特徵列表,分別由其安裝的app、手機品牌等移動裝置資訊組成。如果我們把所有的特徵全都平鋪開,計算每一個特徵在該人群中佔據的比例,就像上文所說,那麼我們將得到超過40萬列資料。
那麼我們首先想到的就是降維。然而無論是線性降維還是非線性降維,本質上都是將數學上的高維空間對映到低維空間,根本不適用於人群的移動裝置資料,做出來的預測太美而不敢想象。當然我們也沒有這麼去做,因為這麼多的entry根本裝不進記憶體,於是大膽猜想之後就不再去費力求證了。
不過憑藉常識,就能對人們常用的app有一些瞭解,所以這些特徵的頻次分佈肯定呈現超長尾,有大量的特徵佔不到人群的0.01%,所以我們只提取那些頻次佔比超過1%的特徵即可。執行結果讓我們很愉悅,只有1000來個特徵。
構建訓練集
接下來我們要做的就是從原有的訓練集中抽取不同的群體。首先想到的肯定是隨機抽樣,直接執行sample()就搞定了。然而,sample()函式的抽樣服從均勻分佈,也就是說,如果原有訓練集中男女比例是0.6,那麼無論抽樣多少個群體,他們的男女比例都會是0.6。
那麼我們可以手動改變這個比例,從訓練集中刻意抽取男女比例不為0.6的群體。操作方法也很容易,先產生一個0-1的隨機數來代表男女比例,然後根據這個男女比例計算出要抽出的群體的男女數量,再從訓練集中抽出對應數量的男女,組成新的群體即可,這樣一個比例就對應一個群體,就對應了一條訓練資料。當然還要根據上面選取的特徵來構建新的特徵,即該特徵在這個群體中所佔的比例。
深度學習模型的應用
隨後我們用PyTorch構建了一個包含兩層全連線的神經網路來進行模型的訓練。為什麼用神經網路呢,因為這樣比較有格調。至於為什麼是ANN不是CNN也不是RNN、LSTM等,畢竟格調還是有成本的,我們想盡量減低複雜度。事實上我們用Lightgbm或者XGBoost效果也是槓槓的,結果基本上都差不多,用傳統模型還需要去做Stacking的操作,用神經網路堆疊深度就輕鬆搞定了。
後續結果
其實在比賽中並沒有拿到令人滿意的結果,因為中間對接資料的時候出現了問題。後來修復了問題,並與其他資料集進行比較,這個方案實現的預測偏差確確實實是最小的(真實值:0.5,預測0.52,其餘方案0.6左右), 說明用群體去預測群體的想法是完全可靠的。 而且這個方法是可以擴充套件到群體的其他屬性標籤,比如工作型別佔比等,完全不侷限於性別。歸根結底,對移動資料難以做到個體精準預測,容易發生過擬合,而通過預測個體來估算群體會導致這種誤差放大。然而一個群體的裝置特徵是顯著的,通過這個方法可以規避個體差異,減少outlier對預測的影響,從而實現更精準的洞察。
推薦閱讀: