はじめに
忘年会の乾杯前に
「今年一年、みなさんお疲れ様でした〜!」
で終わるのは、普通すぎる
というわけで今年は、
Slack/Teams のログを形態素解析して “今年の漢字” を技術で決める
という、エンジニア魂くすぐる遊びをやってみた
今年の漢字を “技術で” 決めるとは?
やったことはシンプル:
- 社内の公開チャンネルから CSV(text列)を回収
- Python(tkinter)で CSV を読み込む GUI を作成
- 文を形態素解析して 単語の出現頻度 TOP100 を算出
- WordCloud で画像化
- 忘年会で発表:「今年の社内は、◯◯の一年でした!」
↓こういう “今年の漢字パネル風” を作れる
(※今回のデータはダミーデータ)
一番ウケた使い方:
乾杯の前に突然 “解析レポート” を出す
乾杯の前に、司会の人が言う:
「エンジニアの私は、みなさんが今年一年どんな思いで働いていたのか、
Slackログを全部解析して決めました
今年の社内を一文字で表すと……こちらです!」
プロジェクターに WordCloudドーン!
「障害」「会議」「調整」「対応」「ありがとう」「大変」
の文字が巨大に浮かび上がる
会場:
「あーーーーー!!!」(謎の一体感)
技術的にはこうなってる(ネタでも安心の実装)
※tkinterでGUI・CSV選択式
※必要最小限の形態素解析+WordCloud
解析してみたら “社内の1年” が一目でわかる
頻出ワードを見ると、
その会社らしさ・チームらしさが丸裸になる
例:
- 「会議」「調整」が太ってる → ミーティング過多の年
- 「障害」「対応」が多め → たくさん戦った年
- 「ありがとう」も多い → 意外と温かいチーム
- 「眠い」「カオス」が頻出 → おつかれさまでした…
忘年会でこれを出すと、
謎の“心の距離が縮まる”効果がある
エンジニアは “忘年会” すら技術でハックする
ただ乾杯するだけじゃ面白くない
どうせなら 技術で遊んでネタにする のがエンジニア
「今年の漢字」を
Slackログ × 形態素解析 × WordCloud × tkinter
で自動生成すると、忘年会の場が一気に温まる
来年は以下も検討したい:
- “今月の漢字” 自動生成
- “プロジェクトごとのWordCloud対決”
- “新人Slackログだけで作る1年のまとめ”
- “部長の発言だけでWordCloud作る”(絶対盛り上がる)
全体コードはこちら↓
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import csv
from janome.tokenizer import Tokenizer
from collections import Counter
from wordcloud import WordCloud
from PIL import Image, ImageTk
import io
import re
# ---------------------------
# 今年の漢字推定ロジック
# ---------------------------
def suggest_kanji(freq_words):
mapping = {
"問題": "問", "課題": "課", "障害": "障", "調整": "調", "改善": "改",
"不具合": "修", "売上": "売", "事業": "事", "成功": "成", "予算": "予",
"挑戦": "挑", "開発": "開", "対応": "対", "成長": "成", "感謝": "感"
}
for word, _ in freq_words:
if word in mapping:
return mapping[word]
# fallback:単語の中から漢字を1つ抜く
for word, _ in freq_words:
kanji = re.findall(r"[一-龥]", word)
if kanji:
return kanji[0]
return "無"
# ---------------------------
# WordCloud生成
# ---------------------------
def generate_wordcloud(freq_dict):
text = " ".join([((k + " ") * v) for k, v in freq_dict.items()])
wc = WordCloud(
width=600,
height=400,
background_color="white",
font_path="/System/Library/Fonts/ヒラギノ角ゴシック W3.ttc" # Mac前提
).generate(text)
buf = io.BytesIO()
wc.to_image().save(buf, format="PNG")
buf.seek(0)
return buf
# ---------------------------
# CSV読み込み(pandas不使用)
# ---------------------------
def read_csv_text_column(path):
"""CSVから text 列だけを抽出する(pandasなし)"""
texts = []
try:
with open(path, encoding="utf-8") as f:
reader = csv.DictReader(f)
if "text" not in reader.fieldnames:
messagebox.showerror("エラー", "CSV に 'text' 列がありません。")
return None
for row in reader:
texts.append(row.get("text", ""))
except Exception as e:
messagebox.showerror("エラー", f"CSV読み込みエラー:\n{e}")
return None
return texts
# ---------------------------
# CSV解析本体
# ---------------------------
def analyze_csv(path, result_text, canvas):
texts = read_csv_text_column(path)
if texts is None:
return
tokenizer = Tokenizer()
words = []
# 形態素解析
for t in texts:
for token in tokenizer.tokenize(t):
pos = token.part_of_speech.split(",")[0]
if pos in ["名詞", "動詞", "形容詞"]:
base = token.base_form
if len(base) > 1:
words.append(base)
freq = Counter(words)
top100 = freq.most_common(100)
# 今年の漢字
this_kanji = suggest_kanji(top100)
# UIリセット
result_text.delete(1.0, tk.END)
canvas.delete("all")
# 結果出力
result_text.insert(tk.END, f"【今年の社内漢字】 → 「{this_kanji}」\n")
result_text.insert(tk.END, "-" * 40 + "\n")
for word, count in top100:
result_text.insert(tk.END, f"{word}: {count}\n")
# WordCloud生成
wc_buf = generate_wordcloud(dict(top100))
img = Image.open(wc_buf)
img = img.resize((400, 300), Image.LANCZOS)
img_tk = ImageTk.PhotoImage(img)
canvas.image = img_tk
canvas.create_image(0, 0, anchor="nw", image=img_tk)
# ---------------------------
# Tkinter GUI
# ---------------------------
def main():
root = tk.Tk()
root.title("今年の社内漢字 解析アプリ")
root.geometry("900x600")
frame = ttk.Frame(root)
frame.pack(padx=20, pady=20, fill="both", expand=True)
# CSV選択ボタン
def select_file():
path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
if path:
analyze_csv(path, result_text, canvas)
btn = ttk.Button(frame, text="CSVを選択", command=select_file)
btn.pack(anchor="w", pady=5)
# 結果テキスト
result_text = tk.Text(frame, width=50, height=30)
result_text.pack(side="left", padx=10, pady=10)
# WordCloud描画キャンバス
canvas = tk.Canvas(frame, width=400, height=300, bg="white")
canvas.pack(side="right", padx=10, pady=10)
root.mainloop()
if __name__ == "__main__":
main()
