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 と似ているようで、いくつか重要な違いがあります。
-
df["列名"]vsdf.select("列名")
df["列名"]はpl.Seriesを返しますが、df.select("列名")はpl.DataFrameを返します。
用途に応じて使い分ける必要があります。 -
Eager モードと Lazy モードの違い
pl.read_csv()は即座に実行する Eager モード です。
大規模データにはpl.scan_csv()→.collect()の Lazy モード が効率的です。
本章では基礎として Eager モードを扱います。 -
describe()の戻り値が DataFrame
Polars のdescribe()はDataFrameを返します。
数値型以外の列も含めた統計量が表示されるため、列の型確認が先に必要です。 -
nullとNaNの違い
Polars では欠損値をnull(= Python のNone)で表現します。
NaNは浮動小数点の特殊値として別途区別されます。
今回扱うノックの全体像
| No. | タイトル | 製造業での活用場面 |
|---|---|---|
| 071 | Polarsの役割を理解する | pandas との違いを整理し、大規模製造データへの適用可否を判断 |
| 072 | Polarsをimportする | インポートとバージョン確認・基本設定 |
| 073 | Seriesを作成する | 不良数・生産数など1列データの扱い |
| 074 | DataFrameを作成する | ライン別生産実績テーブルの構築 |
| 075 | CSVを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 形式をベースにした列指向ストレージを採用しています。
「不良数列だけ合計する」といった列単位の演算が特に高速です。
| 比較項目 | pandas | Polars |
|---|---|---|
| ベース形式 | NumPy | Apache Arrow |
| 速度(大規模) | 標準 | 最大5倍以上 |
| メモリ使用量 | 多い | 少ない |
| 欠損値の型 | NaN(float) | null(型非依存) |
| 遅延評価(Lazy) | なし | あり(scan_csv → collect) |
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.Seriesにdtypeを指定することで、型の不一致によるエラーを未然に防ぎます。.sum(),.mean(),.max(),.min()が直接呼べるため、
「5ラインの不良数合計を瞬時に確認」といった操作が簡潔に書けます。- 不良数合計
50から、この1日で 50個の不良品が発生 したことが読み取れます。
PCB-B2 の不良数18が最多で、重点管理が必要なラインといえます。
No.074:DataFrameを作成する
実務での意味
DataFrame は複数の列を持つ表形式データです。
製造現場では「ライン名・生産数・不良数・稼働率を1つのテーブルにまとめる」
という操作が基本になります。
分析・モデル化の考え方
DataFrame の主な作成方法:
- 辞書から作成(最もシンプル・架空データの検証に最適)
- Series のリストから作成
- 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["列名"]はSeries、df.select("列名")はDataFrameを返す点に注意してください。defect_rate_pct列はまだ作成していないため「存在しません」と表示されます。
No.079:データ型を確認する
実務での意味
データ型の確認は集計ミスを防ぐ最重要確認事項の1つです。
製造現場でよくある問題:
- 日付列が
Stringのまま → 日付での並び替え・期間フィルタが機能しない - 生産数列が
Float64→ 整数であるはずの値が472.0と表示される - 欠損値が
"NULL"という文字列 → 欠損として認識されない
分析・モデル化の考え方
型確認の手順:
df.dtypesで全列の型を確認- 日付列は
DateまたはDatetime型であることを確認 - 数値列は
Int32/Int64(整数)またはFloat64(小数)であることを確認 - カテゴリ列(ライン名など)は
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_countとdefect_countがInt64型(整数)になっています。working_hoursは小数を含むためFloat64型です。- カテゴリ列(
line,line_name,machine_id)はString型で問題ありません。 - 型の自動分類を関数化しておくと、毎月のCSV品質チェックを効率化できます。
No.080:基本統計量を確認する
実務での意味
describe() は数値列の基本統計量を一括確認できる、
最初の分析で必ず使うべきメソッドです。
製造現場では「不良数の平均・最大値が期待範囲内か」「稼働時間にばらつきがないか」などを
即座に把握するのに活用します。
分析・モデル化の考え方
df.describe() が返す統計量:
| 統計量 | 意味 | 製造データでの活用 |
|---|---|---|
count | 非null値の個数 | 欠損値の確認 |
null_count | null(欠損)値の個数 | 欠損率の把握 |
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")
グラフ保存完了: 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. | 学んだこと | 製造業での活用 |
|---|---|---|
| 071 | Polarsの役割 | pandas との違いを理解し、大規模データへの適用判断 |
| 072 | importと確認 | 実行環境の記録・バージョン固定の重要性 |
| 073 | Seriesの作成 | 不良数・稼働率などの1列データ管理 |
| 074 | DataFrameの作成 | 辞書から生産実績テーブルを構築 |
| 075 | CSV読み込み | 月次生産実績 CSV を型安全に読み込み |
| 076 | head / tail | 読み込み直後の目視確認 |
| 077 | shape | 行数・列数で欠損日・余分行を検出 |
| 078 | columns / schema | 列名・型の一括確認と正規化 |
| 079 | dtypes | 日付・数値・文字列型の正しい確認 |
| 080 | describe | 基本統計量・変動係数でライン安定性を評価 |
次章(No.081〜090) では、Polars によるデータ加工
(フィルタ・列追加・欠損処理・並べ替え)を扱います。
法人向けのご相談
製造業の DX 推進・データ分析基盤の構築・社内 Python 研修については、
数理工房にお気軽にご相談ください。
📩 お問い合わせ: surikobo.co.jp/contact
まずはお気軽にご相談ください。
本記事は「データ分析のための Python 入門 100本ノック」シリーズの一部です。
シリーズ全体の目次は こちら からご確認ください。