1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

polarsを使ってspaceship titanicを提出する

Posted at

はじめに

polarsとは

polarsはpythonで使える高速のデータフレームライブラリです。
データフレームライブラリといえばpandas🐼が有名ですが、それに対するpolars🐻‍❄️です。
今回はpolarsに慣れるため、kaggleのコンペSpaceship Titanicに、結果を提出してみます。

やること

  • テーブルデータの読み書き
  • 平均、標準偏差などの基本統計量の確認
  • ユニークな要素の確認
  • 欠損値の処理

やらないこと

  • コンペのスコアは気にしません
  • 高度な解析は行いません

事前準備

実行環境にはgoogle colaboratoryを使用します。
また、colab上でkaggle apiを叩いてデータのダウンロードや提出を行います。
下記ページがわかりやすかった。
https://take-tech-engineer.com/kaggle-colab-api/

やってみる

csvファイルのリード 

import polars as pl
ldf = pl.scan_csv("train.csv")

先頭、末尾の行を見る

print('head', ldf.head(10).collect())
print('teil', ldf.tail(10).collect())

# result
'''
head shape: (5, 14)
┌─────────────┬────────────┬───────────┬───────┬───┬────────┬────────┬───────────────┬─────────────┐
│ PassengerId ┆ HomePlanet ┆ CryoSleep ┆ Cabin ┆ … ┆ Spa    ┆ VRDeck ┆ Name          ┆ Transported │
│ ---         ┆ ---        ┆ ---       ┆ ---   ┆   ┆ ---    ┆ ---    ┆ ---           ┆ ---         │
│ str         ┆ str        ┆ bool      ┆ str   ┆   ┆ f64    ┆ f64    ┆ str           ┆ bool        │
╞═════════════╪════════════╪═══════════╪═══════╪═══╪════════╪════════╪═══════════════╪═════════════╡
│ 0001_01     ┆ Europa     ┆ false     ┆ B/0/P ┆ … ┆ 0.0    ┆ 0.0    ┆ Maham         ┆ false       │
│             ┆            ┆           ┆       ┆   ┆        ┆        ┆ Ofracculy     ┆             │
│ 0002_01     ┆ Earth      ┆ false     ┆ F/0/S ┆ … ┆ 549.0  ┆ 44.0   ┆ Juanna Vines  ┆ true        │
│ 0003_01     ┆ Europa     ┆ false     ┆ A/0/S ┆ … ┆ 6715.0 ┆ 49.0   ┆ Altark Susent ┆ false       │
│ 0003_02     ┆ Europa     ┆ false     ┆ A/0/S ┆ … ┆ 3329.0 ┆ 193.0  ┆ Solam Susent  ┆ false       │
│ 0004_01     ┆ Earth      ┆ false     ┆ F/1/S ┆ … ┆ 565.0  ┆ 2.0    ┆ Willy         ┆ true        │
│             ┆            ┆           ┆       ┆   ┆        ┆        ┆ Santantines   ┆             │
└─────────────┴────────────┴───────────┴───────┴───┴────────┴────────┴───────────────┴─────────────┘
teil shape: (5, 14)
┌───────────┬────────────┬───────────┬──────────┬───┬────────┬────────┬──────────────┬─────────────┐
│ Passenger ┆ HomePlanet ┆ CryoSleep ┆ Cabin    ┆ … ┆ Spa    ┆ VRDeck ┆ Name         ┆ Transported │
│ Id        ┆ ---        ┆ ---       ┆ ---      ┆   ┆ ---    ┆ ---    ┆ ---          ┆ ---         │
│ ---       ┆ str        ┆ bool      ┆ str      ┆   ┆ f64    ┆ f64    ┆ str          ┆ bool        │
│ str       ┆            ┆           ┆          ┆   ┆        ┆        ┆              ┆             │
╞═══════════╪════════════╪═══════════╪══════════╪═══╪════════╪════════╪══════════════╪═════════════╡
│ 9276_01   ┆ Europa     ┆ false     ┆ A/98/P   ┆ … ┆ 1643.0 ┆ 74.0   ┆ Gravior      ┆ false       │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Noxnuther    ┆             │
│ 9278_01   ┆ Earth      ┆ true      ┆ G/1499/S ┆ … ┆ 0.0    ┆ 0.0    ┆ Kurta        ┆ false       │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Mondalley    ┆             │
│ 9279_01   ┆ Earth      ┆ false     ┆ G/1500/S ┆ … ┆ 1.0    ┆ 0.0    ┆ Fayey Connon ┆ true        │
│ 9280_01   ┆ Europa     ┆ false     ┆ E/608/S  ┆ … ┆ 353.0  ┆ 3235.0 ┆ Celeon       ┆ false       │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Hontichre    ┆             │
│ 9280_02   ┆ Europa     ┆ false     ┆ E/608/S  ┆ … ┆ 0.0    ┆ 12.0   ┆ Propsh       ┆ true        │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Hontichre    ┆             │
└───────────┴────────────┴───────────┴──────────┴───┴────────┴────────┴──────────────┴─────────────┘
'''

