Pythonを使ってエクセルからデータを収集・分析・グラフ化する方法

グラフデータ Python
スポンサーリンク
スポンサーリンク

「普段のデータ分析やレポート作成を効率化したい。」

「Pythonのグラフ作成技術を習得したい。」

上記の疑問にお答えします。

この記事では、Pythonを使ってExcelのデータを分析し、見やすいグラフを作成する方法を、初心者にも理解しやすく解説します。

具体的に次のことを解説します。

  • 【準備】Pythonによるデータ分析とグラフ化をする前に
  • 【紹介】使用するライブラリ
  • 【実践】ソースコードと解説

 

「偉そうに語るおまえは誰やねん。」と思われるので、私のことも少し紹介させてください。

たいらーのプロフィール

  • 文系四大出身。ソフトウェア開発の経験はなしですが、IT業界に身を置いています。
  • 開発者やユーザーとのパイプ役など、業務にプログラミングスキルを活かす。
  • Pythonは独学で習得。スクレイピングや作業の自動化などに勤しんでいます。

 

Pythonを使ってデータの収集や分析、グラフ化ができれば、作業の効率が格段に上がり、もっと重要な業務に集中できるようになるでしょう。

この記事を参考に、ぜひ業務にPythonを活用してみてください

 

1.【準備】Pythonによるデータ分析とグラフ化をする前に

ここでは、データ分析とグラフ化をする前に必要な準備と、前提条件について説明します。

 

・Pythonのインストール

Pythonを始めるには、まずインストールと基本的な設定が必要です。

Pythonのインストールがまだの方は次の記事を参考にして、Pythonをインストールしましょう。

Python3のインストール方法【導入は10分で完了!】

 

・今回の前提条件

今回は、勤怠管理をテーマに説明します。

業務フローは、よくありそうな次のケースを前提として、コードを実装します。

  1. 各部署の従業員は、会社指定のエクセルの勤務管理表で月の勤務時間などを記録、報告している。
  2. 従業員は、月に1回、月末に勤務管理表を事務員に提出している。
  3. 担当の事務員は、各従業員の実働時間、残業時間などを集計し、上司に報告している。

 

勤務を管理するための「勤務管理表」は、例として次を使用します。(クリックで拡大)

勤務管理表_03

 

作業場所として、デスクトップに「勤務管理表」フォルダを作成し、その中に各従業員の勤務管理表を格納します。

勤務管理表_01

勤務管理表_02

 

最終的には、報告レポートとして、次のようにまとめたいと思います。

各従業員の稼働時間と残業時間を一覧にし、部署ごとの残業時間をグラフ化します。

結果_01

結果_02

 

2.【紹介】使用するライブラリ

今回紹介するコードでは、次のライブラリを使用しています。

各ライブラリについて、簡単に説明しておきます。

 

pandas

pandasは、データ分析と操作のための強力なライブラリで、主にデータフレームという形式でデータを扱います。

統計分析やデータクリーニングに広く用いられています。

 

os

osライブラリは、オペレーティングシステムとのやり取りを可能にするための機能を提供します。

ファイルやディレクトリの操作、パスの操作、システム情報の取得などが可能です。

 

glob

globライブラリは、ファイルシステム内でのファイルの検索に使用されます。

ワイルドカードを使用したパターンマッチングにより、ディレクトリ内のファイルリストを取得するのに便利です。

 

datetime

datetimeライブラリは、日付や時刻に関するデータを扱うためのものです。

日付や時刻の生成、操作、算出などが可能で、時間に関連した様々なプログラミングタスクに使用されます。

 

matplotlib

matplotlibは、グラフやチャートを作成するためのライブラリです。

データの可視化に非常に有用で、多様なプロットスタイルやフォーマットをサポートしています。

 

openpyxl

openpyxlは、Excelファイル(.xlsx)を読み書きするためのライブラリです。

Excelファイルの生成、既存ファイルの読み込みや編集、データの操作などが可能です。

 

これらの情報を表にまとめると以下のようになります。

ライブラリ/モジュール概要
pandasデータ分析と操作のためのライブラリ。データフレームを用いたデータ処理に特化。
osオペレーティングシステムとのインタラクションを可能にする機能を提供。
globファイルシステム内でのファイル検索に使用。ワイルドカードによる検索が可能。
datetime日付や時刻のデータを扱う。日付の生成・操作・算出などに用いられる。
matplotlibグラフやチャートの作成に用いるデータ可視化ライブラリ。
openpyxlExcelファイルの読み書きを行う。.xlsxファイルの生成・編集に適用。

 

