AIFFEL 15日目


LMS:データEDA
今日のテーマノードは整理すべきなので、振り返る前に内容を整理しておきます.
データセット:Kglobleポケモンデータ
1.データセットの読み込み
import os
csv_path = os.getenv("HOME") +"/aiffel/pokemon_eda/data/Pokemon.csv"
original_data = pd.read_csv(csv_path)
元のデータをpokemon変数にコピーして検証します(元のデータの破損を防ぐ)
pokemon = original_data.copy()
print(pokemon.shape)
pokemon.head()
2.データセットの表示
伝説変数をtargetに設定するので、伝説ポケモンは伝説変数に格納され、普通ポケモンは普通変数に格納されます.
# 전설의 포켓몬 데이터셋
legendary = pokemon[pokemon["Legendary"] == True].reset_index(drop=True)
print(legendary.shape)
legendary.head()

# 일반 포켓몬 데이터셋
ordinary = pokemon[pokemon["Legendary"] == False].reset_index(drop=True)
print(ordinary.shape)
ordinary.head()
測定値確認
pokemon.isnull().sum()
>> Type 2 의 결측치 : 386
列全体のチェック
print(len(pokemon.columns)) >>13
pokemon.columns 
タイプ1とタイプ2は何種類ありますか?
len(list(set(pokemon["Type 1"]))), len(list(set(pokemon["Type 2"])))
>>18, 19
タイプ2はもっと大きいです.車集を見てみましょう.
set(pokemon["Type 2"]) - set(pokemon["Type 1"])
>> {nan}
18種類の属性はtype 1とtype 2で同じです.type 2はより多くの実測値しかありません!
typeに何があるか見てみろ
types = list(set(pokemon["Type 1"]))
print(len(types))
print(types)
一般的なポケモンと伝説のポケモンのtype 1はsnsでcountplotを使用したビジュアル化
plt.figure(figsize=(10, 7))  # 그래프 크기를 조정

plt.subplot(211)
sns.countplot(data=ordinary, x="Type 1", order=types).set_xlabel('')
plt.title("[Ordinary Pokemons]")

plt.subplot(212)
sns.countplot(data=legendary, x="Type 1", order=types).set_xlabel('')
plt.title("[Legendary Pokemons]")

plt.show()
pivot tableで各属性の伝説ポケモンの数を確認
# Type1별로 Legendary 의 비율을 보여주는 피벗 테이블
pd.pivot_table(pokemon, index="Type 1", values="Legendary").sort_values(by=["Legendary"], ascending=False)
アトリビュート別にTotal値分布を描画すると、伝奇面に異なる色が表示されます.
fig, ax = plt.subplots()
fig.set_size_inches(12, 6)  # 화면 해상도에 따라 그래프 크기를 조정해 주세요.

sns.scatterplot(data=pokemon, x="Type 1", y="Total", hue="Legendary")
plt.show()
伝説のポケモンの桟値は主に上流にあることが確認された.
ポケモンの数を決める
plt.figure(figsize=(12, 10))   # 화면 해상도에 따라 그래프 크기를 조정해 주세요.

plt.subplot(211)
sns.countplot(data=ordinary, x="Generation").set_xlabel('')
plt.title("[All Pkemons]")
plt.subplot(212)
sns.countplot(data=legendary, x="Generation").set_xlabel('')
plt.title("[Legendary Pkemons]")
plt.show()
伝説のポケモンの総額を確認
fig, ax = plt.subplots()
fig.set_size_inches(8, 4)

sns.scatterplot(data=legendary, y="Type 1", x="Total")
plt.show()
結果をチェックすると、通常は特定の値のセットがあります.
print(sorted(list(set(legendary["Total"]))))
ソートと検証を行うと、9つの値が出力されます.
伝説のポケモンは65匹で、総価格は9個で、押し寄せたと解釈できる!
では普通のポケモンは?
len(sorted(list(set(ordinary["Total"])))) >>195
735匹、総価値195個>>比較的小さい
もしポケモンの総価格が伝説のポケモンの総価格集合に含まれていたら>>伝説のポケモンは確率が高い!
したがって、total featureはターゲットを区別する重要な列です.
名前の長さが気になります.伝説的なリフレッシュデータセットにname countという列を新規作成
legendary["name_count"] = legendary["Name"].apply(lambda i: len(i))    
legendary.head()
同じように一般的なデータセットを作成しましょう.
ordinary["name_count"] = ordinary["Name"].apply(lambda i: len(i))    
ordinary.head()
2つのグループを視覚的に比較
plt.figure(figsize=(12, 10))  

plt.subplot(211)
sns.countplot(data=legendary, x="name_count").set_xlabel('')
plt.title("Legendary")
plt.subplot(212)
sns.countplot(data=ordinary, x="name_count").set_xlabel('')
plt.title("Ordinary")
plt.show()
だいたい伝説のポケモンの名前が長いことが確認できます.一般的にポケモンは10文字以上も少ない!
確率で知りましょう
print(round(len(legendary[legendary["name_count"] > 9]) / len(legendary) * 100, 2), "%") #41.54%, 

