ワードクラウドを生成・表示する

wordcloudWordCloud クラスに対して .generate() にスペース区切りの単語列を渡すだけで画像オブジェクトが生成されます。生成後は matplotlibimshow() で表示します。

Python — 基本的なワードクラウド生成
from wordcloud import WordCloud
import matplotlib.pyplot as plt

# PART 02 で作成した load_and_tokenize() を呼んで単語列を取得
# (ここでは簡略化のためハードコードした単語列を使用)
tokenized_text = (
    "データベース 接続 エラー 発生 サービス 停止 コネクション プール 設定 ミス "
    "ネットワーク 障害 タイムアウト 多発 ネットワーク 機器 ファームウェア 不具合 "
    "メモリ 不足 アプリケーション サーバー クラッシュ メモリ リーク バグ "
    "ディスク 容量 不足 ログ 書き込み 失敗 ログ ローテーション 設定 漏れ "
    "データベース スロークエリ 応答 時間 増大 インデックス 未設定 "
    "認証 サーバー 接続 タイムアウト ログイン 認証 サーバー 過負荷 "
    "レートリミット 超過 リクエスト 拒否 バッチ 処理 並列 設定 ミス "
    "証明書 期限切れ 通信 切断 証明書 更新 作業 漏れ "
    "キャッシュ サーバー 障害 データベース 負荷 集中 キャッシュ 冗長 不足 "
    "デプロイ 設定 ファイル 読み込み エラー 環境変数 設定 漏れ"
)

# ── WordCloud 生成 ─────────────────────────────────────────────────────
FONT_PATH = "C:/Windows/Fonts/meiryo.ttc"   # ※ OS に合わせて変更

wc = WordCloud(
    font_path        = FONT_PATH,
    width            = 800,
    height           = 400,
    background_color = "white",
    max_words        = 50,
    colormap         = "tab10",
    collocations     = False,    # 2語連語の自動結合を無効化
    prefer_horizontal= 0.9,      # 横書き優先率(0.0〜1.0)
)

wc.generate(tokenized_text)

# ── matplotlib で表示 ──────────────────────────────────────────────────
plt.figure(figsize=(12, 6))
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.title("障害管理表 ワードクラウド", fontsize=16, pad=14)
plt.tight_layout()
plt.show()
出力イメージ(概念図)
╔══════════════════════════════════════════════════════════╗
║          障害管理表 ワードクラウド                           ║
║                                                          ║
║    データベース         設定        ネットワーク              ║
║         エラー    障害     タイムアウト    接続               ║
║    メモリ      サーバー    ログ    キャッシュ                  ║
║       ミス   不具合   クラッシュ    証明書  認証               ║
║   漏れ    インデックス    デプロイ    環境変数  容量             ║
║                                                          ║
╚══════════════════════════════════════════════════════════╝

「データベース」「設定」「ネットワーク」「エラー」が大きく表示され、これらが障害の主要キーワードであることが一目でわかります。「設定」「ミス」「漏れ」が多く出ていることから、設定作業の見直しが有効な対策であると読み取れます。

日本語フォントの指定

wordcloud は日本語フォントを自動検出しないため、font_path に TrueType フォント (.ttc / .ttf) のフルパスを指定する必要があります。フォントを指定しないと日本語が豆腐(□)になります。

OSフォント例パス例
Windows メイリオ C:/Windows/Fonts/meiryo.ttc
Windows 游ゴシック C:/Windows/Fonts/YuGothM.ttc
macOS ヒラギノ角ゴシック /System/Library/Fonts/ヒラギノ角ゴシック W3.ttc
Linux (Ubuntu) Noto Sans CJK JP /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc
Python — OS 自動判定でフォントパスを設定
import sys
import pathlib

def get_default_font() -> str:
    """OS に応じてデフォルト日本語フォントパスを返す"""
    if sys.platform == "win32":
        candidates = [
            pathlib.Path("C:/Windows/Fonts/meiryo.ttc"),
            pathlib.Path("C:/Windows/Fonts/YuGothM.ttc"),
        ]
    elif sys.platform == "darwin":
        candidates = [
            pathlib.Path("/System/Library/Fonts/ヒラギノ角ゴシック W3.ttc"),
            pathlib.Path("/System/Library/Fonts/Hiragino Sans GB W3.ttc"),
        ]
    else:  # Linux
        candidates = [
            pathlib.Path("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"),
            pathlib.Path("/usr/share/fonts/truetype/fonts-japanese-gothic.ttf"),
        ]

    for path in candidates:
        if path.exists():
            return str(path)

    raise FileNotFoundError(
        "日本語フォントが見つかりません。font_path を手動で指定してください。"
    )