基本統計量を表示する

データの総数、nullデータの数、平均、標準偏差、最大、最小、中央値、25パーセンタイル、75パーセンタイルの値が確認できる。

print(ldf.collect().describe())

# result
'''
shape: (9, 15)
┌───────────┬───────────┬──────────┬───────────┬───┬───────────┬───────────┬───────────┬───────────┐
│ describe  ┆ Passenger ┆ HomePlan ┆ CryoSleep ┆ … ┆ Spa       ┆ VRDeck    ┆ Name      ┆ Transport │
│ ---       ┆ Id        ┆ et       ┆ ---       ┆   ┆ ---       ┆ ---       ┆ ---       ┆ ed        │
│ str       ┆ ---       ┆ ---      ┆ f64       ┆   ┆ f64       ┆ f64       ┆ str       ┆ ---       │
│           ┆ str       ┆ str      ┆           ┆   ┆           ┆           ┆           ┆ f64       │
╞═══════════╪═══════════╪══════════╪═══════════╪═══╪═══════════╪═══════════╪═══════════╪═══════════╡
│ count     ┆ 8693      ┆ 8693     ┆ 8693.0    ┆ … ┆ 8693.0    ┆ 8693.0    ┆ 8693      ┆ 8693.0    │
│ null_coun ┆ 0         ┆ 201      ┆ 217.0     ┆ … ┆ 183.0     ┆ 188.0     ┆ 200       ┆ 0.0       │
│ t         ┆           ┆          ┆           ┆   ┆           ┆           ┆           ┆           │
│ mean      ┆ null      ┆ null     ┆ 0.358306  ┆ … ┆ 311.13877 ┆ 304.85479 ┆ null      ┆ 0.503624  │
│           ┆           ┆          ┆           ┆   ┆ 8         ┆ 1         ┆           ┆           │
│ std       ┆ null      ┆ null     ┆ 0.47953   ┆ … ┆ 1136.7055 ┆ 1145.7171 ┆ null      ┆ 0.500016  │
│           ┆           ┆          ┆           ┆   ┆ 35        ┆ 89        ┆           ┆           │
│ min       ┆ 0001_01   ┆ Earth    ┆ 0.0       ┆ … ┆ 0.0       ┆ 0.0       ┆ Aard      ┆ 0.0       │
│           ┆           ┆          ┆           ┆   ┆           ┆           ┆ Curle     ┆           │
│ max       ┆ 9280_02   ┆ Mars     ┆ 1.0       ┆ … ┆ 22408.0   ┆ 24133.0   ┆ Zubeneb   ┆ 1.0       │
│           ┆           ┆          ┆           ┆   ┆           ┆           ┆ Pasharne  ┆           │
│ median    ┆ null      ┆ null     ┆ 0.0       ┆ … ┆ 0.0       ┆ 0.0       ┆ null      ┆ 1.0       │
│ 25%       ┆ null      ┆ null     ┆ null      ┆ … ┆ 0.0       ┆ 0.0       ┆ null      ┆ null      │
│ 75%       ┆ null      ┆ null     ┆ null      ┆ … ┆ 59.0      ┆ 46.0      ┆ null      ┆ null      │
└───────────┴───────────┴──────────┴───────────┴───┴───────────┴───────────┴───────────┴───────────┘
'''

nullが含まれない行を抽出する

print(ldf.drop_nulls().collect())