print(round(len(ordinary[ordinary["name_count"] > 9]) / len(ordinary) * 100, 2), "%") #15.65%
名前の長さfeatureは伝説のポケモンを区別する重要な変数でもある.
3.前処理データ
name count columnで、名前の長さが10を超えるかどうかを示すカテゴリcolumnを作成します.「long name」コラムに新しく登場した.
pokemon["name_count"] = pokemon["Name"].apply(lambda i: len(i))
pokemon["long_name"] = pokemon["name_count"] >= 10
pokemon.head()
次は伝説のポケモンの名前でよく使われるコインで、新しい色を作ります.
ポケットモンスターの名前がアルファベットで構成されているかどうかをisalphaでチェックし、スペースがあってもfalseで出力されるので、まずスペースのない色を作成します.
pokemon["Name_nospace"] = pokemon["Name"].apply(lambda i: i.replace(" ", ""))
今からIsalphaコラムを作りましょう.
pokemon["name_isalpha"] = pokemon["Name_nospace"].apply(lambda i: i.isalpha())
名前にアルファベットが含まれていない他の文字に名前を付けます.
print(pokemon[pokemon["name_isalpha"] == False].shape) #9마리
pokemon[pokemon["name_isalpha"] == False]

pokemon = pokemon.replace(to_replace="Nidoran♀", value="Nidoran X")
pokemon = pokemon.replace(to_replace="Nidoran♂", value="Nidoran Y")
pokemon = pokemon.replace(to_replace="Farfetch'd", value="Farfetchd")
pokemon = pokemon.replace(to_replace="Mr. Mime", value="Mr Mime")
pokemon = pokemon.replace(to_replace="Porygon2", value="Porygon")
pokemon = pokemon.replace(to_replace="Ho-oh", value="Ho Oh")
pokemon = pokemon.replace(to_replace="Mime Jr.", value="Mime Jr")
pokemon = pokemon.replace(to_replace="Porygon-Z", value="Porygon Z")
pokemon = pokemon.replace(to_replace="Zygarde50% Forme", value="Zygarde Forme")

pokemon.loc[[34, 37, 90, 131, 252, 270, 487, 525, 794]] #확인
では今正則表現でToken化していきましょう
大文字から小文字で終わるパターンを探して、コインを渡します.
そこで,隔写を基準としてパターン別にトークン化する関数を発表した.
def tokenize(name):
    name_split = name.split(" ")
    
    tokens = []
    for part_name in name_split:
        a = re.findall('[A-Z][a-z]*', part_name)
        tokens.extend(a)
        
    return np.array(tokens)
伝説のポケモンに応用する
all_tokens = list(legendary["Name"].apply(tokenize).values)

token_set = []
for token in all_tokens:
    token_set.extend(token)

print(len(set(token_set)))
print(token_set)
分割されたタグのうち、多く出現するタグを10個選択
このとき、コレクションパッケージのカウンタオブジェクトを使用します.
most_common = Counter(token_set).most_common(10)
most_common
ここでは、伝説のポケモンの名前に登場するマークがポケモンの名前の色にあるかどうかを見てみましょう.
for token, _ in most_common:
   
    pokemon[f"{token}"] = pokemon["Name"].str.contains(token)

pokemon.head(10)
次に,ホットコーディングを用いてカテゴリデータ型を前処理する.
for t in types:
    pokemon[t] = (pokemon["Type 1"] == t) | (pokemon["Type 2"] == t)
    
pokemon[[["Type 1", "Type 2"] + types][0]].head()
でもそうしないで、ファンタのgetdummy()を使うほうが効率的なようで、
4.学習モデル
まず、前に処理したカラム+既存のカラムでfeatureを定義し、不要なカラムや文字変数のあるカラムを除外します.
また、伝説をターゲットデータに分類する.
features = ['Total', 'HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed', 'Generation', 
            'name_count', 'long_name', 'Forme', 'Mega', 'Mewtwo', 'Kyurem', 'Deoxys', 'Hoopa', 
            'Latias', 'Latios', 'Kyogre', 'Groudon', 'Poison', 'Water', 'Steel', 'Grass', 
            'Bug', 'Normal', 'Fire', 'Fighting', 'Electric', 'Psychic', 'Ghost', 'Ice', 
            'Rock', 'Dark', 'Flying', 'Ground', 'Dragon', 'Fairy']

target = "Legendary"
X,yに各データを入力し、train setとtest setに分離します.
X = pokemon[features]
y = pokemon[target]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=15)

print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)
DecisionTreeを使用してモデルを作成し、学習と評価を行います.
model = DecisionTreeClassifier(random_state=25)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
confusion_matrix(y_test, y_pred)
print(classification_report(y_test, y_pred))
recall > 0.92
従来のベースラインモデルではrecallは0.62であり,新しい特性の作成と学習によりモデルの性能が大幅に向上したことがわかる.
振り返る
実際,データ解析を行う際には,名目型変数をスタック変数とする以外に,新しいfeatureを加えることは考えられなかった.このノードでは,データを与える際にランダムにモデルに戻るのではなく,どのような順序と方法で前処理してモデルに入れるかを知った.
今日はまた、アプリケーションモデルのコードは簡単だと感じましたが、前処理コードが本当に一人一人にとって難しいと、難しくなるので、Pythonの実力の重要性を改めて認識しました.
今週はいつの間にか終わりました.もう3週間もかかっていますが、私の実力がどこまで上がったのか、今はまだよくわかりませんが、そんなに努力していないような気がします.3週間やっていたIpelは、あまり計画や時間を気にしていなかったようで、これからはタスクページを単独で作成し、やるべきこと、やっていること、やっていることを体系化して、一目で見られるようにしています.