![見出し画像](https://assets.st-note.com/production/uploads/images/144223583/rectangle_large_type_2_0a37776d10b5a8469fcbe0028eb8c85f.jpeg?width=1200)
PythonでHRMOSから出力したCSVのデータを可視化するスクリプト
HRMOSのダッシュボードの数値では手の届かない痒い部分がある
前職でもHRMOSを使用していて、現在でもHRMOSを使用しています。
しかし、ダッシュボードでは自社に必要なデータを見ることが出来ないという理由でスプレッドシートに書き出して分析していました。
VLOOKUPを使って必要なデータを抽出したり、
複雑なCOUNTIFやらSUMIFを使って、ゴニョゴニョ….。
こういうのPythonで一発で出来たらいいよなぁーと思って作ったのが今回のスクリプトです。
手始めに今回作ったのは、採用媒体別の応募者数を棒グラフで出力するスクリプトです。手元にHRMOSのCSVデータがないため、グラフをお見せ出来ないのですが、ちょっとPythonの可能性を感じました。
実行環境
Windows 11
Visual Studio Code
Pythonスクリプト全文…..長いです。
長いけど、Chat GPTとかに書かせているので、自分ではそこまで書いていません。それよりもハルシネーション(AIがそれっぽい嘘を付くこと)が厄介です。プログラミングの場合はエラーが起きるので、今のが嘘だなと分かりやすいですが…..。
import os
from glob import glob
from datetime import datetime
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rcParams
import seaborn as sns
def get_latest_file(dir_path):
"""
指定されたフォルダから最新のCSVファイルを取得する
"""
files = glob(os.path.join(dir_path, "*.csv"))
if not files:
return None
latest_file = max(files, key=os.path.getctime)
print(f"最新のファイル名: {os.path.basename(latest_file)}\n\n")
return latest_file
def select_df(df):
"""
必要なカラムに限定して取得する
欠損値を '-' で埋める
"""
df.fillna('-', inplace=True)
print(df.columns)
target_columns = ['応募ID', '求人ID', '選考ポジション名', '応募日', '氏名', '所属組織', '生年月日', '応募経路詳細', 'レジュメ(フリーテキスト)', '選考ステータス', '1次ステップ判定結果入力日', '2次ステップ判定結果入力日', '3次ステップ判定結果入力日', '4次ステップ判定結果入力日', '5次ステップ判定結果入力日', '不合格・重複終了日', '辞退理由(詳細)']
df_selected = df[target_columns]
return df_selected
def preprocess_data(df_selected):
"""
データフレームの前処理を行います。
Args:
df_selected (pandas.DataFrame): 応募データが含まれるデータフレーム。
media_counts (pandas.Series): メディアのカウント情報が含まれるシリーズ。
Returns:
pandas.DataFrame: 前処理後のデータフレーム。
"""
# 株式会社など円グラフの表示に不要な部分を置換する
df_selected['応募経路詳細'] = df_selected['応募経路詳細'].replace('-', '自社')
df_selected['応募経路詳細'] = df_selected['応募経路詳細'].apply(lambda x: x if x in ['ビズリーチ', 'Green', 'Wantedly', '自社', 'Findy'] else 'エージェント')
# 応募経路詳細を置換した上で、媒体別の応募者数をカウント
media_counts = df_selected['応募経路詳細'].value_counts().sort_values(ascending=False)
# yyyy/MM/dd形式に変換後、データ型を日付時刻型に変換する
df_selected['応募日'] = pd.to_datetime(df_selected['応募日'], format='%Y年%m月%d日').dt.strftime('%Y/%m/%d')
df_selected['応募日'] = pd.to_datetime(df_selected['応募日'])
print(df_selected['応募日'].dtype)
monthly_applications = df_selected.groupby([df_selected['応募日'].dt.to_period('M'), '応募経路詳細']).size().unstack()
monthly_applications = monthly_applications[media_counts.index]
print(monthly_applications)
return monthly_applications, media_counts
def select_color(media_counts):
"""
積み上げ棒グラフの色を指定するための関数
FIXME: color_mapに該当がない場合、灰色(#d0cacd)として出力されてしまう
"""
color_map = {
'ビズリーチ': '#0b2787',
'Green': '#60b630',
'Wantedly': '#21bddb',
'自社': '#ff0000',
'Findy': '#109f95'
}
colors = media_counts.index.map(lambda x: color_map.get(x, "#d0cacd")).tolist()
print(colors)
return colors
def set_style():
"""
Seabornと日本語フォントの設定を行います。
"""
sns.set_style('darkgrid', {'axes.grid': True, 'grid.color': '0.8'})
sns.set_palette('winter_r')
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Yu Gothic', 'Meirio']
def add_percentage_labels(ax, monthly_applications):
"""
積み立て棒グラフに各バーの割合を%で表示します。
Axesオブジェクトとは、matplotlibにおける中心的なクラスの一つです。
グラフの描画領域(プロットエリア)を定義します。
グラフのタイトル、軸のラベル、軸の範囲など、グラフの各要素を管理します
Args:
ax (matplotlib.axes.Axes): 描画する棒グラフのAxesオブジェクト。
monthly_applications (pandas.DataFrame): 月別の応募数が含まれるデータフレーム。
Returns:
None
"""
for p in ax.patches:
width, height = p.get_width(), p.get_height()
# バーの高さが0でない場合のみテキストを描画
if height > 0:
x, y = p.get_xy()
# 各バーの割合を計算して表示
percentage = height / monthly_applications.sum(axis=1).iloc[int(x + width / 2)] * 100
ax.text(x + width / 2,
y + height / 2,
'{:.0f}%'.format(round(percentage)), # テキストを整数で表示
horizontalalignment='center',
verticalalignment='center',
color='white',
fontdict={'weight': 'bold'})
def fill_missing_values(data):
"""
欠損値を0で置き換え、小数点以下を切り捨てる
"""
data = data.copy()
data = data.fillna(0).astype(int)
print(data.head(3))
return data
def create_table(ax, df):
"""
指定された軸上にデータフレームを表形式で表示します。
Args:
ax (matplotlib.axes.Axes): 表を表示する軸。
df (pandas.DataFrame): 表示するデータフレーム。
Returns:
matplotlib.table.Table: 作成した表。
"""
ax.axis('off')
table = ax.table(cellText=df.values,
colLabels=df.columns,
rowLabels=df.index,
cellLoc='center',
loc='center',
bbox=[0, 0.3, 1, 1.4])
table.auto_set_font_size(False)
table.set_fontsize(12)
table.scale(1.1, 1.3) # スケールの調整
return table
def decorate_table(table):
"""
表に色分けや装飾を追加します。
Args:
table (matplotlib.table.Table): 装飾を追加する表。
"""
# ヘッダー行の色を変更
header_color = '#40466e' # ヘッダー行の背景色を指定
for key, cell in table.get_celld().items():
if key[0] == 0:
cell.set_text_props(weight='bold', color='white') # テキストの色を白に変更
cell.set_facecolor(header_color) # 背景色を再設定
elif key[0] % 2 == 0:
# visible_edgeの記載があると、set_facecolorが無効化されるかもしれない
cell.visible_edges = 'BT'
# cell.set_facecolor('#d8dae2')
else:
# 縦の罫線を消す
cell.visible_edges = 'BT' # 下端と上端の罫線のみ表示
# 罫線の色を変更
cell.set_edgecolor('#797d99')
def create_bar_chart(monthly_applications, colors):
"""
月別の応募者数を積み立て棒グラフで描画し、画像として保存します。
Args:
df_selected (pandas.DataFrame): 応募データが含まれるデータフレーム。
media_counts (pandas.Series): メディアのカウント情報が含まれるシリーズ。
colors (list): 棒グラフの色を指定するリスト。
destination_path (str): グラフの画像を保存するパス。
Returns:
None
"""
set_style()
fig, ax = plt.subplots(figsize=(12, 8))
# 棒グラフを描画
monthly_applications.plot(kind='bar', stacked=True, ax=ax, color=colors, edgecolor="none")
# X軸のラベルを回転
plt.xticks(rotation=0)
# 縦の罫線を消す
plt.rcParams['axes.grid.axis'] = 'y'
ax.xaxis.grid(False)
plt.title('媒体別応募数の推移', fontsize=20, fontdict={'weight': 'bold'})
plt.xlabel('') # 何も書かないと応募日が表示されてしまう
# 凡例の表示(背景色、罫線無し、グラフの外)
plt.legend(bbox_to_anchor=(1.0, 1), loc='upper left', fontsize=14, facecolor='none', frameon=False)
plt.tight_layout()
# 各バーの割合を%で表示
add_percentage_labels(ax, monthly_applications) # 別途定義されている関数
return fig
def create_chart_and_table(monthly_applications, colors):
"""
月別の応募者数を積み立て棒グラフで描画し、画像として保存します。
Args:
df_selected (pandas.DataFrame): 応募データが含まれるデータフレーム。
media_counts (pandas.Series): メディアのカウント情報が含まれるシリーズ。
colors (list): 棒グラフの色を指定するリスト。
destination_path (str): グラフの画像を保存するパス。
Returns:
None
"""
set_style()
fig = plt.figure(figsize=(12, 9))
ax1 = fig.add_subplot(211) # 上のグラフ
ax2 = fig.add_axes([0.1, 0.065, 0.6, 0.2]) # 下の表を描画する場所の指定
"""
最初の値 (x): 表の左下隅の x 座標 (0.0 はグラフの左端、1.0 はグラフの右端)
2番目の値 (y): 表の左下隅の y 座標 (0.0 はグラフの下端、1.0 はグラフの上端)
3番目の値 (width): 表の幅 (0.0 から 1.0 まで)
4番目の値 (height): 表の高さ (0.0 から 1.0 まで)
"""
# 棒グラフを描画
monthly_applications.plot(kind='bar', stacked=True, ax=ax1, color=colors, edgecolor="none")
# X軸のラベルを回転
ax1.tick_params(axis='x', labelrotation=0) # ax1 に対して回転を設定
# 縦の罫線を消す
plt.rcParams['axes.grid.axis'] = 'y'
ax1.xaxis.grid(False) # ax1 に対してグリッドを設定
ax1.set_title('媒体別応募数の推移', fontsize=20, fontdict={'weight': 'bold'}) # ax1 に対してタイトルを設定
ax1.set_xlabel('') # ax1 に対して X 軸ラベルを設定
# 凡例の表示(背景色、罫線無し、グラフの外)
ax1.legend(bbox_to_anchor=(1.0, 1), loc='upper left', fontsize=14, facecolor='none', frameon=False)
plt.tight_layout()
# 各バーの割合を%で表示
add_percentage_labels(ax1, monthly_applications) # 別途定義されている関数
# グラフと一緒にテーブルを描画
data = fill_missing_values(monthly_applications)
table = create_table(ax2, data)
decorate_table(table)
return fig
def get_current_time_string():
"""
現在の日時を文字列形式で取得します。
Returns:
str: 現在の日時を表す文字列(形式: "YYYY_MMDD_HHMM")。
"""
current_time = datetime.now()
date_string = current_time.strftime("%Y_%m%d_%H%M")
return date_string
def save_fig(fig, destination_path, file_name):
"""
グラフを画像として保存します。
Args:
fig (matplotlib.figure.Figure): 保存するグラフのFigureオブジェクト。
destination_path (str): グラフの画像を保存するパス。
"""
merged = f'{destination_path}{file_name}'
fig.savefig(merged)
plt.show() # 必要であれば表示
def visualize_monthly_application():
"""
HRMOSのCSVから月間の応募者数を採用媒体別に集計、グラフで表示する関数
半期ベースで見る事を想定
FIXME: 対象期間が長いと表やグラフが見切れる可能性がある
"""
# hrmos_csvのフォルダから最新のCSVを取得する
dir_path = r'c:/Users/user/Desktop/*********/hrmos_csv/'
latest_file = get_latest_file(dir_path)
if os.path.exists(latest_file):
print("ファイルが存在します")
# HRMOSのCSVをUTF-16形式でData Frameとして取得する
df = pd.read_csv(latest_file, encoding='utf-16', sep='\t')
df_selected = select_df(df)
# 月間の媒体別応募者数を算出
monthly_applications, media_counts = preprocess_data(df_selected)
colors = select_color(media_counts)
# 日本語表記でグラフを描画
set_style()
# fig = create_bar_chart(monthly_applications, colors)
fig = create_chart_and_table(monthly_applications, colors)
# グラフを保存するフォルダとファイル名を指定
date_string = get_current_time_string()
destination_path = r'c:/Users/user/Desktop/************/'
file_name = f'bar_graph_{date_string}.jpg'
# 描画されたグラフを保存する
save_fig(fig, destination_path, file_name)
else:
print("ファイルが存在しません")
if __name__ == "__main__":
visualize_monthly_application()
この記事が気に入ったらサポートをしてみませんか?