このパートでやること
ワードクラウドの生成には「スペース区切りの単語列」が必要です。日本語は単語の区切りがないため、形態素解析で単語に分割する工程が欠かせません。本パートでは次の手順を順番に実装します。
Excel を pandas で読み込む
pd.read_excel() でファイルを読み込み、DataFrame の構造を確認します。PART 01 で生成した incident_log.xlsx をカレントディレクトリに置いてから実行してください。
import pandas as pd
# Excel 読み込み(engine は openpyxl が自動選択される)
df = pd.read_excel("incident_log.xlsx")
print("=== 基本情報 ===")
print(f"shape : {df.shape}") # (行数, 列数)
print(f"dtypes:\n{df.dtypes}") # 各列の型
print()
print("=== 先頭 3 行 ===")
print(df.head(3).to_string())
print()
print("=== 欠損値チェック ===")
print(df.isnull().sum())
=== 基本情報 === shape : (10, 4) dtypes: 障害ID object 発生日 datetime64[ns] 障害内容 object 原因 object dtype: object === 先頭 3 行 === 障害ID 発生日 障害内容 原因 0 INC-001 2024-01-10 データベース接続エラーが発生し、サービスが停止した コネクションプールの設定ミス 1 INC-002 2024-01-15 ネットワーク障害によりAPIタイムアウトが多発した ネットワーク機器のファームウェア不具合 2 INC-003 2024-02-03 メモリ不足でアプリケーションサーバーがクラッシュした メモリリークのバグ === 欠損値チェック === 障害ID 0 発生日 0 障害内容 0 原因 0 dtype: int64
💡 シートを指定するには
Excel ファイルに複数のシートがある場合は pd.read_excel("file.xlsx", sheet_name="シート名") または sheet_name=0(インデックス)でシートを指定できます。省略時は最初のシートが読み込まれます。
テキストの前処理と列の結合
業務 Excel では一部のセルが空欄になっていることがあります。欠損値(NaN)のまま文字列演算を行うと TypeError が発生するため、fillna("") で空文字に変換してから結合します。
import pandas as pd
df = pd.read_excel("incident_log.xlsx")
# ─── 前処理 ─────────────────────────────────────────────────────────────
# 1. 分析対象の列を指定(複数列をまとめて分析する場合はリストに追加)
target_cols = ["障害内容", "原因"]
# 2. 欠損値を空文字に置換して列を結合(読点で連結することで文境界を保持)
text_series = df[target_cols].fillna("").apply(
lambda row: "。".join(row.values.astype(str)), axis=1
)
# 3. 全行テキストを1つの文字列に結合(行間はスペース区切り)
combined_text = " ".join(text_series.tolist())
print(f"総文字数: {len(combined_text)}")
print("--- 先頭 100 文字 ---")
print(combined_text[:100])
print("---")
print()
# ─── 確認:空セルのある行をあえて作ってテスト ─────────────────────────────
import numpy as np
df_test = df.copy()
df_test.loc[0, "原因"] = np.nan # 0 行目の「原因」を欠損にする
text_test = df_test[target_cols].fillna("").apply(
lambda row: "。".join(row.values.astype(str)), axis=1
)
print("欠損ありでも連結できる例:")
print(text_test.iloc[0]) # → "データベース接続エラーが発生し、サービスが停止した。"
総文字数: 529 --- 先頭 100 文字 --- データベース接続エラーが発生し、サービスが停止した。コネクションプールの設定ミス ネットワーク障害によりAPIタイムアウトが多発した。ネットワーク機器のファームウェア --- 欠損ありでも連結できる例: データベース接続エラーが発生し、サービスが停止した。
⚠️ 文字コードのトラブルに注意
古い Excel ファイルやシステムから出力した CSV を読む場合は encoding="shift-jis" または encoding="cp932" の指定が必要なことがあります。UnicodeDecodeError が出た場合は pd.read_csv(..., encoding="cp932") を試してください。
janome で形態素解析する
janome の Tokenizer クラスを使ってテキストを形態素(最小意味単位の単語)に分割します。各トークンは品詞・読み・活用形などの情報を持っており、これを使って後のフィルタリングを行います。
from janome.tokenizer import Tokenizer
t = Tokenizer()
# ── 短い文で動作確認 ───────────────────────────────────────
sample = "データベース接続エラーが発生し、サービスが停止した"
print(f"{'表層形':<18} {'品詞':<8} {'品詞細分類1':<10} {'基本形'}")
print("-" * 60)
for token in t.tokenize(sample):
parts = token.part_of_speech.split(",")
pos = parts[0] # 品詞(名詞・動詞・助詞…)
pos_sub = parts[1] # 品詞細分類1
base = token.base_form # 基本形(動詞の原形等)
surface = token.surface # 表層形(元の文字列)
print(f"{surface:<18} {pos:<8} {pos_sub:<10} {base}")
表層形 品詞 品詞細分類1 基本形 ------------------------------------------------------------ データベース 名詞 一般 データベース 接続 名詞 サ変接続 接続 エラー 名詞 一般 エラー が 助詞 格助詞 が 発生 名詞 サ変接続 発生 し 動詞 自立 する 、 記号 読点 、 サービス 名詞 一般 サービス が 助詞 格助詞 が 停止 名詞 サ変接続 停止 し 動詞 自立 する た 助動詞 * た
💡 wakati=True モード
Tokenizer(wakati=True) で初期化すると、品詞情報を解析せず表層形のみを取得するワカチ書き専用モードになります。大量テキストでは通常モードより 2〜3 倍高速です。ただし品詞によるフィルタリングができないため、今回のような「名詞だけ抽出したい」用途では通常モードを使います。
品詞フィルタリング
「が」「を」「に」などの助詞や、「した」「ある」などの補助動詞はワードクラウドに含めてもノイズになるだけです。名詞・動詞・形容詞に絞り、さらに 1 文字語や数字のみの語を除外することで質の高い単語列を得られます。
from janome.tokenizer import Tokenizer
def extract_words(text: str, use_base_form: bool = False) -> str:
"""
テキストを形態素解析し、名詞・動詞・形容詞のみを
スペース区切りの文字列として返す。
Parameters
----------
text : str
解析対象テキスト
use_base_form : bool, default False
True にすると動詞・形容詞を基本形(原形)に変換して返す
例: "停止した" → "停止 する" ではなく "停止 する"(動詞は基本形)
Returns
-------
str
スペース区切りの単語列
"""
t = Tokenizer()
# 抽出する品詞(大分類)
keep_pos = {"名詞", "動詞", "形容詞"}
# 除外する名詞の細分類(数字・記号・接尾辞など)
exclude_noun_sub = {"数", "接尾", "非自立", "代名詞"}
words = []
for token in t.tokenize(text):
parts = token.part_of_speech.split(",")
pos = parts[0] # 品詞(大分類)
pos_sub = parts[1] # 品詞細分類1
surface = token.surface # 表層形
base_form = token.base_form # 基本形
# 対象品詞以外はスキップ
if pos not in keep_pos:
continue
# 名詞:細分類による追加除外
if pos == "名詞" and pos_sub in exclude_noun_sub:
continue
# 動詞の補助動詞(「して」の「し」など)を除外
if pos == "動詞" and pos_sub == "非自立":
continue
# 表示に使うフォーム(基本形 or 表層形)
word = base_form if (use_base_form and pos in {"動詞", "形容詞"}) else surface
# 1 文字語・数字のみの語はノイズになるので除外
if len(word) <= 1 or word.isdigit():
continue
words.append(word)
return " ".join(words)
# ── 動作確認 ──────────────────────────────────────────────────────────
sample = "データベース接続エラーが発生し、サービスが停止した。コネクションプールの設定ミス"
result = extract_words(sample)
print("フィルタ後:")
print(result)
フィルタ後: データベース 接続 エラー 発生 サービス 停止 コネクション プール 設定 ミス
「が」「し」「た」などのノイズが除去され、障害に関連する意味のある単語だけが残りました。この単語列がワードクラウドへの入力になります。
| 除外ルール | 対象の例 | 理由 |
|---|---|---|
| 品詞が名詞・動詞・形容詞以外 | が・を・に(助詞)、した・です(助動詞) | 意味を持たない機能語 |
| 名詞の細分類が数・接尾・非自立・代名詞 | 1・2・目・もの | 数値や接尾辞は単独では意味不明 |
| 動詞の細分類が非自立 | して・しまって | 補助動詞は意味が希薄 |
| 1 文字語 / 数字のみ | し・さ・1・42 | ワードクラウドのノイズになる |
前処理から解析まで一括実行
ここまでの処理を 1 つの関数にまとめます。Excel を読み込んで形態素解析済みのテキストを返すエントリーポイントを作っておくと、PART 03 のワードクラウド生成コードからシンプルに呼び出せます。
import pandas as pd
from janome.tokenizer import Tokenizer
def extract_words(text: str) -> str:
"""名詞・動詞・形容詞(1文字以上、数字除外)をスペース区切りで返す"""
t = Tokenizer()
keep_pos = {"名詞", "動詞", "形容詞"}
exclude_sub = {"数", "接尾", "非自立", "代名詞"}
words = []
for token in t.tokenize(text):
parts = token.part_of_speech.split(",")
pos = parts[0]
sub = 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 load_and_tokenize(
filepath: str,
text_cols: list[str],
sheet_name: int | str = 0,
) -> str:
"""
Excel を読み込み、指定列を結合して形態素解析した単語列を返す。
Parameters
----------
filepath : Excel ファイルパス
text_cols : 分析対象の列名リスト
sheet_name : シート名またはインデックス(デフォルト: 0)
Returns
-------
str スペース区切りの単語列
"""
df = pd.read_excel(filepath, sheet_name=sheet_name)
# 指定列の欠損を空文字に変換して結合
text_series = (
df[text_cols]
.fillna("")
.apply(lambda row: "。".join(row.values.astype(str)), axis=1)
)
combined = " ".join(text_series.tolist())
tokenized = extract_words(combined)
return tokenized
# ── エントリーポイント ────────────────────────────────────────────────────
if __name__ == "__main__":
result = load_and_tokenize(
filepath = "incident_log.xlsx",
text_cols = ["障害内容", "原因"],
)
print(f"総単語数: {len(result.split())}")
print("先頭 20 単語:")
print(" / ".join(result.split()[:20]))
総単語数: 57 先頭 20 単語: データベース / 接続 / エラー / 発生 / サービス / 停止 / コネクション / プール / 設定 / ミス / ネットワーク / 障害 / タイムアウト / 多発 / ネットワーク / 機器 / ファームウェア / 不具合 / メモリ / 不足
✅ 次の PART 03 では…
ここで完成した load_and_tokenize() 関数を使い、wordcloud と matplotlib でワードクラウド画像を生成・表示・PNG 保存します。ストップワードの追加や月次自動生成といった応用例も紹介します。