100本ノック / Python / データ分析のためのPython入門100本ノック

エラー表示の読み方を理解する

Polars入門:製造ラインデータを高速・安全に読み解く

100本ノック 第8章(No.071〜No.080):Polars入門

本記事は「データ分析のための Python 入門 100本ノック」シリーズの 第8章 です。
第7章(No.061〜070)では NumPy による配列演算を学びました。
本章では Polars ― pandas より高速でメモリ効率が高い次世代 DataFrame ライブラリ ― を使い、
電子部品工場の月次生産実績データを読み込み・確認・集計する基本操作を習得します。

[!NOTE] 本資料は、数理工房 (もしくは代表である和山個人) が過去に企業研修において使用した notebook を 企業様の許可を得て再構成・編集のうえ公開しています。
掲載データはすべて架空のものであり、実在する企業・工場・数値とは一切関係ありません。

はじめに:この記事で扱う製造業の実務課題

電子部品製造工場(プリント基板実装ライン)の生産管理チーム K さんの月初業務です。

毎月初旬の定例作業
  1. 5ラインの日次生産実績 CSV を管理システムからエクスポート(20営業日分 × 5ライン)
  2. CSV を Excel で開いて目視で行数・列数を確認(「今月は何行あるんだっけ?」)
  3. 各列のデータ型が正しいか手動チェック(日付が文字列になっていないか?)
  4. 基本統計量(平均・最大・最小・標準偏差)を関数で手計算
  5. 生産数が異常に少ない日・欠損日を目視でスクロールして探す

Python の Polars を使えば、
数万行の CSV を pandas より最大5倍速く 読み込み、
型確認・統計量・異常値検出を 3〜5行のコード で完結できます。

現場でよくある状況

場面課題
CSV 読み込みの遅さ1ヶ月分の CSV(数万行)を pandas で読むと体感で遅い
型の不一致日付列が object(文字列)のまま集計できない
列名の確認「この列って何列目だっけ?」と毎回 Excel で確認
行数の把握「欠損日ないか?」を目視スクロールで確認
統計量の確認describe() の結果を解釈できず活用できていない

「データを読んだ後、まず確認すべき5つのこと」 ―
行数・列数・列名・型・統計量 ― を本章で体系的に身につけます。

なぜこの問題は判断が難しいのか

Polars は pandas と似ているようで、いくつか重要な違いがあります。

  1. df["列名"] vs df.select("列名")
    df["列名"]pl.Series を返しますが、df.select("列名")pl.DataFrame を返します。
    用途に応じて使い分ける必要があります。

  2. Eager モードと Lazy モードの違い
    pl.read_csv() は即座に実行する Eager モード です。
    大規模データには pl.scan_csv().collect()Lazy モード が効率的です。
    本章では基礎として Eager モードを扱います。

  3. describe() の戻り値が DataFrame
    Polars の describe()DataFrame を返します。
    数値型以外の列も含めた統計量が表示されるため、列の型確認が先に必要です。

  4. nullNaN の違い
    Polars では欠損値を null(= Python の None)で表現します。
    NaN は浮動小数点の特殊値として別途区別されます。

今回扱うノックの全体像

No.タイトル製造業での活用場面
071Polarsの役割を理解するpandas との違いを整理し、大規模製造データへの適用可否を判断
072Polarsをimportするインポートとバージョン確認・基本設定
073Seriesを作成する不良数・生産数など1列データの扱い
074DataFrameを作成するライン別生産実績テーブルの構築
075CSVをDataFrameとして読み込む月次生産実績 CSV の読み込みと基本確認
076先頭行と末尾行を確認する読み込み直後の目視確認(head / tail)
077行数・列数を確認する欠損日・余分行の有無チェック(shape)
078列名を確認する列名一覧の確認と正規化
079データ型を確認する日付・数値型の正しい型確認
080基本統計量を確認する生産数・不良率の平均・最大・最小・標準偏差の一括確認

Python 環境の準備

import subprocess, sys

res = subprocess.run(["sw_vers", "-productVersion"], capture_output=True, text=True)
print(f"macOS : {res.stdout.strip()}")
print(f"Python: {sys.version}")
macOS : 26.3
Python: 3.11.9 (main, Apr 19 2024, 11:43:47) [Clang 14.0.6 ]
import numpy as np
import polars as pl
import matplotlib
import matplotlib.pyplot as plt
import csv, os, datetime

matplotlib.rcParams['font.family'] = 'Hiragino Maru Gothic Pro'
%config InlineBackend.figure_format = 'svg'
np.random.seed(42)

print("ライブラリ読み込み完了")
print(f"  NumPy     : {np.__version__}")
print(f"  Polars    : {pl.__version__}")
print(f"  Matplotlib: {matplotlib.__version__}")
ライブラリ読み込み完了
  NumPy     : 1.26.4
  Polars    : 1.42.1
  Matplotlib: 3.9.2

架空データの作成

