2
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?

機械学習環境を整備したい

2
Last updated at Posted at 2025-12-11

はじめに

研究のために Python 環境について色々調べたのでまとめました.
タイトルは機械学習ですが,Python プロジェクト全般で使えると思います.

開発環境

Python 開発で必須なものの一つが仮想環境ですが,これは uv で構築しています.
こちらは今回の Advent Calendar 含め沢山記事があるので割愛します.

フォーマッタは VSCode 拡張の Ruff を使用しています.

あと,私は使っていませんが型チェックなどを行ってくれる mypy なんかも有用だと思います.

ディレクトリ構成

言わずもがなファイル,ディレクトリ整理はどんなプロジェクトでもしましょう.
ディレクトリテンプレートの扱いに優れる Cookiecutter などを使用すれば,複数プロジェクトで同じ構成を使用する場合に一貫性を持たせられます.
今のディレクトリ構成 (概略) はこんな感じです ( 参考はこちらの記事 + ChatGPT ) .

project/
├─ src/
│   ├─ config/
│   ├─ models/
│   ├─ train/
│   └─ visualizer/
├─ outputs/
│   ├─ logs/
│   ├─ models/
│   └─ pred/
└─ main.py

Python ライブラリ

最後にコーディングの話です.
汚いコードは罪ですので可読性が高く保守しやすいコードを書きたいですよね.
個人的に「Python 書きづれ~」と思ったときにライブラリを調べたもののまとめです.
こういうものは枚挙に暇が無いですし,ここより詳しいことが書いてある記事がたくさんあるので,「へ~こんなのもあるのか」くらいの温度感で見てもらえると嬉しいです.

標準ライブラリ

pathlib

パスを変数管理するときは os モジュールではなく pathlib が便利です.
os.path では,関数の入れ子の発生が多いため,可読性が下がります.
pathlib であればメソッドチェーンが効くし,パスの結合に関数を使う必要もないため美しく書けます.
例えば

# os
os.path.exists(os.path.join("path", "to", "file"))

# pathlib
from pathlib import Path
Path("path", "to", "file").exists()
## or
(Path("path") / "to" / "file").exists()

こんな感じで使えます.
多くのライブラリのパスを引数に取る関数では Path オブジェクトも扱ってくれるため,わざわざ str(path) とする必要は少ないです.

dataclasses

データを文字列をキーにして dict で保存していませんか?
このように保存すると

  • 外からアクセスするときにキーが分かりにくい
  • 保存されているデータの型が分かりにくい

という欠点があります.
代わりに dataclass を使いましょう.
例えば以下のように実装すればいいです.

from dataclasses import dataclass

@dataclass
class Game:
    name: str # requires type annotation
    price: int
    review: float
    is_released: bool

これを使えば

  • Game.name のようにドット演算子でアクセスできる
    • 多くのエディタで予測が効く (vim 派は知らない)
  • 型が宣言されているため処理が書きやすい

ということです.

logging

なんらかのログを取るとき,毎回

with open("log_file.log", "a") as f:

を書きたくはないですよね.
ログ出力はそれ専用の logging を使って取ると処理を書くのも楽です.

from logging import getLogger, FileHandler

# 最低限のセットアップ
logger = getLogger(__name__)
logger.setLevel(INFO)
logger.setLevel(DEBUG)
filehandler = FileHandler(log_file_path, encoding="utf-8")
logger.addHandler(filehandler)

# logger.level() で level に合う出力
logger.debug("starg logging")

メッセージのフォーマットや出力先を柔軟に設定することもできます.

外部ライブラリ

PyYAML + dacite

学習パラメータなどは YAMLJSON で保存するとモデルを動かすときに取得しやすいです.
今回は dataclassYAML で扱うことを考えます.

  • dataclassYAML で保存
from dataclasses import asdict
import yaml

game = Game(name="mine sweeper", ...) # dataclass
with Path.open(yaml_path, "w") as f:
    yaml.safe_dump(asdict(game), f)
  • YAML から dataclass を読み込み

yaml.safe_load() するだけでは dict になってしまうため,dacite.from_dict() を使用して dataclass の型に合うように変換します.

import yaml
from dacite import from_dict

with Path.open(yaml_path, "r") as f:
    # game: dict
    game = yaml.safe_load(f)

    # game: Game
    game = from_dict(data_class=Game, data=game) 

これでモデルのバージョン管理もしやすいですね.

参考にした記事

Ruff の設定

Cookiecutter

logging

dacite

2
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
2
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?