#result
'''
shape: (6_606, 14)
┌───────────┬────────────┬───────────┬──────────┬───┬────────┬────────┬──────────────┬─────────────┐
│ Passenger ┆ HomePlanet ┆ CryoSleep ┆ Cabin    ┆ … ┆ Spa    ┆ VRDeck ┆ Name         ┆ Transported │
│ Id        ┆ ---        ┆ ---       ┆ ---      ┆   ┆ ---    ┆ ---    ┆ ---          ┆ ---         │
│ ---       ┆ str        ┆ bool      ┆ str      ┆   ┆ f64    ┆ f64    ┆ str          ┆ bool        │
│ str       ┆            ┆           ┆          ┆   ┆        ┆        ┆              ┆             │
╞═══════════╪════════════╪═══════════╪══════════╪═══╪════════╪════════╪══════════════╪═════════════╡
│ 0001_01   ┆ Europa     ┆ false     ┆ B/0/P    ┆ … ┆ 0.0    ┆ 0.0    ┆ Maham        ┆ false       │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Ofracculy    ┆             │
│ 0002_01   ┆ Earth      ┆ false     ┆ F/0/S    ┆ … ┆ 549.0  ┆ 44.0   ┆ Juanna Vines ┆ true        │
│ 0003_01   ┆ Europa     ┆ false     ┆ A/0/S    ┆ … ┆ 6715.0 ┆ 49.0   ┆ Altark       ┆ false       │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Susent       ┆             │
│ 0003_02   ┆ Europa     ┆ false     ┆ A/0/S    ┆ … ┆ 3329.0 ┆ 193.0  ┆ Solam Susent ┆ false       │
│ …         ┆ …          ┆ …         ┆ …        ┆ … ┆ …      ┆ …      ┆ …            ┆ …           │
│ 9278_01   ┆ Earth      ┆ true      ┆ G/1499/S ┆ … ┆ 0.0    ┆ 0.0    ┆ Kurta        ┆ false       │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Mondalley    ┆             │
│ 9279_01   ┆ Earth      ┆ false     ┆ G/1500/S ┆ … ┆ 1.0    ┆ 0.0    ┆ Fayey Connon ┆ true        │
│ 9280_01   ┆ Europa     ┆ false     ┆ E/608/S  ┆ … ┆ 353.0  ┆ 3235.0 ┆ Celeon       ┆ false       │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Hontichre    ┆             │
│ 9280_02   ┆ Europa     ┆ false     ┆ E/608/S  ┆ … ┆ 0.0    ┆ 12.0   ┆ Propsh       ┆ true        │
│           ┆            ┆           ┆          ┆   ┆        ┆        ┆ Hontichre    ┆             │
└───────────┴────────────┴───────────┴──────────┴───┴────────┴────────┴──────────────┴─────────────┘
'''

nullが含まれる行を抽出する

カラムごとにnullチェックを実施して表示。

for c in ldf.columns:
  n_ldf = ldf.filter(pl.col(c).is_null())
  print(c, n_ldf.collect())

# result
'''
PassengerId shape: (0, 14)
┌─────────────┬────────────┬───────────┬───────┬───┬─────┬────────┬──────┬─────────────┐
│ PassengerId ┆ HomePlanet ┆ CryoSleep ┆ Cabin ┆ … ┆ Spa ┆ VRDeck ┆ Name ┆ Transported │
│ ---         ┆ ---        ┆ ---       ┆ ---   ┆   ┆ --- ┆ ---    ┆ ---  ┆ ---         │
│ str         ┆ str        ┆ bool      ┆ str   ┆   ┆ f64 ┆ f64    ┆ str  ┆ bool        │
╞═════════════╪════════════╪═══════════╪═══════╪═══╪═════╪════════╪══════╪═════════════╡
└─────────────┴────────────┴───────────┴───────┴───┴─────┴────────┴──────┴─────────────┘
HomePlanet shape: (201, 14)
┌─────────────┬────────────┬───────────┬──────────┬───┬───────┬────────┬─────────────┬─────────────┐
│ PassengerId ┆ HomePlanet ┆ CryoSleep ┆ Cabin    ┆ … ┆ Spa   ┆ VRDeck ┆ Name        ┆ Transported │
│ ---         ┆ ---        ┆ ---       ┆ ---      ┆   ┆ ---   ┆ ---    ┆ ---         ┆ ---         │
│ str         ┆ str        ┆ bool      ┆ str      ┆   ┆ f64   ┆ f64    ┆ str         ┆ bool        │
╞═════════════╪════════════╪═══════════╪══════════╪═══╪═══════╪════════╪═════════════╪═════════════╡
│ 0064_02     ┆ null       ┆ true      ┆ E/3/S    ┆ … ┆ 0.0   ┆ 0.0    ┆ Colatz Keen ┆ true        │
│ 0119_01     ┆ null       ┆ false     ┆ A/0/P    ┆ … ┆ 65.0  ┆ 6898.0 ┆ Batan       ┆ false       │
│             ┆            ┆           ┆          ┆   ┆       ┆        ┆ Coning      ┆             │
│ 0210_01     ┆ null       ┆ true      ┆ D/6/P    ┆ … ┆ 0.0   ┆ 0.0    ┆ Arraid      ┆ true        │
│             ┆            ┆           ┆          ┆   ┆       ┆        ┆ Inicont     ┆             │
│ 0242_01     ┆ null       ┆ false     ┆ F/46/S   ┆ … ┆ 283.0 ┆ 0.0    ┆ Almone Sté  ┆ false       │
│ …           ┆ …          ┆ …         ┆ …        ┆ … ┆ …     ┆ …      ┆ …           ┆ …           │
│ 9194_01     ┆ null       ┆ false     ┆ E/603/S  ┆ … ┆ 13.0  ┆ 3147.0 ┆ null        ┆ false       │
│ 9248_01     ┆ null       ┆ false     ┆ F/1792/S ┆ … ┆ 207.0 ┆ 0.0    ┆ Gian Perle  ┆ true        │
│ 9257_01     ┆ null       ┆ false     ┆ F/1892/P ┆ … ┆ 24.0  ┆ 0.0    ┆ Ties Apple  ┆ false       │
│ 9274_01     ┆ null       ┆ true      ┆ G/1508/P ┆ … ┆ 0.0   ┆ 0.0    ┆ Chelsa      ┆ true        │
│             ┆            ┆           ┆          ┆   ┆       ┆        ┆ Bullisey    ┆             │
└─────────────┴────────────┴───────────┴──────────┴───┴───────┴────────┴─────────────┴─────────────┘
以下略

'''