想定シナリオ: 電子部品製造工場 / プリント基板実装ライン 生産管理チーム
期間: 2024年1月(20営業日)
管理対象: 5製品ライン(基板種・単価・基準不良率が異なる)
出力: 月次生産実績 CSV(production_jan2024.csv

# 設定
np.random.seed(42)
LINE_IDS   = ["PCB-A1", "PCB-A2", "PCB-B1", "PCB-B2", "PCB-C1"]
LINE_NAMES = {
    "PCB-A1": "基板A-小型", "PCB-A2": "基板A-中型",
    "PCB-B1": "基板B-小型", "PCB-B2": "基板B-高密度", "PCB-C1": "基板C-大型",
}
BASE_PROD = {"PCB-A1": 480, "PCB-A2": 360, "PCB-B1": 520, "PCB-B2": 280, "PCB-C1": 200}
BASE_DR   = {"PCB-A1": 0.018, "PCB-A2": 0.022, "PCB-B1": 0.015, "PCB-B2": 0.031, "PCB-C1": 0.025}
UNIT_PRICE = {"PCB-A1": 850, "PCB-A2": 1200, "PCB-B1": 760, "PCB-B2": 2400, "PCB-C1": 3200}

# 2024年1月の営業日(月〜金、20日間)
biz_days, d = [], datetime.date(2024, 1, 4)
while len(biz_days) < 20:
    if d.weekday() < 5:
        biz_days.append(d)
    d += datetime.timedelta(days=1)

# データ生成
records = []
for date in biz_days:
    for line in LINE_IDS:
        prod     = max(10, int(np.random.normal(BASE_PROD[line], BASE_PROD[line] * 0.05)))
        dr       = max(0.0, np.random.normal(BASE_DR[line], 0.005))
        defects  = int(prod * dr)
        work_h   = round(min(9.0, max(6.0, np.random.normal(7.8, 0.3))), 1)
        machine  = f"M{LINE_IDS.index(line)+1:02d}-{np.random.randint(1, 4)}"
        records.append({
            "date": date.strftime("%Y-%m-%d"),
            "line": line,
            "line_name": LINE_NAMES[line],
            "production_count": prod,
            "defect_count": defects,
            "working_hours": work_h,
            "unit_price": UNIT_PRICE[line],
            "machine_id": machine,
        })

# CSV 保存
CSV_PATH = "production_jan2024.csv"
with open(CSV_PATH, "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=records[0].keys())
    writer.writeheader()
    writer.writerows(records)

print(f"生成完了: {CSV_PATH}")
print(f"  レコード数 : {len(records):,} 行")
print(f"  列数       : {len(records[0])} 列")
print(f"  期間       : {records[0]['date']}{records[-1]['date']}")
print(f"  ライン数   : {len(LINE_IDS)} ライン")
生成完了: production_jan2024.csv
  レコード数 : 100 行
  列数       : 8 列
  期間       : 2024-01-04 〜 2024-01-31
  ライン数   : 5 ライン

No.071:Polarsの役割を理解する

実務での意味

製造現場の生産実績データは日々蓄積され、数ヶ月分になると 数万〜数十万行 に達します。
従来の pandas でも十分に扱えますが、Polars は pandas より高速でメモリ効率が高く
大規模データへの対応力が求められる製造業の DX 基盤に適しています。

Polars を選ぶ判断基準:

  • 処理対象が 10万行以上
  • 集計・フィルタ処理を 繰り返し自動実行(日次バッチ処理など)
  • 複数のデータソースを結合して分析する場面

分析・モデル化の考え方

Polars は Apache Arrow 形式をベースにした列指向ストレージを採用しています。
「不良数列だけ合計する」といった列単位の演算が特に高速です。

比較項目pandasPolars
ベース形式NumPyApache Arrow
速度(大規模)標準最大5倍以上
メモリ使用量多い少ない
欠損値の型NaN(float)null(型非依存)
遅延評価(Lazy)なしあり(scan_csvcollect

Pythonで確認する

# Polars のバージョン確認と主要クラス一覧
print(f"Polars バージョン: {pl.__version__}")
print()

# 主要クラス確認
for cls in ["DataFrame", "Series", "LazyFrame", "Expr"]:
    print(f"  pl.{cls}")
print()

# 行数を変えながら DataFrame 作成時間を簡易計測
import time

print(f"{'行数':>10s}  {'Polars 作成時間(ms)':>22s}")
print("-" * 38)
for n in [1_000, 10_000, 100_000]:
    data = {"val": list(range(n))}
    t0 = time.perf_counter()
    _ = pl.DataFrame(data)
    t1 = time.perf_counter()
    print(f"{n:>10,d}  {(t1 - t0) * 1000:>20.3f} ms")
Polars バージョン: 1.42.1

  pl.DataFrame
  pl.Series
  pl.LazyFrame
  pl.Expr

        行数         Polars 作成時間(ms)
--------------------------------------
     1,000                 2.601 ms
    10,000                 0.881 ms
   100,000                 0.622 ms

結果の読み取り

  • Polars は小規模データでも高速ですが、行数が増えるほど優位性が顕著 になります。
  • 製造現場で月次・年次のバッチ集計を行う場合、Polars への移行を検討する価値があります。
  • DataFrame, Series, LazyFrame, Expr の4つのクラスが Polars の核心です。

No.072:Polarsをimportする

実務での意味

ライブラリの正しいインポートは分析の出発点です。
バージョンを明示的に確認する習慣は、チーム開発や本番環境への移行時に
「動いていたのに急に動かなくなった」問題を防ぐために重要です。

分析・モデル化の考え方

Polars は import polars as pl という慣習が定着しています(pandas の pd に対応)。
製造データ分析のプロジェクトでは requirements.txt
polars>=1.0 のようにバージョンを固定すると再現性が高まります。

Pythonで確認する

# Polars のインポートとバージョン確認
import polars as pl
import sys

print("=" * 42)
print("  実行環境の確認")
print("=" * 42)
print(f"  Python    : {sys.version.split()[0]}")
print(f"  Polars    : {pl.__version__}")
print(f"  NumPy     : {np.__version__}")
print(f"  Matplotlib: {matplotlib.__version__}")
print("=" * 42)
print()

# 典型的な import スタイルの確認
print("推奨インポートスタイル:")
print("  import polars as pl          # Polars 本体")
print("  from polars import col, lit  # よく使う関数を短縮形で使う場合")
==========================================
  実行環境の確認
==========================================
  Python    : 3.11.9
  Polars    : 1.42.1
  NumPy     : 1.26.4
  Matplotlib: 3.9.2
==========================================

推奨インポートスタイル:
  import polars as pl          # Polars 本体
  from polars import col, lit  # よく使う関数を短縮形で使う場合

結果の読み取り

  • pl.__version__ でバージョンが確認できます。
  • プロジェクトの開始時に実行環境を記録しておくことで、
    後から「どの環境で実行したか」を追跡できます。
  • Polars の API は pandas に比べて変更が多いため、バージョン固定は特に重要です。

No.073:Seriesを作成する

実務での意味

Series は1つの列(1次元データ)を表す Polars の基本データ構造です。
製造現場では「ある日の全ラインの不良数リスト」「5ラインの平均稼働率リスト」など、
単一の指標をまとめて管理するのに使います。

分析・モデル化の考え方

pl.Series を作成する際は 型を明示することが推奨されます。
Polars は型推論が得意ですが、製造データでは整数/浮動小数点の区別が集計結果に影響します。

Polars 型製造データでの用途
Int32 / Int64生産数、不良数(整数)
Float64不良率、稼働率(小数)
Stringライン名、機器ID
Date生産日付

Pythonで確認する

# 5ラインの1日分不良数 Series
defect_s = pl.Series("defect_count", [8, 12, 5, 18, 7], dtype=pl.Int32)
print("不良数 Series:")
print(defect_s)
print()

# 稼働率 Series
avail_s = pl.Series(
    "availability_rate",
    [0.952, 0.881, 0.975, 0.843, 0.921],
    dtype=pl.Float64,
)
print("稼働率 Series:")
print(avail_s)
print()

# Series の属性
print("Series 属性:")
print(f"  名前   : {defect_s.name}")
print(f"  型     : {defect_s.dtype}")
print(f"  要素数 : {len(defect_s)}")
print()

# 基本演算
print("不良数 Series の基本統計量:")
print(f"  合計  : {defect_s.sum()}")
print(f"  平均  : {defect_s.mean():.2f}")
print(f"  最大  : {defect_s.max()}")
print(f"  最小  : {defect_s.min()}")
不良数 Series:
shape: (5,)
Series: 'defect_count' [i32]
[
	8
	12
	5
	18
	7
]

稼働率 Series:
shape: (5,)
Series: 'availability_rate' [f64]
[
	0.952
	0.881
	0.975
	0.843
	0.921
]

Series 属性:
  名前   : defect_count
  型     : Int32
  要素数 : 5

不良数 Series の基本統計量:
  合計  : 50
  平均  : 10.00
  最大  : 18
  最小  : 5

結果の読み取り

  • pl.Seriesdtype を指定することで、型の不一致によるエラーを未然に防ぎます。
  • .sum(), .mean(), .max(), .min() が直接呼べるため、
    「5ラインの不良数合計を瞬時に確認」といった操作が簡潔に書けます。
  • 不良数合計 50 から、この1日で 50個の不良品が発生 したことが読み取れます。
    PCB-B2 の不良数 18 が最多で、重点管理が必要なラインといえます。

No.074:DataFrameを作成する

実務での意味

DataFrame は複数の列を持つ表形式データです。
製造現場では「ライン名・生産数・不良数・稼働率を1つのテーブルにまとめる」
という操作が基本になります。

分析・モデル化の考え方

DataFrame の主な作成方法:

  1. 辞書から作成(最もシンプル・架空データの検証に最適)
  2. Series のリストから作成
  3. CSV / Parquet ファイルから読み込み(No.075で扱う)

Pythonで確認する

# 2024年1月4日(第1営業日)の5ライン生産実績 DataFrame
df_day1 = pl.DataFrame({
    "line":             ["PCB-A1", "PCB-A2", "PCB-B1", "PCB-B2", "PCB-C1"],
    "line_name":        ["基板A-小型", "基板A-中型", "基板B-小型", "基板B-高密度", "基板C-大型"],
    "production_count": [472, 351, 515, 274, 198],
    "defect_count":     [8,   12,  5,   18,  7],
    "working_hours":    [7.8, 8.1, 7.6, 7.9, 8.0],
    "unit_price":       [850, 1200, 760, 2400, 3200],
})

print("2024年1月4日 生産実績 DataFrame:")
print(df_day1)
print()

# 各列の型
print("各列のデータ型:")
for col, dtype in zip(df_day1.columns, df_day1.dtypes):
    print(f"  {col:22s}: {dtype}")
print()

# 不良率列を追加(列追加の予習)
df_day1_ext = df_day1.with_columns(
    (pl.col("defect_count") / pl.col("production_count") * 100)
    .round(2)
    .alias("defect_rate_pct")
)
print("不良率(%) 追加後:")
print(df_day1_ext.select(["line", "production_count", "defect_count", "defect_rate_pct"]))
2024年1月4日 生産実績 DataFrame:
shape: (5, 6)
┌────────┬──────────────┬──────────────────┬──────────────┬───────────────┬────────────┐
│ line   ┆ line_name    ┆ production_count ┆ defect_count ┆ working_hours ┆ unit_price │
│ ---    ┆ ---          ┆ ---              ┆ ---          ┆ ---           ┆ ---        │
│ str    ┆ str          ┆ i64              ┆ i64          ┆ f64           ┆ i64        │
╞════════╪══════════════╪══════════════════╪══════════════╪═══════════════╪════════════╡
│ PCB-A1 ┆ 基板A-小型   ┆ 472              ┆ 8            ┆ 7.8           ┆ 850        │
│ PCB-A2 ┆ 基板A-中型   ┆ 351              ┆ 12           ┆ 8.1           ┆ 1200       │
│ PCB-B1 ┆ 基板B-小型   ┆ 515              ┆ 5            ┆ 7.6           ┆ 760        │
│ PCB-B2 ┆ 基板B-高密度 ┆ 274              ┆ 18           ┆ 7.9           ┆ 2400       │
│ PCB-C1 ┆ 基板C-大型   ┆ 198              ┆ 7            ┆ 8.0           ┆ 3200       │
└────────┴──────────────┴──────────────────┴──────────────┴───────────────┴────────────┘

各列のデータ型:
  line                  : String
  line_name             : String
  production_count      : Int64
  defect_count          : Int64
  working_hours         : Float64
  unit_price            : Int64

不良率(%) 追加後:
shape: (5, 4)
┌────────┬──────────────────┬──────────────┬─────────────────┐
│ line   ┆ production_count ┆ defect_count ┆ defect_rate_pct │
│ ---    ┆ ---              ┆ ---          ┆ ---             │
│ str    ┆ i64              ┆ i64          ┆ f64             │
╞════════╪══════════════════╪══════════════╪═════════════════╡
│ PCB-A1 ┆ 472              ┆ 8            ┆ 1.69            │
│ PCB-A2 ┆ 351              ┆ 12           ┆ 3.42            │
│ PCB-B1 ┆ 515              ┆ 5            ┆ 0.97            │
│ PCB-B2 ┆ 274              ┆ 18           ┆ 6.57            │
│ PCB-C1 ┆ 198              ┆ 7            ┆ 3.54            │
└────────┴──────────────────┴──────────────┴─────────────────┘

結果の読み取り

  • 辞書からの DataFrame 作成は直感的で、架空データでのロジック検証に最適です。
  • with_columns で不良率列を追加しました(No.083 でより詳しく扱います)。
  • PCB-B2(基板B-高密度) の不良率が 6.57% と最も高く、重点管理ラインです。
  • PCB-B1(基板B-小型) の不良率が 0.97% と最も低く、安定したラインです。

No.075:CSVをDataFrameとして読み込む

実務での意味

製造現場では生産管理システムからのデータエクスポートが CSV 形式であることが多く、
「毎月 CSV を読み込んで集計する」というワークフローが一般的です。
Polars の pl.read_csv() は pandas の pd.read_csv() より高速で、
大規模CSV でも型推論が正確 です。

分析・モデル化の考え方

CSV 読み込み時の重要なオプション:

オプション意味製造データでの用途
try_parse_dates=True日付列を自動で Date 型に変換生産日付列の正規化
null_values="NA"欠損値の表現文字列を指定管理システム固有の欠損表現
n_rows=100先頭 n 行だけ読む大規模 CSV の確認
separator=","区切り文字を指定タブ区切りなど

Pythonで確認する

# CSV の読み込み
csv_path = "production_jan2024.csv"
df = pl.read_csv(csv_path, try_parse_dates=True)

print("CSV 読み込み完了:")
print(f"  ファイル  : {csv_path}")
print(f"  形状      : {df.shape[0]} 行 × {df.shape[1]} 列")
print()

# 読み込んだ DataFrame を表示(最初の3行)
print("DataFrame の内容(最初の3行):")
print(df.head(3))
print()

# ファイルサイズ確認
file_size = os.path.getsize(csv_path)
print(f"ファイルサイズ: {file_size:,} バイト ({file_size / 1024:.1f} KB)")
CSV 読み込み完了:
  ファイル  : production_jan2024.csv
  形状      : 100 行 × 8 列

DataFrame の内容(最初の3行):
shape: (3, 8)
┌────────────┬────────┬────────────┬────────────┬────────────┬────────────┬────────────┬───────────┐
│ date       ┆ line   ┆ line_name  ┆ production ┆ defect_cou ┆ working_ho ┆ unit_price ┆ machine_i │
│ ---        ┆ ---    ┆ ---        ┆ _count     ┆ nt         ┆ urs        ┆ ---        ┆ d         │
│ date       ┆ str    ┆ str        ┆ ---        ┆ ---        ┆ ---        ┆ i64        ┆ ---       │
│            ┆        ┆            ┆ i64        ┆ i64        ┆ f64        ┆            ┆ str       │
╞════════════╪════════╪════════════╪════════════╪════════════╪════════════╪════════════╪═══════════╡
│ 2024-01-04 ┆ PCB-A1 ┆ 基板A-小型 ┆ 491        ┆ 8          ┆ 8.0        ┆ 850        ┆ M01-3     │
│ 2024-01-04 ┆ PCB-A2 ┆ 基板A-中型 ┆ 387        ┆ 6          ┆ 7.8        ┆ 1200       ┆ M02-3     │
│ 2024-01-04 ┆ PCB-B1 ┆ 基板B-小型 ┆ 527        ┆ 10         ┆ 7.6        ┆ 760        ┆ M03-1     │
└────────────┴────────┴────────────┴────────────┴────────────┴────────────┴────────────┴───────────┘

ファイルサイズ: 5,628 バイト (5.5 KB)

結果の読み取り

  • try_parse_dates=True を指定することで、date 列が自動的に Date 型として読み込まれます。
    pandas で parse_dates=["date"] と列名を明示する必要があるのと比べてシンプルです。
  • 読み込み直後に df.shape で行数・列数を確認する習慣を持つと、
    「データが正しく読み込まれたか」を素早く検証できます。
  • 今回の CSV は 5ライン × 20営業日 = 100行 であることが確認できます。

No.076:先頭行と末尾行を確認する

実務での意味

CSV 読み込み直後に先頭・末尾の数行を目視確認することは、
「データが期待通りに読み込まれたか」を素早く確認するための基本習慣です。
先頭行で列構造・型・値の範囲を確認し、末尾行でデータの終端(欠損・余分な行)を確認します。

分析・モデル化の考え方

  • df.head(n): 先頭 n 行(デフォルト n=5)
  • df.tail(n): 末尾 n 行(デフォルト n=5)

製造データでは「月末の行が欠損していないか」「最終行に合計行が混入していないか」を
tail() で確認するのが効果的です。

Pythonで確認する

print("先頭 5 行 (df.head(5)):")
print(df.head(5))
print()

print("末尾 5 行 (df.tail(5)):")
print(df.tail(5))
print()

# データ期間と種類の確認
dates = df["date"].unique().sort()
print(f"データ期間  : {dates[0]}{dates[-1]}")
print(f"ユニーク日数: {len(dates)} 日")
print()
print("ラインの種類:")
for line in df["line"].unique().sort().to_list():
    print(f"  {line}")
先頭 5 行 (df.head(5)):
shape: (5, 8)
┌────────────┬────────┬────────────┬────────────┬────────────┬────────────┬────────────┬───────────┐
│ date       ┆ line   ┆ line_name  ┆ production ┆ defect_cou ┆ working_ho ┆ unit_price ┆ machine_i │
│ ---        ┆ ---    ┆ ---        ┆ _count     ┆ nt         ┆ urs        ┆ ---        ┆ d         │
│ date       ┆ str    ┆ str        ┆ ---        ┆ ---        ┆ ---        ┆ i64        ┆ ---       │
│            ┆        ┆            ┆ i64        ┆ i64        ┆ f64        ┆            ┆ str       │
╞════════════╪════════╪════════════╪════════════╪════════════╪════════════╪════════════╪═══════════╡
│ 2024-01-04 ┆ PCB-A1 ┆ 基板A-小型 ┆ 491        ┆ 8          ┆ 8.0        ┆ 850        ┆ M01-3     │
│ 2024-01-04 ┆ PCB-A2 ┆ 基板A-中型 ┆ 387        ┆ 6          ┆ 7.8        ┆ 1200       ┆ M02-3     │
│ 2024-01-04 ┆ PCB-B1 ┆ 基板B-小型 ┆ 527        ┆ 10         ┆ 7.6        ┆ 760        ┆ M03-1     │
│ 2024-01-04 ┆ PCB-B2 ┆ 基板B-高密 ┆ 272        ┆ 10         ┆ 8.3        ┆ 2400       ┆ M04-1     │
│            ┆        ┆ 度         ┆            ┆            ┆            ┆            ┆           │
│ 2024-01-04 ┆ PCB-C1 ┆ 基板C-大型 ┆ 182        ┆ 4          ┆ 7.5        ┆ 3200       ┆ M05-3     │
└────────────┴────────┴────────────┴────────────┴────────────┴────────────┴────────────┴───────────┘

末尾 5 行 (df.tail(5)):
shape: (5, 8)
┌────────────┬────────┬────────────┬────────────┬────────────┬────────────┬────────────┬───────────┐
│ date       ┆ line   ┆ line_name  ┆ production ┆ defect_cou ┆ working_ho ┆ unit_price ┆ machine_i │
│ ---        ┆ ---    ┆ ---        ┆ _count     ┆ nt         ┆ urs        ┆ ---        ┆ d         │
│ date       ┆ str    ┆ str        ┆ ---        ┆ ---        ┆ ---        ┆ i64        ┆ ---       │
│            ┆        ┆            ┆ i64        ┆ i64        ┆ f64        ┆            ┆ str       │
╞════════════╪════════╪════════════╪════════════╪════════════╪════════════╪════════════╪═══════════╡
│ 2024-01-31 ┆ PCB-A1 ┆ 基板A-小型 ┆ 520        ┆ 10         ┆ 8.2        ┆ 850        ┆ M01-1     │
│ 2024-01-31 ┆ PCB-A2 ┆ 基板A-中型 ┆ 355        ┆ 9          ┆ 7.6        ┆ 1200       ┆ M02-3     │
│ 2024-01-31 ┆ PCB-B1 ┆ 基板B-小型 ┆ 484        ┆ 6          ┆ 7.9        ┆ 760        ┆ M03-1     │
│ 2024-01-31 ┆ PCB-B2 ┆ 基板B-高密 ┆ 286        ┆ 6          ┆ 7.9        ┆ 2400       ┆ M04-1     │
│            ┆        ┆ 度         ┆            ┆            ┆            ┆            ┆           │
│ 2024-01-31 ┆ PCB-C1 ┆ 基板C-大型 ┆ 198        ┆ 4          ┆ 8.2        ┆ 3200       ┆ M05-3     │
└────────────┴────────┴────────────┴────────────┴────────────┴────────────┴────────────┴───────────┘

データ期間  : 2024-01-04 〜 2024-01-31
ユニーク日数: 20 日

ラインの種類:
  PCB-A1
  PCB-A2
  PCB-B1
  PCB-B2
  PCB-C1

結果の読み取り

  • 先頭行で日付・ライン名・各数値が正しく読み込まれていることを確認できます。
  • 末尾行で最終営業日(2024-01-31 周辺)のデータが欠損なく含まれていることを確認できます。
  • ユニーク日数が 20日 = 1月の営業日数と一致しており、欠損日がないことが確認できます。
  • df["date"].unique().sort() でデータの日付範囲を素早く把握できます。

No.077:行数・列数を確認する

実務での意味

shape は DataFrame の規模(行数 × 列数)を確認する最初の操作です。
予期しない行数(例:余分な集計行・ヘッダー重複)は、
集計結果の誤りに直結します。月次処理の冒頭で必ず確認するようにしましょう。

期待値との照合

  • 5ライン × 20営業日 = 100行 であることを確認
  • 8列(date, line, line_name, production_count, defect_count, working_hours, unit_price, machine_id)

分析・モデル化の考え方

df.shape はタプル (行数, 列数) を返します。
実務では assert df.shape[0] == 100 のように自動チェックを組み込むと
「行が足りない月」を見落とすリスクを防げます。

Pythonで確認する

# shape の確認
rows, cols = df.shape
print(f"DataFrame の形状: {rows} 行 × {cols} 列")
print()

# 期待値との照合
expected_rows = 5 * 20
expected_cols = 8

print("期待値との照合:")
ok_r = "✓ 期待通り" if rows == expected_rows else f"✗ 期待値 {expected_rows} 行"
ok_c = "✓ 期待通り" if cols == expected_cols else f"✗ 期待値 {expected_cols} 列"
print(f"  行数: {rows:3d} 行  ({ok_r})")
print(f"  列数: {cols:3d} 列  ({ok_c})")
print()

# 別の取得方法
print(f"行数 (len)  : {len(df):,} 行")
print(f"列数 (width): {df.width} 列")
print()

# ライン別行数(= 営業日数)の確認
line_counts = (
    df.group_by("line").agg(pl.len().alias("day_count")).sort("line")
)
print("ライン別 行数(営業日数):")
print(line_counts)
DataFrame の形状: 100 行 × 8 列

期待値との照合:
  行数: 100 行  (✓ 期待通り)
  列数:   8 列  (✓ 期待通り)

行数 (len)  : 100 行
列数 (width): 8 列

ライン別 行数(営業日数):
shape: (5, 2)
┌────────┬───────────┐
│ line   ┆ day_count │
│ ---    ┆ ---       │
│ str    ┆ u32       │
╞════════╪═══════════╡
│ PCB-A1 ┆ 20        │
│ PCB-A2 ┆ 20        │
│ PCB-B1 ┆ 20        │
│ PCB-B2 ┆ 20        │
│ PCB-C1 ┆ 20        │
└────────┴───────────┘

結果の読み取り

  • df.shape で (100, 8) = 100行 × 8列 が確認でき、期待値と一致しています。
  • df.width は列数の別名プロパティです(pandas の df.shape[1] と同等)。
  • ライン別行数がすべて 20行(20営業日)と一致していれば、欠損日なしと判断できます。
  • もしいずれかのラインが 20行未満であれば、その日の生産データが欠損している可能性があります。

No.078:列名を確認する

実務での意味

列名の確認は「どの情報がこの DataFrame に含まれているか」を把握する基本操作です。
製造現場では複数の担当者が CSV を作成するため、
同じ意味の列が "生産数", "prod_count", "ProdQty" など
表記が統一されていないことがよくあります。列名の正規化は分析の前提作業です。

分析・モデル化の考え方

  • df.columns: 列名のリストを返す
  • df.schema: 列名と型の辞書({列名: dtype})を返す
  • 列名の正規化には df.rename({"旧名": "新名"}) を使います(No.084 で詳しく扱います)

Pythonで確認する

# 列名一覧の確認
print("列名一覧 (df.columns):")
for i, col in enumerate(df.columns):
    print(f"  [{i}] {col}")
print()

# schema(列名 + 型)
print("列名と型 (df.schema):")
for col, dtype in df.schema.items():
    print(f"  {col:25s}: {dtype}")
print()

# 列へのアクセス方法の違い
print("列へのアクセス方法:")
print(f"  df['production_count']         → {type(df['production_count']).__name__}")
print(f"  df.select('production_count')  → {type(df.select('production_count')).__name__}")
print()

# 存在チェック
for check_col in ["defect_count", "defect_rate_pct"]:
    exists = check_col in df.columns
    mark = "✓ 存在します" if exists else "✗ 存在しません"
    print(f"  '{check_col}' → {mark}")
列名一覧 (df.columns):
  [0] date
  [1] line
  [2] line_name
  [3] production_count
  [4] defect_count
  [5] working_hours
  [6] unit_price
  [7] machine_id

列名と型 (df.schema):
  date                     : Date
  line                     : String
  line_name                : String
  production_count         : Int64
  defect_count             : Int64
  working_hours            : Float64
  unit_price               : Int64
  machine_id               : String

列へのアクセス方法:
  df['production_count']         → Series
  df.select('production_count')  → DataFrame

  'defect_count' → ✓ 存在します
  'defect_rate_pct' → ✗ 存在しません

結果の読み取り

  • df.columns でインデックス付きの列名一覧が確認でき、
    「何列目にどのデータがあるか」を素早く把握できます。
  • df.schema は列名と型を同時に返すため、型の問題を早期発見できます。
    例:日付列が String のまま読み込まれた場合はここで気づけます。
  • df["列名"]Seriesdf.select("列名")DataFrame を返す点に注意してください。
  • defect_rate_pct 列はまだ作成していないため「存在しません」と表示されます。

No.079:データ型を確認する

実務での意味

データ型の確認は集計ミスを防ぐ最重要確認事項の1つです。
製造現場でよくある問題:

  • 日付列が String のまま → 日付での並び替え・期間フィルタが機能しない
  • 生産数列が Float64 → 整数であるはずの値が 472.0 と表示される
  • 欠損値が "NULL" という文字列 → 欠損として認識されない

分析・モデル化の考え方

型確認の手順:

  1. df.dtypes で全列の型を確認
  2. 日付列は Date または Datetime 型であることを確認
  3. 数値列は Int32/Int64(整数)または Float64(小数)であることを確認
  4. カテゴリ列(ライン名など)は String 型でよい

Pythonで確認する

# 全列の型確認(型ごとにコメントを付与)
print("全列のデータ型:")
type_notes = {
    "Date": "✓ 日付型として正しく読み込まれています",
    "Int32": "✓ 整数型",
    "Int64": "✓ 整数型",
    "Float32": "✓ 浮動小数点型",
    "Float64": "✓ 浮動小数点型",
    "String": "✓ 文字列型",
}
for col, dtype in zip(df.columns, df.dtypes):
    note = type_notes.get(str(dtype), "")
    print(f"  {col:25s}: {str(dtype):10s}  {note}")
print()

# 型の自動分類
date_cols  = [c for c, d in zip(df.columns, df.dtypes) if d == pl.Date]
int_cols   = [c for c, d in zip(df.columns, df.dtypes) if d in (pl.Int32, pl.Int64)]
float_cols = [c for c, d in zip(df.columns, df.dtypes) if d in (pl.Float32, pl.Float64)]
str_cols   = [c for c, d in zip(df.columns, df.dtypes) if str(d) == "String"]

print("型の自動分類:")
print(f"  日付列     : {date_cols}")
print(f"  整数列     : {int_cols}")
print(f"  浮動小数列 : {float_cols}")
print(f"  文字列列   : {str_cols}")
print()

# date 列の型と値域
print("date 列の詳細:")
print(f"  型    : {df['date'].dtype}")
print(f"  最小値: {df['date'].min()}")
print(f"  最大値: {df['date'].max()}")
全列のデータ型:
  date                     : Date        ✓ 日付型として正しく読み込まれています
  line                     : String      ✓ 文字列型
  line_name                : String      ✓ 文字列型
  production_count         : Int64       ✓ 整数型
  defect_count             : Int64       ✓ 整数型
  working_hours            : Float64     ✓ 浮動小数点型
  unit_price               : Int64       ✓ 整数型
  machine_id               : String      ✓ 文字列型

型の自動分類:
  日付列     : ['date']
  整数列     : ['production_count', 'defect_count', 'unit_price']
  浮動小数列 : ['working_hours']
  文字列列   : ['line', 'line_name', 'machine_id']

date 列の詳細:
  型    : Date
  最小値: 2024-01-04
  最大値: 2024-01-31

結果の読み取り

  • try_parse_dates=True の効果で、date 列が Date 型として正しく読み込まれています。
  • production_countdefect_countInt64 型(整数)になっています。
  • working_hours は小数を含むため Float64 型です。
  • カテゴリ列(line, line_name, machine_id)は String 型で問題ありません。
  • 型の自動分類を関数化しておくと、毎月のCSV品質チェックを効率化できます。

No.080:基本統計量を確認する

実務での意味

describe() は数値列の基本統計量を一括確認できる、
最初の分析で必ず使うべきメソッドです。
製造現場では「不良数の平均・最大値が期待範囲内か」「稼働時間にばらつきがないか」などを
即座に把握するのに活用します。

分析・モデル化の考え方

df.describe() が返す統計量:

統計量意味製造データでの活用
count非null値の個数欠損値の確認
null_countnull(欠損)値の個数欠損率の把握
mean平均値基準値との比較
std標準偏差ばらつきの大きさ
min / max最小・最大値外れ値の検出
25% / 50% / 75%四分位数外れ値・偏りの検出

変動係数 CV(= 標準偏差 / 平均 × 100%) は製造ラインの安定性評価に有効です:
CV が高いライン = 生産量・品質のばらつきが大きく、工程改善の優先候補になります。

Pythonで確認する

# describe() で全列の統計量を確認
print("基本統計量 (df.describe()):")
print(df.describe())
基本統計量 (df.describe()):
shape: (9, 9)
┌────────────┬────────────┬────────┬───────────┬───┬───────────┬───────────┬───────────┬───────────┐
│ statistic  ┆ date       ┆ line   ┆ line_name ┆ … ┆ defect_co ┆ working_h ┆ unit_pric ┆ machine_i │
│ ---        ┆ ---        ┆ ---    ┆ ---       ┆   ┆ unt       ┆ ours      ┆ e         ┆ d         │
│ str        ┆ str        ┆ str    ┆ str       ┆   ┆ ---       ┆ ---       ┆ ---       ┆ ---       │
│            ┆            ┆        ┆           ┆   ┆ f64       ┆ f64       ┆ f64       ┆ str       │
╞════════════╪════════════╪════════╪═══════════╪═══╪═══════════╪═══════════╪═══════════╪═══════════╡
│ count      ┆ 100        ┆ 100    ┆ 100       ┆ … ┆ 100.0     ┆ 100.0     ┆ 100.0     ┆ 100       │
│ null_count ┆ 0          ┆ 0      ┆ 0         ┆ … ┆ 0.0       ┆ 0.0       ┆ 0.0       ┆ 0         │
│ mean       ┆ 2024-01-17 ┆ null   ┆ null      ┆ … ┆ 7.47      ┆ 7.802     ┆ 1682.0    ┆ null      │
│            ┆ 16:48:00   ┆        ┆           ┆   ┆           ┆           ┆           ┆           │
│ std        ┆ null       ┆ null   ┆ null      ┆ … ┆ 2.475965  ┆ 0.353619  ┆ 963.41983 ┆ null      │
│            ┆            ┆        ┆           ┆   ┆           ┆           ┆ 5         ┆           │
│ min        ┆ 2024-01-04 ┆ PCB-A1 ┆ 基板A-中  ┆ … ┆ 3.0       ┆ 6.9       ┆ 760.0     ┆ M01-1     │
│            ┆            ┆        ┆ 型        ┆   ┆           ┆           ┆           ┆           │
│ 25%        ┆ 2024-01-11 ┆ null   ┆ null      ┆ … ┆ 6.0       ┆ 7.5       ┆ 850.0     ┆ null      │
│ 50%        ┆ 2024-01-18 ┆ null   ┆ null      ┆ … ┆ 7.0       ┆ 7.8       ┆ 1200.0    ┆ null      │
│ 75%        ┆ 2024-01-24 ┆ null   ┆ null      ┆ … ┆ 9.0       ┆ 8.1       ┆ 2400.0    ┆ null      │
│ max        ┆ 2024-01-31 ┆ PCB-C1 ┆ 基板C-大  ┆ … ┆ 16.0      ┆ 9.0       ┆ 3200.0    ┆ M05-3     │
│            ┆            ┆        ┆ 型        ┆   ┆           ┆           ┆           ┆           │
└────────────┴────────────┴────────┴───────────┴───┴───────────┴───────────┴───────────┴───────────┘
# ライン別 不良率の統計量と変動係数
df_r = df.with_columns(
    (pl.col("defect_count") / pl.col("production_count") * 100)
    .alias("defect_rate_pct")
)

line_stats = (
    df_r.group_by("line")
    .agg([
        pl.col("defect_rate_pct").mean().alias("mean_pct"),
        pl.col("defect_rate_pct").std().alias("std_pct"),
        pl.col("defect_rate_pct").min().alias("min_pct"),
        pl.col("defect_rate_pct").max().alias("max_pct"),
        pl.col("production_count").sum().alias("total_prod"),
        pl.col("defect_count").sum().alias("total_def"),
    ])
    .sort("line")
)
line_stats = line_stats.with_columns(
    (pl.col("std_pct") / pl.col("mean_pct") * 100).alias("cv_pct")
)
print("ライン別 不良率の統計量(変動係数 CV 付き):")
print(line_stats)
print()

# 全体サマリー
total_prod = df["production_count"].sum()
total_def  = df["defect_count"].sum()
print("=" * 46)
print("  生産実績サマリー(2024年1月)")
print("=" * 46)
print(f"  総生産数    : {total_prod:>8,} 個")
print(f"  総不良数    : {total_def:>8,} 個")
print(f"  全体不良率  : {total_def / total_prod * 100:>8.2f} %")
print(f"  平均稼働時間: {df['working_hours'].mean():>8.2f} h/日ライン")
print("=" * 46)
ライン別 不良率の統計量(変動係数 CV 付き):
shape: (5, 8)
┌────────┬──────────┬──────────┬──────────┬──────────┬────────────┬───────────┬───────────┐
│ line   ┆ mean_pct ┆ std_pct  ┆ min_pct  ┆ max_pct  ┆ total_prod ┆ total_def ┆ cv_pct    │
│ ---    ┆ ---      ┆ ---      ┆ ---      ┆ ---      ┆ ---        ┆ ---       ┆ ---       │
│ str    ┆ f64      ┆ f64      ┆ f64      ┆ f64      ┆ i64        ┆ i64       ┆ f64       │
╞════════╪══════════╪══════════╪══════════╪══════════╪════════════╪═══════════╪═══════════╡
│ PCB-A1 ┆ 1.860707 ┆ 0.409036 ┆ 1.02459  ┆ 2.603037 ┆ 9588       ┆ 178       ┆ 21.982828 │
│ PCB-A2 ┆ 1.969265 ┆ 0.41238  ┆ 1.049869 ┆ 2.601156 ┆ 7253       ┆ 142       ┆ 20.940792 │
│ PCB-B1 ┆ 1.673189 ┆ 0.541363 ┆ 0.727273 ┆ 3.059273 ┆ 10266      ┆ 172       ┆ 32.355145 │
│ PCB-B2 ┆ 2.92322  ┆ 0.59152  ┆ 1.811594 ┆ 4.166667 ┆ 5675       ┆ 166       ┆ 20.235214 │
│ PCB-C1 ┆ 2.237741 ┆ 0.553861 ┆ 1.492537 ┆ 3.553299 ┆ 3973       ┆ 89        ┆ 24.750899 │
└────────┴──────────┴──────────┴──────────┴──────────┴────────────┴───────────┴───────────┘

==============================================
  生産実績サマリー(2024年1月)
==============================================
  総生産数    :   36,755 個
  総不良数    :      747 個
  全体不良率  :     2.03 %
  平均稼働時間:     7.80 h/日ライン
==============================================
# 可視化:ライン別 平均不良率 + 日別不良率推移
fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# ── グラフ1: ライン別 平均不良率(エラーバー:標準偏差) ──
ax1 = axes[0]
lines_list = line_stats["line"].to_list()
mean_vals  = line_stats["mean_pct"].to_list()
std_vals   = line_stats["std_pct"].to_list()
cv_vals    = line_stats["cv_pct"].to_list()
colors     = ["#4878CF", "#6ACC65", "#D65F5F", "#B47CC7", "#C4AD66"]

bars = ax1.bar(lines_list, mean_vals, color=colors, alpha=0.8,
               edgecolor="black", linewidth=0.5)
ax1.errorbar(lines_list, mean_vals, yerr=std_vals, fmt="none",
             color="black", capsize=5, linewidth=1.5)

for bar, cv in zip(bars, cv_vals):
    ax1.text(
        bar.get_x() + bar.get_width() / 2,
        bar.get_height() + max(std_vals) * 0.12,
        f"CV={cv:.1f}%", ha="center", va="bottom", fontsize=8,
    )

ax1.set_title("ライン別 平均不良率(エラーバー:標準偏差)", fontsize=11, pad=12)
ax1.set_xlabel("ライン", fontsize=10)
ax1.set_ylabel("不良率 (%)", fontsize=10)
ax1.grid(axis="y", alpha=0.3)
ax1.tick_params(axis="x", labelsize=8)

# ── グラフ2: 日別 全ライン合計不良率の推移 ──
ax2 = axes[1]
df_daily = (
    df_r.group_by("date")
    .agg([
        pl.col("production_count").sum().alias("total_prod"),
        pl.col("defect_count").sum().alias("total_def"),
    ])
    .sort("date")
)
daily_rate  = (df_daily["total_def"] / df_daily["total_prod"] * 100).to_list()
dates_label = [str(d)[5:] for d in df_daily["date"].to_list()]  # "MM-DD"
avg_rate    = sum(daily_rate) / len(daily_rate)

ax2.plot(range(len(daily_rate)), daily_rate, marker="o", color="#D65F5F",
         linewidth=1.5, markersize=4, label="日別不良率")
ax2.axhline(y=avg_rate, color="gray", linestyle="--", linewidth=1,
            label=f"平均 {avg_rate:.2f}%")
ax2.set_title("日別 全ライン合計不良率の推移(2024年1月)", fontsize=11, pad=12)
ax2.set_xlabel("営業日(MM-DD)", fontsize=10)
ax2.set_ylabel("不良率 (%)", fontsize=10)
ax2.set_xticks(range(0, len(daily_rate), 4))
ax2.set_xticklabels([dates_label[i] for i in range(0, len(daily_rate), 4)], fontsize=8)
ax2.grid(alpha=0.3)
ax2.legend(fontsize=9)

plt.tight_layout()
plt.savefig("no080_defect_analysis.svg", format="svg", bbox_inches="tight")
plt.show()
print("グラフ保存完了: no080_defect_analysis.svg")

svg

グラフ保存完了: no080_defect_analysis.svg

結果の読み取り

  • df.describe() で100行 × 8列のデータを一括確認でき、
    不良数の最大値・最小値・標準偏差 が即座に把握できます。
  • 変動係数(CV) から以下が読み取れます:
    • PCB-B2(基板B-高密度) :CV が最大 → 品質が不安定で、工程改善の最優先候補
    • PCB-A1(基板A-小型) :CV が最小 → 工程が安定しており、ベストプラクティスの参考ライン
  • 日別不良率推移グラフから、特定の営業日に不良率が高い日がないかを確認できます。
    高い日があれば、その日の機械・作業員・材料ロットなどを調査する契機になります。

対象ノックを通して見える実務上の示唆

No.071〜080 の Polars 入門を通して、製造データ分析における以下の示唆が得られます。

1. Polars は製造業の大規模データに向いている

月次・年次の生産実績(数万〜数十万行)を扱う場合、
Polars は pandas に比べ処理速度・メモリ効率の両面で優れています。
DX 推進の初期投資として Polars の導入を検討する価値があります。

2. データ品質確認の 5 ステップを習慣化する

CSV を読み込んだら必ず以下の順で確認しましょう:

ステップ操作確認ポイント
① 形状確認df.shape期待する行数・列数と一致しているか
② 先頭末尾確認df.head() / df.tail()余分な行・ヘッダー重複がないか
③ 列名確認df.columns / df.schema列名が正しいか・表記ゆれがないか
④ 型確認df.dtypes日付が Date 型か・数値が Int/Float か
⑤ 統計量確認df.describe()最大・最小・標準偏差が業務上妥当か

3. 変動係数(CV)でライン安定性を素早く評価できる

describe() の標準偏差と平均から変動係数(CV)を計算することで、
どのラインが不安定で改善が必要か を定量的に優先順位付けできます。

4. Lazy モードで大規模データも効率的に処理できる(次のステップ)

本章は Eager モード(pl.read_csv)を扱いましたが、
数百万行の場合は pl.scan_csv.filter().collect() の Lazy モードが効果的です。
処理が必要な行・列だけをメモリに乗せるため、メモリ不足を防げます。

実務導入する場合に必要なこと

Polars を製造現場で本格導入する際のチェックリスト

1. 環境整備

  • pip install polars で本番環境にインストール
  • requirements.txt にバージョンを固定(例:polars>=1.0,<2.0
  • 既存の pandas コードとの共存方針を決める(段階的移行 or 全置換)

2. データパイプライン設計

  • CSV の文字コード・区切り文字・日付形式を確認して read_csv オプションを設定
  • 欠損値の表現("NULL", "-", 空文字)を確認して null_values を指定
  • 大規模CSV(10万行以上)には scan_csv → Lazy モードを採用

3. 品質管理への組み込み

  • データ読み込み後の assert df.shape[0] == 期待行数 を自動チェックに組み込む
  • 型チェック関数を作成し、毎月の CSV 読み込み時に実行
  • 変動係数(CV)の閾値を設定し、超えたラインを自動アラート

4. チームへの展開

  • Polars の基本操作(本章の内容)をチーム内勉強会で共有
  • pandas ユーザーへの移行ガイドを作成(主要な操作の対応表)

まとめ

本章(No.071〜080)では、Polars の基本操作を電子部品製造工場の生産実績データを題材に学びました。

No.学んだこと製造業での活用
071Polarsの役割pandas との違いを理解し、大規模データへの適用判断
072importと確認実行環境の記録・バージョン固定の重要性
073Seriesの作成不良数・稼働率などの1列データ管理
074DataFrameの作成辞書から生産実績テーブルを構築
075CSV読み込み月次生産実績 CSV を型安全に読み込み
076head / tail読み込み直後の目視確認
077shape行数・列数で欠損日・余分行を検出
078columns / schema列名・型の一括確認と正規化
079dtypes日付・数値・文字列型の正しい確認
080describe基本統計量・変動係数でライン安定性を評価

次章(No.081〜090) では、Polars によるデータ加工
(フィルタ・列追加・欠損処理・並べ替え)を扱います。

法人向けのご相談

製造業の DX 推進・データ分析基盤の構築・社内 Python 研修については、
数理工房にお気軽にご相談ください。

📩 お問い合わせ: surikobo.co.jp/contact
まずはお気軽にご相談ください。


本記事は「データ分析のための Python 入門 100本ノック」シリーズの一部です。
シリーズ全体の目次は こちら からご確認ください。