業務記録を月別の集計表とグラフにする
CSVの日付と作業時間を検証し、月別の記録数と合計時間をCSVと棒グラフに保存します。
四列が完全に一致する行を探し、元の行番号とともに新しいExcelファイルへまとめます。最初に出現した行も含めて、重複グループを確認します。
この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 한국어
対象読者Excelデータを集約した後に重複入力を確認する事務担当者
この例では、order_id、customer、item、quantityの四つの値がすべて一致する行を重複と見なします。注文番号だけが同じ行は重複とは見なしません。文字列の空白や大文字・小文字も自動では変更しません。
重複を削除する前に、同じ内容を持つすべての行をDuplicatesシートに集めます。最初に出現した行も含めます。一回だけ出現した行はUniqueシートに残し、全8行を漏れなく確認できるようにします。
orders.xlsxのシート名はOrdersとし、先頭行の列名と順序を以下に合わせる必要があります。列を追加してもヘッダーエラーになるため、業務ファイルで直接置き換えるのではなく、必要な四列をコピーした練習用ファイルを作ってください。
| 列 | 役割 | 例 |
|---|---|---|
| order_id | 文字列の注文番号 | O-1001 |
| customer | 文字列の顧客名 | Alpha |
| item | 文字列の品目 | Sensor |
| quantity | 正の整数の数量 | 2 |
完全に空の行は読み飛ばします。一部の値が空、または数式を含む場合は停止します。注文番号・顧客名・品目は空でない文字列である必要があり、数値の注文番号は自動で文字列に変換しません。
python --version
python -m pip install -r requirements.txt
python example.pyインストールにはインターネット接続が必要です。コードのBASEは、現在のターミナル位置ではなくexample.pyの位置を基準に入力と結果のパスを決めます。
load_workbookの読み取り専用モードで元のファイルを開き、Counterで各行の出現回数を数えます。元のExcelの行番号は、enumerateのstart=2で記録します。結果は新しいWorkbookに保存するため、元のファイルを保存し直しません。
"""Find repeated business rows. Keep the source workbook unchanged."""
from collections import Counter
from pathlib import Path
from openpyxl import Workbook, load_workbook
from openpyxl.styles import Font, PatternFill
BASE = Path(__file__).resolve().parent
HEADERS = ("order_id", "customer", "item", "quantity")
def main():
destination = BASE / "outputs"
if destination.exists():
raise ValueError("outputs already exists; rename it before running again.")
source = load_workbook(BASE / "orders.xlsx", read_only=True, data_only=False)
try:
if "Orders" not in source.sheetnames:
raise ValueError("Orders sheet is missing.")
worksheet = source["Orders"]
rows = list(worksheet.iter_rows(values_only=True))
if not rows or tuple(rows[0]) != HEADERS:
raise ValueError(f"Expected headers: {HEADERS}")
records = []
for row_number, row in enumerate(rows[1:], start=2):
if all(value is None for value in row):
continue
if any(value is None for value in row):
raise ValueError(f"Row {row_number}: missing value.")
if any(isinstance(value, str) and value.startswith("=") for value in row):
raise ValueError(f"Row {row_number}: formulas are not supported.")
if not all(isinstance(value, str) and value.strip() for value in row[:3]):
raise ValueError(f"Row {row_number}: first three fields must be text.")
if type(row[3]) is not int or row[3] <= 0:
raise ValueError(f"Row {row_number}: quantity must be a positive integer.")
records.append((row_number, tuple(row)))
if not records:
raise ValueError("No data rows were found.")
finally:
source.close()
counts = Counter(row for _, row in records)
repeated = [(number, row) for number, row in records if counts[row] > 1]
unique = [(number, row) for number, row in records if counts[row] == 1]
book = Workbook()
book.remove(book.active)
for name, selected in (("Duplicates", repeated), ("Unique", unique)):
sheet = book.create_sheet(name)
sheet.append(("source_row", *HEADERS, "occurrences"))
for number, row in selected:
sheet.append((number, *row, counts[row]))
sheet.freeze_panes = "A2"
sheet.auto_filter.ref = sheet.dimensions
sheet.sheet_view.showGridLines = False
for cell in sheet[1]:
cell.font = Font(name="Arial", bold=True, color="FFFFFF")
cell.fill = PatternFill("solid", fgColor="243B53")
for column, width in zip("ABCDEF", (14, 16, 18, 20, 14, 16)):
sheet.column_dimensions[column].width = width
destination.mkdir(exist_ok=False)
book.save(destination / "duplicate_review.xlsx")
book.close()
groups = sum(count > 1 for count in counts.values())
print(f"Input rows: {len(records)}; duplicate groups: {groups}")
print(f"Duplicate rows: {len(repeated)}; unique rows: {len(unique)}")
print("Created outputs/duplicate_review.xlsx (source unchanged).")
if __name__ == "__main__":
try:
main()
except (OSError, ValueError) as error:
raise SystemExit(f"Stopped: {error}") from error
outputs/duplicate_review.xlsxにDuplicatesとUniqueの二つのシートが作られます。source_rowは元のExcelの行番号、occurrencesは同じ内容が入力全体に現れた回数です。
| 項目 | 同梱データの結果 |
|---|---|
| 入力データ行数 | 8 |
| 重複グループ数 | 2 |
| Duplicatesの行数 | 4(元の2, 3, 5, 8行) |
| Uniqueの行数 | 4(元の4, 6, 7, 9行) |
Duplicatesに4行あるからといって、削除すべき行が4行あるわけではありません。各グループから一行ずつ残すなら余分に入力された行は2行ですが、何を残すかは元のファイルを確認してから決める必要があります。
| メッセージまたは症状 | 確認すること |
|---|---|
| Orders sheet is missing | 元のシート名をOrdersに合わせます。 |
| Expected headers | 列名、順序、余分な列を確認します。 |
| missing value / formulas are not supported | 表示された元の行を確認し、数式ではなく値で用意します。 |
| quantity must be a positive integer | 数量は1以上の整数で入力します。 |
| outputs already exists | 前回の結果フォルダーを別名にして保管します。 |
| ModuleNotFoundError | 実行に使うpythonで、requirements.txtのパッケージをインストールします。 |
Windows 11 (10.0.26200)、CPython 3.12.14(64ビット)。openpyxl 3.1.5、Matplotlib 3.10.8。各例で使用するライブラリのバージョンはrequirements.txtで固定しています。
コード、入力データ、実行手順が含まれています。展開して、まずREADME.txtを読んでください。
サンプルZIPをダウンロードサンプルコード、ファイル名、入力キーは原文のままです。翻訳本文のコマンドと確認手順も併せて参照してください。
独自に作成した練習用資料 · 元のファイルを別に保管してから実行してください。
説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。