列の要素を確認

列ごとにユニークな要素を確認する。
全部出力すると大変なので headで先頭だけ表示する。

for c in ldf.columns:
  unq_df = ldf.select(c).unique().collect()
  print(f"{c}\tsize:{len(unq_df)}\tsample{unq_df.head()}")

'''
PassengerId	size:8693	sampleshape: (5, 1)
┌─────────────┐
│ PassengerId │
│ ---         │
│ str         │
╞═════════════╡
│ 9179_03     │
│ 6399_01     │
│ 5535_03     │
│ 6593_02     │
│ 8521_01     │
└─────────────┘
HomePlanet	size:4	sampleshape: (4, 1)
┌────────────┐
│ HomePlanet │
│ ---        │
│ str        │
╞════════════╡
│ null       │
│ Earth      │
│ Europa     │
│ Mars       │
└────────────┘
以下略

'''


新たな特徴量を作る

Cabinは'/'で3つのブロックに分けられそう。

def reconstruct(df):
  return df.with_columns(
      pl.col('Cabin')
      .str.splitn('/', 3)
      .struct.rename_fields(['Cabin_area', 'Cabin_number', 'Cabin_type'])
  ).unnest('Cabin').with_columns(
      pl.col('Cabin_number')
      .cast(int)
  )

appended_ldf = reconstruct(ldf).drop_nulls()
print(appended_ldf.select('PassengerId', 'Cabin_area', 'Cabin_number', 'Cabin_type').head(10).collect())

'''
shape: (10, 4)
┌─────────────┬────────────┬──────────────┬────────────┐
│ PassengerId ┆ Cabin_area ┆ Cabin_number ┆ Cabin_type │
│ ---         ┆ ---        ┆ ---          ┆ ---        │
│ str         ┆ str        ┆ i64          ┆ str        │
╞═════════════╪════════════╪══════════════╪════════════╡
│ 0001_01     ┆ B          ┆ 0            ┆ P          │
│ 0002_01     ┆ F          ┆ 0            ┆ S          │
│ 0003_01     ┆ A          ┆ 0            ┆ S          │
│ 0003_02     ┆ A          ┆ 0            ┆ S          │
│ …           ┆ …          ┆ …            ┆ …          │
│ 0006_01     ┆ F          ┆ 2            ┆ S          │
│ 0007_01     ┆ F          ┆ 3            ┆ S          │
│ 0008_01     ┆ B          ┆ 1            ┆ P          │
│ 0008_03     ┆ B          ┆ 1            ┆ P          │
└─────────────┴────────────┴──────────────┴────────────┘

'''


データの分布を可視化する

列ごとにどの要素が多いか(少ないか)を集計する。
今回は関数を作ってみた。

def calc_distribution(data:pl.DataFrame, column_name:str) -> pl.DataFrame:
  return data.select(
      pl.col(column_name).value_counts()
      .struct.rename_fields(['value', 'count'])
  ).unnest(column_name)