FONT_PATH = get_default_font()
print(f"使用フォント: {FONT_PATH}")

主要パラメータ一覧

WordCloud の主なパラメータを把握しておくと、出力の見栄えを細かく調整できます。

パラメータデフォルト説明
width400画像の幅(ピクセル)
height200画像の高さ(ピクセル)
background_color"black"背景色。"white" が読みやすい
max_words200表示する最大単語数
min_font_size4最小フォントサイズ(pt)
max_font_size自動最大フォントサイズ(pt)
colormap"viridis"matplotlib のカラーマップ名
collocationsTrueFalse で 2 語連語の自動結合を無効化(日本語では False 推奨)
prefer_horizontal0.9横書き単語の比率。0.5 にすると縦横半々
stopwordsSTOPWORDS除外する単語のセット
maskNone表示形状を定義する NumPy 配列(白 = 空白)

PNG 画像として保存する

ワードクラウドの保存方法は 2 とおりあります。方法 Awc.to_file())は WordCloud オブジェクトから直接保存する方法で、コードが最もシンプルです。方法 Bplt.savefig())はタイトルや軸ラベルを含む matplotlib の図全体を保存します。

Python — PNG 保存 2 パターン
from wordcloud import WordCloud
import matplotlib.pyplot as plt

# (生成済みの wc オブジェクトがある前提)

# ── 方法 A: WordCloud オブジェクトから直接保存 ─────────────────────────
wc.to_file("wordcloud_incident.png")
print("✅ wordcloud_incident.png を保存しました")

# ── 方法 B: matplotlib の figure ごと保存(タイトル込み) ─────────────────
fig, ax = plt.subplots(figsize=(12, 6))
ax.imshow(wc, interpolation="bilinear")
ax.axis("off")
ax.set_title("障害管理表 ワードクラウド", fontsize=16, pad=14)
fig.tight_layout()
fig.savefig("wordcloud_incident_with_title.png", dpi=150, bbox_inches="tight")
plt.close(fig)
print("✅ wordcloud_incident_with_title.png を保存しました")

💡 dpi を上げると高解像度になる

dpi=150 で通常スクリーン向けの十分なサイズになります。プレゼンテーション用など印刷品質が必要な場合は dpi=300 を指定してください。ファイルサイズは約 4 倍になります。

ストップワードを追加する

形態素解析でノイズ語を除いても、業務固有の不要語(「発生」「対応」「確認」など、どの障害にも必ず出てくる語)が大きく表示されてしまうことがあります。stopwords パラメータにセットを渡して除外できます。

Python — ストップワードのカスタマイズ
from wordcloud import WordCloud, STOPWORDS

# デフォルトの英語ストップワードセットに追加
custom_stopwords = set(STOPWORDS) | {
    # ── 動詞・形容詞の一般語 ──────────────────────────────────────────
    "する", "なる", "ある", "れる", "られる",
    # ── 汎用名詞(障害票どこにでも出る語) ────────────────────────────
    "発生", "対応", "確認", "処理", "作業", "ため", "より", "こと",
}

wc = WordCloud(
    font_path        = FONT_PATH,
    width            = 800,
    height           = 400,
    background_color = "white",
    max_words        = 50,
    colormap         = "Set2",
    collocations     = False,
    stopwords        = custom_stopwords,   # ← ここで渡す
)

wc.generate(tokenized_text)
wc.to_file("wordcloud_filtered.png")
print("✅ wordcloud_filtered.png を保存しました")

効果的なストップワードの見つけ方

まずストップワードなしで生成し、大きく表示されている語のうち「どの障害にも使う一般語」を特定します。その語をストップワードに追加して再生成すると、より業務特有のキーワードが際立ちます。この調整は 2〜3 回繰り返すと最適な結果が得られます。

応用 — 月次自動生成・カテゴリ別分析

ワードクラウドのパイプラインが完成したら、DataFrame のフィルタリングと組み合わせることで多様な分析が可能になります。

月次ワードクラウードの自動生成

Python — 月次自動生成
import pandas as pd
from wordcloud import WordCloud
import pathlib

