AI Village Capture the Flag @ DEFCON31（Cluster - Level 1）【解説】


## Q

数字とデータの世界で、私たちは揺れ動きます。誰が大々的に収益を上げるのかを測定するモデル、しかし！賢い者が、ある策略を使って、あるグループの予測を引き上げました。このずる賢い者はコードの中で巧妙に舞い、一つのグループの運命を引き上げました。しかし心配はいりません、私たちはこの変装を見破るでしょう。そして、どのグループが利益を得ていたのかを明らかにします。

（どのサブグループが体系的に誤分類されているかを見つけてください。）


---

こちらの記事もおすすめ


https://hamaruki.com/explanation-verification-the-dawn-of-lmms-preliminary-explorations-with-gpt-4vision/

https://hamaruki.com/starting-chatvrm-with-docker/

https://hamaruki.com/cg-production-is-also-possible-with-chatgpt/


## 初期設定とデータの取得

```python

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形式で返します。

```bash

!pip -q install skops
!pip -q install scikit-learn==1.3.0

```

ここでskopsと特定バージョンのscikit-learnをインストールしています。これらは機械学習モデルの操作に必要です。



```python

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によってソートしています。

## データの処理

```python

prediction = pipe.predict(data)
data['pos_missclassified'] =  prediction != data.income
data['counter'] = 1

```

- モデルpipeを使用してデータセットdataの予測を行い、予測結果をpredictionに保存します。
- 実際の収入（income）と予測結果を比較し、誤分類されたデータポイントをpos_missclassified列に記録します。
- 各行に対してカウンター（counter）を設定します。



```bash

          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]
```


## 誤分類の分析


```python

# 分析に使用する特徴のリスト
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

```python

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

```python

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

```python

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



```

## 年齢セグメントの導入

```python

query(data[(data.occupation == 'Tech-support') & (data.age < 35)].id.values.tolist())

```

- 最後に、特定の条件（ここでは職業がTech-supportで年齢が35歳未満）に一致するデータポイントを選択し、そのIDをquery関数に渡しています。
- これは、特定のサブポピュレーションが誤分類されているかどうかを確認するためのステップです。


## 参考サイト

https://www.kaggle.com/code/masakitani/25-flags-of-pain-no-cifar-and-granny-3