にむかひて

LightGBMでカテゴリカル変数を扱う(Elixirより)

2021年11月 トップ > ひとこと > 調査したことの記録
#Elixir #LightGBM

LightGBMでカテゴリカル変数を使用するには? Elixir側から渡すときにどのようにデータを作るべきか?

結論

Elixir側からはわかりやすいようにString(数値0始まり)として送り、Python側でpandas.DataFrameをcategory型にすると良さそう

ドキュメント(*1)から抜粋

categorical_feature (list of str or int, or ‘auto’, optional (default=’auto’)) – Categorical features. If list of int, interpreted as indices. If list of str, interpreted as feature names (need to specify feature_name as well). If ‘auto’ and data is pandas DataFrame, pandas unordered categorical columns are used. All values in categorical features should be less than int32 max value (2147483647). Large values could be memory consuming. Consider using consecutive integers starting from zero. All negative values in categorical features will be treated as missing values. The output cannot be monotonically constrained with respect to a categorical feature.

  • ということでString(category型)にしてはみたが、手元データでは普通にIntegerで送ったときと結果が変わらなかった
    • 木構造なので、ある程度はよしなにやれる可能性が高い
    • とはいえ、ドキュメントにあるので対応しておくのがベターと思われる

コード(イメージ)

target_vec = #<= 何かしらのカテゴリカル変数データ配列
dict = target_vec |> Enum.uniq() |> Enum.with_index() |> Enum.into(%{}, fn {label, ind} -> {label, Integer.to_string(ind)} end)
target_vec = target_vec |> Enum.map(& dict[&1])
  • Integer.to_string() により文字列にして、python側でcategoryだと判別できるようにしている
  • 学習と試行時に同じindex(辞書)で採番する必要があるので注意する
    • python側で astype('category').cat.codes は使えないということ
vec = pd.DataFrame(vec)
for i, v in enumerate(vec.dtypes):
  if v == 'object':
    vec[i] = vec[i].astype('category')
return vec
  • 受け取ったデータをpandasのデータフレームに変換して’category’扱いにする

参考させていただいた資料等

サイト内検索