Q
数字とデータの世界で、私たちは揺れ動きます。誰が大々的に収益を上げるのかを測定するモデル、しかし!賢い者が、ある策略を使って、あるグループの予測を引き上げました。このずる賢い者はコードの中で巧妙に舞い、一つのグループの運命を引き上げました。しかし心配はいりません、私たちはこの変装を見破るでしょう。そして、どのグループが利益を得ていたのかを明らかにします。
(どのサブグループが体系的に誤分類されているかを見つけてください。)
こちらの記事もおすすめ
初期設定とデータの取得
import requests
input_data = [0]
def query(input_data):
response = requests.post('http://cluster1.advml.com/score', json={'data': input_data})
return response.json()
- ここではrequestsモジュールをインポートしています。これはHTTPリクエストを行うために使用されます。
- query関数は、特定のエンドポイント(
http://cluster1.advml.com/score
)に対してPOSTリクエストを送信し、応答をJSON形式で返します。
!pip -q install skops
!pip -q install scikit-learn==1.3.0
ここでskopsと特定バージョンのscikit-learnをインストールしています。これらは機械学習モデルの操作に必要です。
import skops.io as sio
import sklearn
import pandas as pd
import itertools
pipe = sio.load("/kaggle/input/ai-village-capture-the-flag-defcon31/cluster1/census_model.skops", trusted=True)
data = pd.read_csv("/kaggle/input/ai-village-capture-the-flag-defcon31/cluster1/census.csv").sort_values('id').reset_index(drop=True)
ここで機械学習モデル(pipe)とデータセット(data)を読み込んでいます。
pandasを使用してCSVファイルをデータフレームに変換し、IDによってソートしています。
データの処理
prediction = pipe.predict(data)
data['pos_missclassified'] = prediction != data.income
data['counter'] = 1
- モデルpipeを使用してデータセットdataの予測を行い、予測結果をpredictionに保存します。
- 実際の収入(income)と予測結果を比較し、誤分類されたデータポイントをpos_missclassified列に記録します。
- 各行に対してカウンター(counter)を設定します。
id age workclass education.num marital.status \
0 0 90 NaN 9 Widowed
1 1 82 Private 9 Widowed
2 2 66 NaN 10 Widowed
3 5 34 Private 9 Divorced
4 6 38 Private 6 Separated
... ... ... ... ... ...
16276 32551 43 Self-emp-not-inc 10 Married-civ-spouse
16277 32553 43 Private 11 Married-civ-spouse
16278 32554 32 Private 14 Never-married
16279 32555 53 Private 14 Married-civ-spouse
16280 32560 22 Private 9 Never-married
occupation relationship race sex \
0 NaN Not-in-family White Female
1 Exec-managerial Not-in-family White Female
2 NaN Unmarried Black Female
3 Other-service Unmarried White Female
4 Adm-clerical Unmarried White Male
... ... ... ... ...
16276 Craft-repair Husband White Male
16277 Sales Husband White Male
16278 Tech-support Not-in-family Asian-Pac-Islander Male
16279 Exec-managerial Husband White Male
16280 Adm-clerical Own-child White Male
capital.gain capital.loss hours.per.week native.country income \
0 0 4356 40 United-States <=50K
1 0 4356 18 United-States <=50K
2 0 4356 40 United-States <=50K
3 0 3770 45 United-States <=50K
4 0 3770 40 United-States <=50K
... ... ... ... ... ...
16276 0 0 50 United-States <=50K
16277 0 0 45 United-States <=50K
16278 0 0 11 Taiwan <=50K
16279 0 0 40 United-States >50K
16280 0 0 20 United-States <=50K
pos_missclassified counter
0 False 1
1 True 1
2 False 1
3 False 1
4 False 1
... ... ...
16276 False 1
16277 True 1
16278 True 1
16279 False 1
16280 False 1
[16281 rows x 16 columns]
誤分類の分析
# 分析に使用する特徴のリスト
features = ['workclass', 'education.num', 'marital.status', 'occupation', 'relationship', 'race', 'sex', 'native.country']
# 誤分類情報を保存するためのリスト
all_missclassifications = []
# 最大誤分類率の初期化
max_misclassifications = -1
# 最大誤分類クラスターの初期化
max_misclassified_cluster = None
# 最大誤分類を引き起こす特徴の組み合わせの初期化
max_combination = None
# 特徴の組み合わせを反復処理するループ
for r in range(1, len(features) + 1):
for subset in itertools.combinations(features, r):
subset = list(subset) # タプルからリストに変換
# データを選択した特徴の組み合わせでグループ化し、誤分類数とカウンターを集計
g = data.groupby(subset)[['pos_missclassified', 'counter']].sum()
# 各グループの誤分類率を計算
group = g['pos_missclassified']/g['counter']
# 十分なデータ量を持つグループのみを選択(ここでは少なくとも162件)
grouped = group[g['counter'] >= 162]
if len(grouped) == 0:
continue # データがなければ次の組み合わせへ
# 現在のグループの最大誤分類率を見つける
current_max_misclassifications = grouped.max()
# 誤分類率のリストに現在のグループを追加
all_missclassifications.append(grouped.values)
# 最大誤分類率が更新された場合、情報を更新
if current_max_misclassifications > max_misclassifications:
max_misclassifications = current_max_misclassifications
max_misclassified_cluster = grouped.idxmax() # 最大誤分類グループのインデックス
max_combination = subset # 最大誤分類を引き起こす特徴の組み合わせ
- ここでは、特定の特徴(features)の組み合わせに基づいてデータをグループ化し、各グループの誤分類率を計算しています。
- itertools.combinationsを使って、特徴の異なる組み合わせを試します。
- 各グループの誤分類率が最も高いものを見つけて記録しています。
具体例1
subset = ['workclass', 'education.num', 'marital.status']
print(subset)
# ['workclass', 'education.num', 'marital.status']
# データを選択した特徴の組み合わせでグループ化し、誤分類数とカウンターを集計
g = data.groupby(subset)[['pos_missclassified', 'counter']].sum()
print(g)
"""
pos_missclassified counter
workclass education.num marital.status
Federal-gov 4 Married-spouse-absent 0 1
5 Married-civ-spouse 2 2
6 Married-civ-spouse 0 2
7 Divorced 0 2
Never-married 0 2
... ... ...
State-gov 16 Separated 1 1
Without-pay 4 Widowed 0 1
9 Married-civ-spouse 0 3
Never-married 0 3
10 Married-civ-spouse 0 1
[401 rows x 2 columns]
"""
# 各グループの誤分類率を計算
group = g['pos_missclassified']/g['counter']
print(group)
"""
workclass education.num marital.status
Federal-gov 4 Married-spouse-absent 0.0
5 Married-civ-spouse 1.0
6 Married-civ-spouse 0.0
7 Divorced 0.0
Never-married 0.0
...
State-gov 16 Separated 1.0
Without-pay 4 Widowed 0.0
9 Married-civ-spouse 0.0
Never-married 0.0
10 Married-civ-spouse 0.0
Length: 401, dtype: float64
"""
# 十分なデータ量を持つグループのみを選択(ここでは少なくとも162件)
grouped = group[g['counter'] >= 162]
print(grouped)
# 現在のグループの最大誤分類率を見つける
current_max_misclassifications = grouped.max()
print(current_max_misclassifications)
# 0.29310344827586204
具体例2
subset = ['workclass',]
print(subset)
# ['workclass', 'education.num', 'marital.status']
# データを選択した特徴の組み合わせでグループ化し、誤分類数とカウンターを集計
g = data.groupby(subset)[['pos_missclassified', 'counter']].sum()
print("---------------")
print(g)
"""
pos_missclassified counter
workclass
Federal-gov 103 475
Local-gov 165 1030
Never-worked 0 4
Private 1529 11332
Self-emp-inc 122 573
Self-emp-not-inc 235 1278
State-gov 101 649
Without-pay 0 8
"""
# 各グループの誤分類率を計算
group = g['pos_missclassified']/g['counter']
print("---------------")
print(group)
"""
workclass
Federal-gov 0.216842
Local-gov 0.160194
Never-worked 0.000000
Private 0.134928
Self-emp-inc 0.212914
Self-emp-not-inc 0.183881
State-gov 0.155624
Without-pay 0.000000
dtype: float64
"""
# 十分なデータ量を持つグループのみを選択(ここでは少なくとも162件)
grouped = group[g['counter'] >= 162]
print("---------------")
print(grouped)
"""
workclass
Federal-gov 0.216842
Local-gov 0.160194
Private 0.134928
Self-emp-inc 0.212914
Self-emp-not-inc 0.183881
State-gov 0.155624
dtype: float64
"""
# 現在のグループの最大誤分類率を見つける
current_max_misclassifications = grouped.max()
print("---------------")
print(current_max_misclassifications)
# 0.2168421052631579
具体例3
subset = ['occupation', 'sex']
print(subset)
# ['workclass', 'education.num', 'marital.status']
# データを選択した特徴の組み合わせでグループ化し、誤分類数とカウンターを集計
g = data.groupby(subset)[['pos_missclassified', 'counter']].sum()
print("---------------")
print(g)
"""
pos_missclassified counter
occupation sex
Adm-clerical Female 66 1245
Male 110 633
Armed-Forces Male 0 3
Craft-repair Female 7 112
Male 362 1958
Exec-managerial Female 77 581
Male 312 1468
Farming-fishing Female 0 33
Male 34 448
Handlers-cleaners Female 3 78
Male 30 585
Machine-op-inspct Female 10 280
Male 107 744
Other-service Female 21 912
Male 35 766
Priv-house-serv Female 0 74
Male 0 4
Prof-specialty Female 92 725
Male 277 1325
Protective-serv Female 5 42
Male 62 267
Sales Female 28 630
Male 238 1177
Tech-support Female 103 166
Male 156 295
Transport-moving Female 4 42
Male 116 752
"""
# 各グループの誤分類率を計算
group = g['pos_missclassified']/g['counter']
print("---------------")
print(group)
"""
occupation sex
Adm-clerical Female 0.053012
Male 0.173776
Armed-Forces Male 0.000000
Craft-repair Female 0.062500
Male 0.184883
Exec-managerial Female 0.132530
Male 0.212534
Farming-fishing Female 0.000000
Male 0.075893
Handlers-cleaners Female 0.038462
Male 0.051282
Machine-op-inspct Female 0.035714
Male 0.143817
Other-service Female 0.023026
Male 0.045692
Priv-house-serv Female 0.000000
Male 0.000000
Prof-specialty Female 0.126897
Male 0.209057
Protective-serv Female 0.119048
Male 0.232210
Sales Female 0.044444
Male 0.202209
Tech-support Female 0.620482
Male 0.528814
Transport-moving Female 0.095238
Male 0.154255
dtype: float64
"""
# 十分なデータ量を持つグループのみを選択(ここでは少なくとも162件)
grouped = group[g['counter'] >= 162]
print("---------------")
print(grouped)
"""
occupation sex
Adm-clerical Female 0.053012
Male 0.173776
Craft-repair Male 0.184883
Exec-managerial Female 0.132530
Male 0.212534
Farming-fishing Male 0.075893
Handlers-cleaners Male 0.051282
Machine-op-inspct Female 0.035714
Male 0.143817
Other-service Female 0.023026
Male 0.045692
Prof-specialty Female 0.126897
Male 0.209057
Protective-serv Male 0.232210
Sales Female 0.044444
Male 0.202209
Tech-support Female 0.620482
Male 0.528814
Transport-moving Male 0.154255
dtype: float64
"""
# 現在のグループの最大誤分類率を見つける
current_max_misclassifications = grouped.max()
print("---------------")
print(current_max_misclassifications)
# 0.6204819277108434
年齢セグメントの導入
query(data[(data.occupation == 'Tech-support') & (data.age < 35)].id.values.tolist())
- 最後に、特定の条件(ここでは職業がTech-supportで年齢が35歳未満)に一致するデータポイントを選択し、そのIDをquery関数に渡しています。
- これは、特定のサブポピュレーションが誤分類されているかどうかを確認するためのステップです。
参考サイト