perspective-modeの設定

書いておく

(require 'perspective)

(setq persp-show-modestring 'header)

;; 有効化
(persp-mode 1)

;; persp-modeはC-x xがプレフィックス

;; 現在のperspectiveに限定したbs-show
(global-set-key (kbd "C-x C-M-b")
                '(lambda (arg)
                   (interactive "p")
                   (require 'bs nil t)
                   (call-interactively 'persp-bs-show)))

;; perspectiveの状態をEmacs終了時に保存し、復元できるようにする
(setq persp-state-default-file "~/.emacs.d/persp-state-file")
(add-hook 'kill-emacs-hook #'persp-state-save)

(defvar persp-switch-prefix "C-M-%d")
(defvar persp-first-perspective "2") ;; 最初のワークスペースは"2"に設定
(defvar persp-top-perspective "0")
(defvar persp-bottom-perspective "9")

(defun persp-set-keybind ()
  (mapc (lambda (i)
          (persp-switch (int-to-string i))
          (global-set-key (kbd (format persp-switch-prefix i))
                          `(lambda ()
                             (interactive)
                             (persp-switch ,(int-to-string i)))))
        (number-sequence (string-to-number persp-top-perspective)
                         (string-to-number persp-bottom-perspective))))

(defun persp-my-setup ()
  (persp-set-keybind)
  (persp-switch persp-first-perspective)
  (persp-kill "main"))

(add-hook 'persp-state-after-load-hook 'persp-my-setup)
(add-hook 'after-init-hook 'persp-my-setup)

;; *で始まるバッファ名を候補から削除 -> たとえば*scratch*に変えられない副作用
(setq ido-ignore-buffers (append '("\\`\\*") ido-ignore-buffers))

;; *で始まるバッファ名を候補から非表示・表示をトグルする関数
(defun persp-toggle-ignore-buffers ()
  (interactive)
  (if (member "\\`\\*" ido-ignore-buffers)
      (setq ido-ignore-buffers '("\\` "))
    (setq ido-ignore-buffers (append '("\\`\\*") ido-ignore-buffers))))

;; .で始まるファイル名を削除
(setq ido-ignore-files (append '("\\`\\.") ido-ignore-files))

畳み込みのスクラッチ実装(Python)

ディジタル信号処理を勉強するひとは、すべからくマスターすべき演算が畳み込みである(私見)。 畳み込み演算の重要性は論を俟たない。いわゆる線形時不変システムはインパルス応答と入力信号との畳み込みにより記述される。音声のディジタル信号処理の文脈でいえば、分析合成フィルタ(いわゆるボコーダー)の実現に畳み込み演算が用いられる。

Pythonライブラリのnumpyには畳み込みを実行する関数convolveがあり、またscipyにもconvolveがあるため、実用上はそれらを使えば良い(というかぜひ使うべきである)。 ただスクラッチで畳み込みを実装せよと言われたとき、はたと手が止まる人も多いのではなかろうか。

本記事ではディジタル信号処理を対象とし、FIRフィルタ(インパルス応答が有限長)としての畳み込み演算の実装について説明する。

説明

インパルス応答とはデジタルシステムにインパルス信号を入力したときの出力を指す。ここで,入力信号を$x[n]$,インパルス応答を$h[n]$,出力信号を$y[n]$とする。$n$は時間インデックスである。出力信号$y[n]$は次式で示される。

$$ y[n] = \sum\limits_{m = -\infty}^{\infty} x[n-m]h[m] $$

ただし$x[n]$の長さを$N$とする。

$$ x[0], x[1], \ldots, x[N-1] $$

さらに$h[n]$の長さを${M}$とする。

$$ h[0], h[1], \ldots, h[M -1] $$

すると上式の総和は$m=0$から$M - 1$までとなり、$y[n]$の長さは$N + M -1$となる。

上記の説明より、$n = 0, 1, ..., N + M - 1$について

$$ y[n] = \sum\limits_{m = 0}^{M -1} x[n-m]h[m] $$

である。

$x[n]$は長さ$N$の条件を持っている。しかしながら、例えば上記の畳み込みの式において、$n - m $が $N$以上になることが起こり得る。一方で、実際のデータとしては

$$ x[0], x[1], \ldots, x[N-1] $$

しか手元にない。そのとき、$x[n - m] = 0$としたいので、事前に$x[n]$を拡張し、長さ$N + M -1$の系列となるよう、$x[n]$の右側に0を詰めておくのがスマートである。

\begin{align} \tilde{x}[n] = \begin{cases} x[n] & (0 \leq n \leq N-1)\\ 0 & (N\leq n \leq N + M - 2) \end{cases} \end{align}

この結果として、$\tilde{x}[n]$が長さ$N + M -1$の系列になる。 さらに$\tilde{x}[n-m]$のインデックスが非負になる$n \geq m $の範囲で和を取ればよい。 つまり、 $$y[n] = \sum\limits_{m = 0}^{n} \tilde{x}[n-m]h[m]$$ である。 このとき、和のインデックス上限$n$と$h[m]$のインデックス上限$M - 1$の兼ね合いで、$x[n]$と類似の問題が起きる。この問題の煩わしさを避けるため、$h[n]$についても同様の拡張を行う。

\begin{align} \tilde{h}[n] = \begin{cases} h[n] & (0 \leq n \leq N-1)\\ 0 & (N\leq n \leq N + M - 2) \end{cases} \end{align}

最終的に畳み込みは以下のように書ける。 $$ y[n] = \sum\limits_{m = 0}^{n} \tilde{x}[n-m]\tilde{h}[m] \; \; \; (0 \leq n \leq N + M -1) $$

実装

素直にPythonコードに落とし込めばよい。入力の拡張としてのゼロ詰めにはnumpyzeros関数を使う。 地のfor文を使うという、ナイーブな実装なのでPython的には(とても)遅く、あまり実用的ではないのは承知のうえで。

# 前提
# 入力 x[0] ... x[N-1]
# インパルス応答 h[0], ... h[M-1]

import numpy as np

# 出力 y[0] ... y[M+N-2]
y = np.zeros(len(h) + len(x) - 1, dtype=np.float32)

# ゼロづめによる拡張
hzero = np.hstack([h, np.zeros(len(x) - 1)])
xzero = np.hstack([x, np.zeros(len(h) - 1)])

for n in range(0, len(y)):
  for k in range(0, n + 1):
    y[n] = y[n] + hzero[k] * xzero[n - k]

プロットの実例はそのうち追記予定(ほんまか)。

参考

これを読もう。 www.ic.is.tohoku.ac.jp

畳み込みと相互相関の違いとか。 qiita.com

consultの設定 2022

(require 'consult)

;; consult-line ... swiper の代替
;; consult-isearch ... isearch中にconsultインタフェースでクエリを再入力し、isearch再実行
;; consult-multi-occur ... multi-occurの代替
;; consult-focus-line ... クエリにヒットする部分のみを抽出して「表示」する(他が隠れる, narrowing)。
;; その後、C-uつきで呼び出すと、隠れていた部分が表示される(もとに戻る, widen)
;; consult-recent-file ... 最近開いたファイルを選択

(setq consult-async-refresh-delay 0.2)

;; consult-buffer時などにおけるpreview機能の調整
;; (setq consult-preview-key nil) ; 常にプレビューOFF
;; (setq consult-preview-key 'any) ; 常にプレビューON
;; (setq consult-preview-key (kbd "C-M-p")) ; これを押したときだけプレビュー
(consult-customize
 consult-ripgrep consult-git-grep consult-grep
 consult-bookmark consult-recent-file consult-xref
 consult--source-recent-file
 consult--source-project-recent-file
 consult--source-bookmark
 :preview-key (kbd "M-."))

;; カーソル下のシンボルを拾ってconsult-line発動
(defun consult-line-symbol-at-point (&optional at-point)
  (interactive "P")
  (if at-point
      (consult-line (thing-at-point 'symbol))
    (consult-line)))

(define-key isearch-mode-map (kbd "C-:") #'consult-isearch-history) ; 実質的な絞り込み
(define-key isearch-mode-map (kbd "C-;") #'consult-line) ; swiperに対応

;; 絞り込み対象をバッファに限定 : b SPC
;; 絞り込み対象をファイル(recentf)に限定 : f SPC
;; 絞り込み対象をブックマークに限定 : m SPC
;; 絞り込み対象を隠れバッファに限定 : SPC
(global-set-key (kbd "C-x b") #'consult-buffer)

;; consult--source-fileの公式実装では「現在バッファとして保持しているファイル」が
;; ファイル(recentf)の検索対象から除外されるので、
;; それをやめるため単純にitemsにrecentf-listだけを持ってくる。
;; この設定の影響範囲はconsult-bufferのみ。consult-recent-fileは影響を受けない。
(setq consult--source-recent-file
  `(:name     "File"
    :narrow   ?f
    :category file
    :face     consult-file
    :history  file-name-history
    :action   ,#'consult--file-action
    :enabled   ,(lambda () recentf-mode)
    :items ,recentf-list))

(global-set-key (kbd "C-z C-n") #'consult-recent-file)

(global-set-key (kbd "M-g e") 'consult-compile-error)
(global-set-key (kbd "M-g f") 'consult-flymake)
(global-set-key (kbd "M-g g") 'consult-goto-line)
(global-set-key (kbd "M-g M-g") 'consult-goto-line)
(global-set-key (kbd "M-g o") 'consult-outline)
(global-set-key (kbd "M-g m") 'consult-mark)
(global-set-key (kbd "M-g k") 'consult-global-mark)
(global-set-key (kbd "M-g i") 'consult-imenu)
(global-set-key (kbd "M-g I") 'consult-imenu-multi)
(global-set-key (kbd "M-y") 'consult-yank-pop)
(global-set-key (kbd "M-s f") 'consult-find)
(global-set-key (kbd "M-s F") 'consult-locate)
(global-set-key (kbd "M-s g") 'consult-grep)
(global-set-key (kbd "M-s G") 'consult-git-grep)
(global-set-key (kbd "M-s r") 'consult-ripgrep)
(global-set-key (kbd "M-s l") 'consult-line)
(global-set-key (kbd "M-s L") 'consult-line-multi)
(global-set-key (kbd "M-s m") 'consult-multi-occur)
(global-set-key (kbd "M-s k") 'consult-keep-lines)
(global-set-key (kbd "M-s u") 'consult-focus-lines)

;; linum表示中の行番号表示は邪魔なので
(setq consult-goto-line-numbers nil)

;; settings with perspective
;; Use consult-buffer with perspective-el.
;; This would hide the default consult--source-buffer,
;; and show the list of perspective buffers on the top
(require 'perspective)
(declare-function persp-get-buffer-names "perspective")
(with-eval-after-load "perspective"
  (consult-customize consult--source-buffer :hidden t :default nil)
  (defvar consult--source-perspective
    `(:name     "Perspective"
      :narrow   ?s ;; 絞り込みのキー
      :category buffer
      :state    ,#'consult--buffer-state
      :default  t
      :items    ,#'persp-get-buffer-names))
  (add-to-list 'consult-buffer-sources consult--source-perspective))

corfuまわりの設定(vertico, marginalia, orderless, cape, kind-icon, affe)

corfuおよび関連するパッケージの設定をメモとして残す。

  • corfu ... companyパッケージの代わり。カーソル位置での補完UIを提供。
  • vertico ... ido-vertical-modeやivy, selectrumの代わり。ウィンドウ下部(ミニバッファ)で垂直表示な補完UIを提供。
  • consult ... counselの代わり。補完入力を活用し、他のコマンドをラップした便利なコマンド群を提供。
  • marginalia ... consultに表示される候補に「補助情報」を追加する(ファイル属性、ファイル更新日、ファイルサイズなど)。
  • orderless ... 補完候補の絞り込みに活躍。「イニシャル入力」などにより高速かつ柔軟な候補絞り込みを実現。
  • cape ... corfuとの組み合わせが前提。カーソル位置での補完対象が拡張される。
  • kind-icon ... corfu/orderlessと相性の良いパッケージ。各候補の左側に「アイコン」(SVG形式)が追加される。
  • affe ... fuzzy-matchingなconsult-grepやconsult-findに相当するコマンドを提供する。

embarkは割愛。

以下、ほぼ公式の設定を参考にしたもの。verticoについてはvertico-directoryも使う。すごく便利なので。

;; -*- mode: emacs-lisp; coding: utf-8-unix -*-

(require 'corfu)
(corfu-global-mode)
(setq corfu-cycle t) ;; 候補ウィンドウの移動において、上端/下端に達したら下端/上端に回り込む
(setq corfu-auto t) ;; 補完を自動で開始
(setq corfu-quit-no-match 'separator)
(setq corfu-quit-at-boundary nil)

;; 候補スクロール開始位置が、候補ウィンドウの下から何行目か
(setq corfu-scroll-margin 2)

;; ミニバッファでの補完を有効にする
(defun corfu-enable-always-in-minibuffer ()
  "Enable Corfu in the minibuffer if Vertico/Mct are not active."
  (unless (or (bound-and-true-p mct--active)
              (bound-and-true-p vertico--input))
    ;; (setq-local corfu-auto nil) Enable/disable auto completion
    (corfu-mode 1)))
(add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1)

;; TAB cycle if there are only few candidates
(setq completion-cycle-threshold 3)

(defun corfu-beginning-of-prompt ()
  "Move to beginning of completion input."
  (interactive)
  (corfu--goto -1)
  (goto-char (car completion-in-region--data)))

(defun corfu-end-of-prompt ()
  "Move to end of completion input."
  (interactive)
  (corfu--goto -1)
  (goto-char (cadr completion-in-region--data)))

(define-key corfu-map [remap move-beginning-of-line] #'corfu-beginning-of-prompt)
(define-key corfu-map [remap move-end-of-line] #'corfu-end-of-prompt)

(require 'vertico)
(vertico-mode)
(setq vertico-count 20)

(require 'vertico-directory)
(define-key vertico-map (kbd "C-l") #'vertico-directory-up)
(define-key vertico-map "\r" #'vertico-directory-enter)  ;; enter dired
(define-key vertico-map "\d" #'vertico-directory-delete-char)

(require 'marginalia)
(marginalia-mode +1)
;; marginalia-annotatorsをサイクルする
(define-key minibuffer-local-map (kbd "C-M-a") #'marginalia-cycle)

(require 'orderless)
(setq completion-styles '(orderless))

(orderless-define-completion-style orderless+initialism
  (orderless-matching-styles '(orderless-initialism ;;一番最初にinitializm
                               orderless-literal  ;;次にリテラルマッチ
                               orderless-regexp)))

;; (setq completion-category-defaults nil)
(setq completion-category-overrides
      '((eglot (styles orderless+initialism))
        (command (styles orderless+initialism))
        (symbol (styles orderless+initialism))
        (variable (styles orderless+initialism))))
(setq orderless-component-separator #'orderless-escapable-split-on-space)

(require 'cape)
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-tex)
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-keyword)
(add-to-list 'completion-at-point-functions #'cape-abbrev)
(add-to-list 'completion-at-point-functions #'cape-ispell)
(add-to-list 'completion-at-point-functions #'cape-symbol)

;; EmacsのSVG対応コンパイルが必要
(require 'kind-icon)
(setq kind-icon-default-face 'corfu-default)
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)

;; Available commands
;; affe-grep: Filters the content of all text files in the current directory
;; affe-find: Filters the file paths of all files in the current directory
(require 'affe)
(consult-customize affe-grep :preview-key (kbd "M-."))
(defvar affe-orderless-regexp "")
(defun affe-orderless-regexp-compiler (input _type)
  (setq affe-orderless-regexp (orderless-pattern-compiler input))
  (cons affe-orderless-regexp
        (lambda (str) (orderless--highlight affe-orderless-regexp str))))
(setq affe-regexp-compiler #'affe-orderless-regexp-compiler)

Company-modeの設定 2022

書いてみた。

(require 'company)
(add-hook 'after-init-hook 'global-company-mode)
(setq company-minimum-prefix-length 2)

;; キー設定
(define-key company-active-map (kbd "C-n") 'company-select-next)
(define-key company-active-map (kbd "C-p") 'company-select-previous)
(define-key company-active-map (kbd "M-n") nil)
(define-key company-active-map (kbd "M-p") nil)
(define-key company-active-map (kbd "C-m") 'company-complete-selection)

(define-key company-search-map (kbd "C-n") 'company-select-next)
(define-key company-search-map (kbd "C-p") 'company-select-previous)
(define-key company-search-map (kbd "M-n") nil)
(define-key company-search-map (kbd "M-p") nil)


;; 候補に番号を付け、
;; M-1やM-2などM-をつけて押すことで候補選択をショートカットできる
(setq company-show-numbers t)

;; 候補の一番下でさらに下に行こうとすると一番上に戻る
(setq company-selection-wrap-around t)

;; ツールチップ上の候補を右揃え
(setq company-tooltip-align-annotations t)

;; 参考 https://qiita.com/zk_phi/items/9dc373e734d20cd31641
;; シンボルの途中部分を補完する
;; → company にはこの挙動が実装されておらず、カーソルの直後に (空白以外
;; の) 文字がある場合は補完が始まらないため
(require 'company-anywhere)

;; 参考 https://qiita.com/zk_phi/items/9dc373e734d20cd31641
;; ac-dwim時の挙動をcompanyで再現
(require 'company-dwim)
(define-key company-active-map (kbd "TAB") 'company-dwim)
(setq company-frontends
      '(company-pseudo-tooltip-unless-just-one-frontend
        company-dwim-frontend
        company-echo-metadata-frontend))

;; 参考 https://qiita.com/zk_phi/items/9dc373e734d20cd31641
;; company-require-match
;; - never: 補完候補の選択を開始後、補完候補にない文字も打てる
(setq company-require-match 'never)

;; 参考 https://qiita.com/zk_phi/items/9dc373e734d20cd31641
;; 『これは「現在編集中のバッファ、またはそのバッファと同じメジャーモー
;; ドになっているバッファ」から補完候補を探してきてくれるものです。』
(require 'company-same-mode-buffers)
(company-same-mode-buffers-initialize)
(setq company-backends
      `(
        company-capf
        company-dabbrev
        company-semantic
        company-cmake
        company-clang
        company-files

        ;; https://qiita.com/zk_phi/items/9dc373e734d20cd31641
        ;; 「組み込みのキーワードも words-in-same-mode-buffers
        ;; の候補もみんないっしょくたに出てくる」
        ;; (company-keywords :with company-same-mode-buffers)

        (company-dabbrev-code company-gtags company-etags
                              company-keywords)
        company-oddmuse
        company-bbdb
        ,@(unless (version< "24.3.51" emacs-version)
            (list 'company-elisp))
        ,@(unless (version<= "26" emacs-version)
            (list 'company-nxml))
        ,@(unless (version<= "26" emacs-version)
            (list 'company-css))
        ))
(push 'company-same-mode-buffers company-backends) ;先頭に追加

;; lowercaseのみで補完されるのを抑制する(case sensitive)
(eval-when-compile (require 'company-dabbrev))
(setq company-dabbrev-downcase nil)

;; 参考 https://shwaka.github.io/2017/05/03/company-dabbrev-japanese.html
;; company-dabbrevで日本語文字が補完候補に含まれないようにする
(defun edit-category-table-for-company-dabbrev (&optional table)
  (define-category ?s "word constituents for company-dabbrev" table)
  (let ((i 0))
    (while (< i 128)
      (if (equal ?w (char-syntax i))
          (modify-category-entry i ?s table)
        (modify-category-entry i ?s table t))
      (setq i (1+ i)))))
(edit-category-table-for-company-dabbrev)
(setq company-dabbrev-char-regexp "\\cs")

;; company-same-mode-buffers.elにおいて "\\sw"が使用されている箇所を "\\cs"に変更する
;; →日本語文字が補完候補に含まれることを抑制する効果
(defun company-same-mode-buffers-query-construct-any-followed-by (str)
  (cons "\\(?:\\cs\\|\\s_\\)*?" (regexp-quote str)))
(defun company-same-mode-buffers-query-construct-any-word-followed-by (str)
  (cons "\\cs*?" (regexp-quote str)))
(defun company-same-mode-buffers-query-to-regex (lst)
  "Make a regex from a query (list of `query-construct-*' s)."
  (concat "\\_<"
          (mapconcat (lambda (pair) (concat (car pair) "\\(" (cdr pair) "\\)")) lst "")
          "\\(?:\\s_\\|\\cs\\)*"))
(defun company-same-mode-buffers-update-cache (&optional buffer)
  "Put all symbols in the buffer into
`company-same-mode-buffers-cache'."
  (with-current-buffer (or buffer (current-buffer))
    (when (and company-same-mode-buffers-cache-is-dirty
               (derived-mode-p 'prog-mode))
      (let ((tree (gethash major-mode company-same-mode-buffers-cache))
            (symbols (company-same-mode-buffers-search-current-buffer
                      (concat "\\(:?+\\cs\\|\\s_\\)\\{"
                              (number-to-string company-same-mode-buffers-minimum-word-length)
                              ","
                              (number-to-string company-same-mode-buffers-maximum-word-length)
                              "\\}"))))
        (dolist (s symbols)
          (setq tree (company-same-mode-buffers-tree-insert tree s)))
        (puthash major-mode tree company-same-mode-buffers-cache)
        (setq company-same-mode-buffers-cache-is-dirty nil)))))

;; 参考 https://qiita.com/sune2/items/b73037f9e85962f5afb7#company-transformers
;; 補完候補のソート。nilが辞書順
;; (setq company-transformers
;;       '(company-sort-by-occurrence company-sort-by-backend-importance))

;; prescientのアルゴリズム
;; - 直近の選択を上位に移すソーティング
;; - 直近の選択を履歴として保存する
(require 'company-prescient)
(company-prescient-mode 1)
;; →company-transformersに prescient由来のものを追加

;; wordfreq -> MELPAからダウンロード
;; 専用の単語辞書をダウンロード
;; M-x company-wordfreq-download-list
(add-hook 'text-mode-hook (lambda ()
                            (setq-local company-backends
                                        '(company-wordfreq
                                          company-dabbrev
                                          company-capf))
                            (setq-local company-transformers nil)))

;; irony C/C++
(require 'company-irony-c-headers)
(setq company-backends (append company-backends '(company-irony-c-headers)))
(setq company-backends (append company-backends '(company-irony)))
(setq company-backends (append company-backends '(company-reftex-labels)))
(setq company-backends (append company-backends '(company-reftex-citations)))

EmacsでPythonを書く設定2022

はじめに

2022年にあたってPythonまわりのEmacsの設定を再び整理した。
今回もLanguage serverの紹介がメイン。

追記:2024年のものには3rd party plugin に ruffを使うものを書いてみた。language serverはお好みで。
tam5917.hatenablog.com

Python-mode

MELPAからインストール可能。
melpa.org

Language server

Emacsからlanguage serverを使うためにeglotを入れる。

さらにPython用のlanguage serverをインストールする。

pip install 'python-lsp-server[all]'

以前の記事ではpython-language-serverを入れていたが、現在メンテナンスが停止している。
github.com

そこでfork版のpython-lsp-serverを入れたというわけだ。
github.com

3rd Party Plugins

それぞれpython-lsp-serverに対応している。

pip3 install python-lsp-isort
pip3 install python-lsp-black

python-lsp-isortはimport順を自動でソートしてくれるパッケージである。

python-lsp-blackはblackの仕様に沿ってコードをフォーマットしてくれるパッケージである。

これらはeglot-format-bufferからまとめて起動できるが、バッファをファイルに保存する際にhookとして引っ掛けておくことにした。

設定

;; Python
(setq auto-mode-alist (cons '("\\.py$" . python-mode) auto-mode-alist))
(setq interpreter-mode-alist (cons '("python" . python-mode)
                                   interpreter-mode-alist))

(require 'eglot)

;; Python-mode起動時にeglotを有効化
(add-hook 'python-mode-hook 'eglot-ensure)

;; 保存時に自動整形 (eglot)
(add-hook 'python-mode-hook
          #'(lambda ()
              (add-hook 'before-save-hook
                        'eglot-format-buffer nil t)))

;; flycheckはOFFにして、flymakeを使うようにしている。
;; 以下のパッケージを使うと、メッセージがカーソル位置に出現するので、
;; エコーエリアと干渉しないのが良い。お好みで。
;; (with-eval-after-load "flymake"
;;   (require 'flymake-diagnostic-at-point)
;;   (add-hook 'flymake-mode-hook #'flymake-diagnostic-at-point-mode))

LightGBM (LGBM) with Optunaで多クラス分類を行わせるときのパラメタ設定

例えばこんな感じ(10クラス)。

params = {
    "objective": "multiclass",
    "num_class": 10,
    "metric": "multi_logloss",
    "boosting_type": "gbdt",
    "verbosity": -1,
}

多クラス分類させるときは、"metric"に"multi_logloss"を設定する。

残りのパラメタ調整はOptunaにおまかせ!