3.【実践】ソースコードと解説

下記は、ソースコードの全文です。解説は後述します。

 

ソースコード

import pandas as pd
import os, glob, datetime
import matplotlib.pyplot as plt
from openpyxl import load_workbook
from openpyxl.drawing.image import Image
from openpyxl.styles import Border, Side

# ディレクトリのパスを設定
directory_path = 'C:/デスクトップの勤務管理表フォルダ'

# ディレクトリ内のExcelファイル(.xlsxおよび.xls)を探す
excel_files = glob.glob(os.path.join(directory_path, '*.xlsx')) + glob.glob(os.path.join(directory_path, '*.xls'))

# 各ファイルから抽出した情報を格納するためのリスト
employee_info_list = []

def process_datetime(data):
    # ダミーの日付データ
    dummy_date = datetime.datetime(1900, 1, 1, 0, 0, 0)

    # dataがdatetime.timeオブジェクトの場合、今日の日付を追加
    if isinstance(data, datetime.time):
        return datetime.datetime.combine(dummy_date, data)
    # dataがdatetime.datetimeオブジェクトの場合、そのまま返す
    elif isinstance(data, datetime.datetime):
        return data
    # その他の場合、エラーまたは適切な処理を行う
    else:
        raise ValueError("Unsupported data type")

# 各ファイルを読み込んで必要な情報を抽出
for file_path in excel_files:
    try:
        # .xlsxファイルの場合はengine='openpyxl'を使用して読み込む
        if file_path.endswith('.xlsx'):
            df = pd.read_excel(file_path, engine='openpyxl')
        else:
            df = pd.read_excel(file_path)
                     
        # 実働時間合計と残業時間合計の計算     
        worktime = process_datetime(df.iloc[36, 6])
        overtime = process_datetime(df.iloc[36, 7])
         
        # 計算用に日・時・分・秒に分解して変換
        wk_day = float(worktime.day)
        wk_hour = float(worktime.hour)
        wk_minute = float(worktime.minute)
        wk_sec = float(worktime.second)
          
        ot_day = float(overtime.day)
        ot_hour = float(overtime.hour)
        ot_minute = float(overtime.minute)
        ot_sec = float(overtime.second)

        # 再計算
        # 日付が1900/01/01 より小さい場合と 1900/01/01の場合は、dayの加算はしない      
        bace_date1 = datetime.datetime(1900, 1, 1, 0, 0, 0)
        bace_date2 = datetime.datetime(1900, 1, 1, 23, 59, 59)

        total_worktime_hours = wk_day *24 + wk_hour + wk_minute / 60 + wk_sec / 3600
                
        if overtime > bace_date1 and overtime < bace_date2 :
            total_overtime_hours = ot_hour + ot_minute / 60 + ot_sec / 3600  
        elif overtime <= bace_date1 :
            total_overtime_hours = ot_hour + ot_minute / 60 + ot_sec / 3600    
        else:
            total_overtime_hours = ot_day *24 + ot_hour + ot_minute / 60 + ot_sec / 3600
                
        # 必要な情報を抽出
        employee_info = {
            '社員番号': df.iloc[1, 2],  # C3セル
            '氏名': df.iloc[2, 2],      # C4セル
            '部署': df.iloc[1, 6],      # G3セル
            '役職': df.iloc[2, 6],      # G4セル
            '実働時間合計': total_worktime_hours,  # G38セル
            '残業時間合計': total_overtime_hours   # H38セル
        }

        # リストに追加
        employee_info_list.append(employee_info)
    except Exception as e:
        print(f"Error in file {file_path}: {e}")

# リストからDataFrameを作成
combined_data = pd.DataFrame(employee_info_list)

# 新しいExcelファイルとして保存
combined_data.to_excel('employee_data.xlsx', index=False)

#---
#グラフ作成
#---
# グラフのサイズを設定(幅、高さをインチで指定)
plt.figure(figsize=(10, 6))

# 部署ごとの平均残業時間の計算
department_average_overtime = combined_data.groupby('部署')['残業時間合計'].mean()

# 棒グラフの表示
department_average_overtime.plot(kind='bar')