def generate_monthly_wordclouds(
    filepath:  str,
    text_cols: list[str],
    date_col:  str,
    output_dir: str = "output",
    font_path: str = "C:/Windows/Fonts/meiryo.ttc",
) -> None:
    """月ごとのワードクラウド PNG を output_dir に出力する"""
    df = pd.read_excel(filepath)
    df[date_col] = pd.to_datetime(df[date_col])
    df["年月"] = df[date_col].dt.strftime("%Y-%m")

    pathlib.Path(output_dir).mkdir(exist_ok=True)

    wc = WordCloud(
        font_path        = font_path,
        width            = 800,
        height           = 400,
        background_color = "white",
        max_words        = 40,
        colormap         = "tab20",
        collocations     = False,
    )

    for month, group in df.groupby("年月"):
        texts = group[text_cols].fillna("").apply(
            lambda r: "。".join(r.values.astype(str)), axis=1
        )
        combined = " ".join(texts.tolist())
        tokenized = extract_words(combined)   # PART 02 の関数

        if not tokenized.strip():
            print(f"⚠️ {month}: 単語が抽出できませんでした(データなし)")
            continue

        wc.generate(tokenized)
        out = pathlib.Path(output_dir) / f"wordcloud_{month}.png"
        wc.to_file(str(out))
        print(f"✅ {out} を保存しました")


# 実行
generate_monthly_wordclouds(
    filepath   = "incident_log.xlsx",
    text_cols  = ["障害内容", "原因"],
    date_col   = "発生日",
)
実行結果(output/ ディレクトリに月別 PNG が生成される)
✅ output/wordcloud_2024-01.png を保存しました
✅ output/wordcloud_2024-02.png を保存しました
✅ output/wordcloud_2024-03.png を保存しました
✅ output/wordcloud_2024-04.png を保存しました
✅ output/wordcloud_2024-05.png を保存しました

カテゴリ・重要度別の分析

Python — DataFrame フィルタで任意条件を絞る
import pandas as pd
from wordcloud import WordCloud

df = pd.read_excel("incident_log.xlsx")

# ── 例1: 特定の重要度(列があると仮定)に絞る ──────────────────────────
# df_high = df[df["重要度"] == "高"]

# ── 例2: 特定のシステム領域でフィルタ ─────────────────────────────────
# df_db = df[df["カテゴリ"] == "データベース"]

# ── 例3: 期間で絞る ──────────────────────────────────────────────────
df["発生日"] = pd.to_datetime(df["発生日"])
df_q1 = df[df["発生日"].between("2024-01-01", "2024-03-31")]

# フィルタ結果からワードクラウドを生成
texts = df_q1[["障害内容", "原因"]].fillna("").apply(
    lambda r: "。".join(r.values.astype(str)), axis=1
)
combined = " ".join(texts.tolist())
tokenized = extract_words(combined)  # PART 02 の関数

wc = WordCloud(
    font_path        = "C:/Windows/Fonts/meiryo.ttc",
    width            = 800,
    height           = 400,
    background_color = "white",
    max_words        = 40,
    colormap         = "Reds",
    collocations     = False,
)
wc.generate(tokenized)
wc.to_file("wordcloud_q1.png")
print(f"✅ Q1 ({len(df_q1)} 件) のワードクラウドを保存しました")

シリーズ完結版コード

3 パートの処理を 1 ファイルにまとめた完結版です。このファイルだけで「サンプル Excel 生成 → 形態素解析 → ワードクラウド PNG 保存」が完結します。

Python — wordcloud_incident_full.py(完結版)
"""
wordcloud_incident_full.py
==========================
障害管理表 Excel → ワードクラウド PNG 生成の完結版スクリプト。

Usage:
    python wordcloud_incident_full.py              # サンプルデータを生成して実行
    python wordcloud_incident_full.py myfile.xlsx  # 既存 Excel を使う
"""
import sys
import pathlib
import pandas as pd
from janome.tokenizer import Tokenizer
from wordcloud import WordCloud
import matplotlib.pyplot as plt


# ── 設定 ───────────────────────────────────────────────────────────────
FONT_PATH   = "C:/Windows/Fonts/meiryo.ttc"
OUTPUT_FILE = "wordcloud_incident.png"
TEXT_COLS   = ["障害内容", "原因"]