print(calc_distribution(appended_ldf, "HomePlanet").collect())

'''
shape: (3, 2)
┌────────┬───────┐
│ value  ┆ count │
│ ---    ┆ ---   │
│ str    ┆ u32   │
╞════════╪═══════╡
│ Earth  ┆ 3566  │
│ Mars   ┆ 1367  │
│ Europa ┆ 1673  │
└────────┴───────┘
'''

ダミー変数化する 

カテゴリデータはダミー変数にした方が扱いやすい。 
ダミー変換化したいcolumnをリストで指定して処理する例。

target_to_dummies = ["HomePlanet", "CryoSleep", "Cabin_area", "Cabin_type", "Destination", "VIP"]
dummied = appended_ldf.select(target_to_dummies).collect().to_dummies()
remaind = appended_ldf.drop(target_to_dummies).collect()
dummied_df = pl.concat([remaind, dummied], how="horizontal")
print(dummied_df)

'''
shape: (6_606, 30)
┌───────────┬────────────┬──────┬───────────┬───┬────────────┬──────────────┬───────────┬──────────┐
│ Passenger ┆ Cabin_numb ┆ Age  ┆ RoomServi ┆ … ┆ Destinatio ┆ Destination_ ┆ VIP_false ┆ VIP_true │
│ Id        ┆ er         ┆ ---  ┆ ce        ┆   ┆ n_PSO      ┆ TRAPPIST-1e  ┆ ---       ┆ ---      │
│ ---       ┆ ---        ┆ f64  ┆ ---       ┆   ┆ J318.5-22  ┆ ---          ┆ u8        ┆ u8       │
│ str       ┆ i64        ┆      ┆ f64       ┆   ┆ ---        ┆ u8           ┆           ┆          │
│           ┆            ┆      ┆           ┆   ┆ u8         ┆              ┆           ┆          │
╞═══════════╪════════════╪══════╪═══════════╪═══╪════════════╪══════════════╪═══════════╪══════════╡
│ 0001_01   ┆ 0          ┆ 39.0 ┆ 0.0       ┆ … ┆ 0          ┆ 1            ┆ 1         ┆ 0        │
│ 0002_01   ┆ 0          ┆ 24.0 ┆ 109.0     ┆ … ┆ 0          ┆ 1            ┆ 1         ┆ 0        │
│ 0003_01   ┆ 0          ┆ 58.0 ┆ 43.0      ┆ … ┆ 0          ┆ 1            ┆ 0         ┆ 1        │
│ 0003_02   ┆ 0          ┆ 33.0 ┆ 0.0       ┆ … ┆ 0          ┆ 1            ┆ 1         ┆ 0        │
│ …         ┆ …          ┆ …    ┆ …         ┆ … ┆ …          ┆ …            ┆ …         ┆ …        │
│ 9278_01   ┆ 1499       ┆ 18.0 ┆ 0.0       ┆ … ┆ 1          ┆ 0            ┆ 1         ┆ 0        │
│ 9279_01   ┆ 1500       ┆ 26.0 ┆ 0.0       ┆ … ┆ 0          ┆ 1            ┆ 1         ┆ 0        │
│ 9280_01   ┆ 608        ┆ 32.0 ┆ 0.0       ┆ … ┆ 0          ┆ 0            ┆ 1         ┆ 0        │
│ 9280_02   ┆ 608        ┆ 44.0 ┆ 126.0     ┆ … ┆ 0          ┆ 1            ┆ 1         ┆ 0        │
└───────────┴────────────┴──────┴───────────┴───┴────────────┴──────────────┴───────────┴──────────┘

'''

提出ファイルを作る 

値はランダム。
csvファイルを出力する前にpandasに変換したのは、提出ファイルのTrue, Falseの頭文字を大文字にするため。
polarsのままだと、true, falseとなってしまい、scoreが0になります。

import random

df = pl.read_csv('test.csv')
passenger = df.select('PassengerId')
transported = pl.DataFrame(
    {
        'Transported':[random.choice([True, False]) for _ in range(len(passenger))]
    }
)

submit = pl.concat([passenger, transported], how='horizontal')
submit.to_pandas().to_csv("submit.csv", index=False)

提出 

作ったファイルをkaggle APIを使用して提出する。

!kaggle competitions submit -c spaceship-titanic -f submit.csv -m "comment"

最後に 

大まかにやりたいことはできた。(と思う。)
早い、安い、うまいのでpolarsを流行らせたい!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?