plt.title('部署ごとの残業時間(平均)', fontname="Meiryo", fontsize=14)
plt.xlabel('部署', fontname="Meiryo", fontsize=12)
plt.ylabel('残業時間平均(時間)', fontname="Meiryo", fontsize=12)
plt.xticks(fontname="Meiryo", fontsize=10)
plt.axhline(y=40, color='r', linestyle='--')

# グラフを画像ファイルとして保存
plt.savefig('graph.png')

# Excelファイルを開く
workbook = load_workbook('employee_data.xlsx')

# シート名を変更('Sheet1'を'一覧'に変更)
sheet = workbook['Sheet1']
sheet.title = '一覧'

ws = workbook.active

# 罫線のスタイルを定義
thin_border = Border(left=Side(style='thin'), 
                     right=Side(style='thin'), 
                     top=Side(style='thin'), 
                     bottom=Side(style='thin'))

# 全てのセルに罫線を適用
for row in ws.iter_rows():
    for cell in row:
        cell.border = thin_border

# 新しいシートを作成(または既存のシートを選択)
if "Graphs" not in workbook.sheetnames:
    sheet = workbook.create_sheet("Graphs")
else:
    sheet = workbook["Graphs"]

# 画像を挿入
img = Image('graph.png')
sheet.add_image(img, 'A1')  # 'A1'は画像を挿入するセル位置

# 変更を保存
workbook.save('employee_data.xlsx')

 

解説

伝わりにくい箇所を解説します。

17行目から29行目は、Excelファイルから読み込んだ時間データを datetime.datetime オブジェクトにそろえるための関数です。

エクセルの時間データが、datetime.time の場合があるので、このような関数を作成しています。

既にdatetime.datetimeの場合は、そのまま返すようにしています。

def process_datetime(data):
  # ダミーの日付データ
  dummy_date = datetime.datetime(1900, 1, 1, 0, 0, 0)

  # dataがdatetime.timeオブジェクトの場合、今日の日付を追加
  if isinstance(data, datetime.time):
    return datetime.datetime.combine(dummy_date, data)
  # dataがdatetime.datetimeオブジェクトの場合、そのまま返す
  elif isinstance(data, datetime.datetime):
    return data
  # その他の場合、エラーまたは適切な処理を行う
  else:
    raise ValueError("Unsupported data type")

 

31行目から82行目までは、エクセルファイルから必要な情報を抽出しています。

エクセルファイルから実働時間合計と残業時間合計を読み込んだ後は、日付のままだと計算ができないため、日数、時間数、分数、秒数に分解し、実働時間と残業時間を時間数に変換して計算しています。

# 各ファイルを読み込んで必要な情報を抽出
for file_path in excel_files:
  try:
    ・・・
  except Exception as e:
    print(f"Error in file {file_path}: {e}")

 

90行目から109行目では、棒グラフを作成しています。

グラフの要素を簡単に説明すると、次のようになります。

各要素では、フォントの種類やサイズなどを設定することができます。

plt.figure() :グラフのサイズを設定
plt.title:グラフのタイトル
plt.xlabel:グラフのX軸のラベルを設定
plt.ylabel:グラフのY軸のラベルを設定
plt.xticks:X軸の目盛りを設定
plt.axhline:基準線を設定
#---
#グラフ作成
#---
# グラフのサイズを設定(幅、高さをインチで指定)
plt.figure(figsize=(10, 6))

# 部署ごとの平均残業時間の計算
department_average_overtime = combined_data.groupby('部署')['残業時間合計'].mean()

・・・

# グラフを画像ファイルとして保存
plt.savefig('graph.png')

 

111行目以降は、グラフをエクセルファイル追加し、実稼働時間、残業時間の集計表のレイアウトを整えています。

グラフは、新たにシートを追加して保存しています。

# Excelファイルを開く
workbook = load_workbook('employee_data.xlsx')

・・・

# 変更を保存
workbook.save('employee_data.xlsx')

 

4.まとめ

このようにPythonを使用すれば、煩雑な集計作業も簡単に終わらせることができます。

記事で紹介した技術を活用して、日々の業務をよりスマートに進めましょう。

このブログでは、Pythonによる業務効率化やプログラミング初心者のためのPython学習法を紹介していますので、ぜひご覧ください。

 

ご清聴ありがとうございました。