# ── サンプルデータ生成 ─────────────────────────────────────────────────
def create_sample_excel(filepath: str) -> None:
    records = [
        {"障害ID": "INC-001", "発生日": "2024-01-10",
         "障害内容": "データベース接続エラーが発生し、サービスが停止した",      "原因": "コネクションプールの設定ミス"},
        {"障害ID": "INC-002", "発生日": "2024-01-15",
         "障害内容": "ネットワーク障害によりAPIタイムアウトが多発した",         "原因": "ネットワーク機器のファームウェア不具合"},
        {"障害ID": "INC-003", "発生日": "2024-02-03",
         "障害内容": "メモリ不足でアプリケーションサーバーがクラッシュした",    "原因": "メモリリークのバグ"},
        {"障害ID": "INC-004", "発生日": "2024-02-18",
         "障害内容": "ディスク容量不足によりログ書き込みに失敗した",           "原因": "ログローテーション設定の漏れ"},
        {"障害ID": "INC-005", "発生日": "2024-03-05",
         "障害内容": "データベースのスロークエリにより応答時間が増大した",      "原因": "インデックス未設定"},
        {"障害ID": "INC-006", "発生日": "2024-03-12",
         "障害内容": "認証サーバーへの接続タイムアウトでログインできなかった",   "原因": "認証サーバーの過負荷"},
        {"障害ID": "INC-007", "発生日": "2024-04-01",
         "障害内容": "APIのレートリミット超過によりリクエストが拒否された",    "原因": "バッチ処理の並列数設定ミス"},
        {"障害ID": "INC-008", "発生日": "2024-04-20",
         "障害内容": "証明書の期限切れによりHTTPS通信が切断された",           "原因": "証明書更新の作業漏れ"},
        {"障害ID": "INC-009", "発生日": "2024-05-08",
         "障害内容": "キャッシュサーバーの障害でデータベースに負荷が集中した",  "原因": "キャッシュの冗長化不足"},
        {"障害ID": "INC-010", "発生日": "2024-05-22",
         "障害内容": "デプロイ後に設定ファイルの読み込みエラーが発生した",      "原因": "環境変数の設定漏れ"},
    ]
    pd.DataFrame(records).to_excel(filepath, index=False)
    print(f"✅ {filepath} を作成しました")


# ── 形態素解析 ─────────────────────────────────────────────────────────
def extract_words(text: str) -> str:
    t = Tokenizer()
    keep_pos    = {"名詞", "動詞", "形容詞"}
    exclude_sub = {"数", "接尾", "非自立", "代名詞"}
    words = []
    for token in t.tokenize(text):
        parts   = token.part_of_speech.split(",")
        pos, sub = parts[0], parts[1]
        surface  = token.surface
        if pos not in keep_pos: continue
        if pos == "名詞" and sub in exclude_sub: continue
        if pos == "動詞" and sub == "非自立": continue
        if len(surface) <= 1 or surface.isdigit(): continue
        words.append(surface)
    return " ".join(words)


# ── メイン ─────────────────────────────────────────────────────────────
def main() -> None:
    # 引数でファイルパスを受け取る(省略時はサンプル生成)
    excel_path = sys.argv[1] if len(sys.argv) > 1 else "incident_log.xlsx"
    if not pathlib.Path(excel_path).exists():
        create_sample_excel(excel_path)

    # Excel 読み込み → テキスト結合
    df = pd.read_excel(excel_path)
    combined = " ".join(
        df[TEXT_COLS].fillna("").apply(
            lambda r: "。".join(r.values.astype(str)), axis=1
        ).tolist()
    )

    # 形態素解析
    tokenized = extract_words(combined)
    print(f"総単語数: {len(tokenized.split())}")

    # ワードクラウド生成
    wc = WordCloud(
        font_path        = FONT_PATH,
        width            = 1200,
        height           = 600,
        background_color = "white",
        max_words        = 60,
        colormap         = "tab10",
        collocations     = False,
    )
    wc.generate(tokenized)

    # 表示
    plt.figure(figsize=(14, 7))
    plt.imshow(wc, interpolation="bilinear")
    plt.axis("off")
    plt.title("障害管理表 ワードクラウド", fontsize=18, pad=16)
    plt.tight_layout()

    # 保存 & 表示
    wc.to_file(OUTPUT_FILE)
    print(f"✅ {OUTPUT_FILE} を保存しました")
    plt.show()


if __name__ == "__main__":
    main()

まとめ

3 回シリーズで実装したデータパイプラインを振り返ります。

PART 01
環境構築 & サンプルデータ
pip install 5 ライブラリ。pandas で障害管理表サンプル Excel を生成。
PART 02
Excel 読み込み & 形態素解析
pandas でテキスト結合・欠損処理。janome で名詞・動詞・形容詞を抽出。
PART 03
WordCloud 生成・保存・応用
WordCloud でビジュアル生成。matplotlib で表示・PNG 保存。月次自動化・フィルタ分析。

今回構築したパイプラインは障害管理表に限らず、アンケート自由記述・コールセンターログ・社内レビューコメントなど、Excel にテキスト列を持つあらゆるデータに転用できます。ストップワードの調整と対象列の変更だけで、すぐに別用途に応用できます。

💡 さらに発展させるなら

WordCloud のマスク機能を使えば、会社ロゴや雲の形に単語を配置できます。PIL.Image で読み込んだ画像を NumPy 配列に変換して mask パラメータに渡すだけです。また、Word2VecTF-IDF で単語の重み付けを変えることで、単純な出現頻度以上の示唆を得られます。