|
import openpyxl |
|
from openpyxl import Workbook |
|
from openpyxl.styles import PatternFill, Font, Alignment, Border, Side |
|
from openpyxl.formatting.rule import ColorScaleRule, DataBarRule, IconSetRule |
|
from openpyxl.chart import BarChart, LineChart, PieChart, ScatterChart, Reference |
|
from openpyxl.utils import get_column_letter |
|
import random |
|
from datetime import datetime, timedelta |
|
import math |
|
|
|
def create_complex_workbook(): |
|
wb = Workbook() |
|
|
|
# シート1: 売上データ (基本データ) |
|
ws_sales = wb.active |
|
ws_sales.title = "売上データ" |
|
|
|
# ヘッダー設定 |
|
headers = ["ID", "日付", "製品コード", "製品名", "カテゴリ", "単価", "数量", "割引率", "税率", "地域", "営業担当"] |
|
for col, header in enumerate(headers, 1): |
|
ws_sales.cell(row=1, column=col, value=header) |
|
ws_sales.cell(row=1, column=col).font = Font(bold=True) |
|
ws_sales.cell(row=1, column=col).fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid") |
|
ws_sales.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
# データ生成 |
|
products = [ |
|
("P001", "ノートPC Pro", "電子機器", 150000), |
|
("P002", "ワイヤレスマウス", "周辺機器", 3500), |
|
("P003", "USBメモリ 64GB", "ストレージ", 2800), |
|
("P004", "モニター 27inch", "電子機器", 45000), |
|
("P005", "キーボード メカニカル", "周辺機器", 12000), |
|
("P006", "外付けHDD 2TB", "ストレージ", 8900), |
|
("P007", "Webカメラ HD", "周辺機器", 5600), |
|
("P008", "タブレット 10inch", "電子機器", 68000) |
|
] |
|
|
|
regions = ["東京", "大阪", "名古屋", "福岡", "札幌"] |
|
sales_persons = ["田中", "佐藤", "鈴木", "高橋", "伊藤"] |
|
|
|
start_date = datetime(2024, 1, 1) |
|
for row in range(2, 202): # 200行のデータ |
|
ws_sales.cell(row=row, column=1, value=row-1) # ID |
|
ws_sales.cell(row=row, column=2, value=start_date + timedelta(days=random.randint(0, 364))) # 日付 |
|
|
|
product = random.choice(products) |
|
ws_sales.cell(row=row, column=3, value=product[0]) # 製品コード |
|
ws_sales.cell(row=row, column=4, value=product[1]) # 製品名 |
|
ws_sales.cell(row=row, column=5, value=product[2]) # カテゴリ |
|
ws_sales.cell(row=row, column=6, value=product[3]) # 単価 |
|
ws_sales.cell(row=row, column=7, value=random.randint(1, 20)) # 数量 |
|
ws_sales.cell(row=row, column=8, value=random.choice([0, 0.05, 0.1, 0.15, 0.2])) # 割引率 |
|
ws_sales.cell(row=row, column=9, value=0.1) # 税率 |
|
ws_sales.cell(row=row, column=10, value=random.choice(regions)) # 地域 |
|
ws_sales.cell(row=row, column=11, value=random.choice(sales_persons)) # 営業担当 |
|
|
|
# シート2: 計算シート (複雑な数式) |
|
ws_calc = wb.create_sheet("計算シート") |
|
|
|
# ヘッダー |
|
calc_headers = ["ID", "売上高", "割引額", "税抜金額", "消費税", "純売上", "粗利益", "粗利益率", "累積売上", "移動平均", "標準偏差", "Zスコア"] |
|
for col, header in enumerate(calc_headers, 1): |
|
ws_calc.cell(row=1, column=col, value=header) |
|
ws_calc.cell(row=1, column=col).font = Font(bold=True) |
|
ws_calc.cell(row=1, column=col).fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") |
|
ws_calc.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
# 複雑な数式の設定 |
|
for row in range(2, 202): |
|
# ID参照 |
|
ws_calc.cell(row=row, column=1, value=f"='売上データ'!A{row}") |
|
|
|
# 売上高 = 単価 × 数量 |
|
ws_calc.cell(row=row, column=2, value=f"='売上データ'!F{row}*'売上データ'!G{row}") |
|
|
|
# 割引額 = 売上高 × 割引率 |
|
ws_calc.cell(row=row, column=3, value=f"=B{row}*'売上データ'!H{row}") |
|
|
|
# 税抜金額 = 売上高 - 割引額 |
|
ws_calc.cell(row=row, column=4, value=f"=B{row}-C{row}") |
|
|
|
# 消費税 = 税抜金額 × 税率 |
|
ws_calc.cell(row=row, column=5, value=f"=D{row}*'売上データ'!I{row}") |
|
|
|
# 純売上 = 税抜金額 + 消費税 |
|
ws_calc.cell(row=row, column=6, value=f"=D{row}+E{row}") |
|
|
|
# 粗利益 (仮定: 原価率60%) |
|
ws_calc.cell(row=row, column=7, value=f"=D{row}*0.4") |
|
|
|
# 粗利益率 |
|
ws_calc.cell(row=row, column=8, value=f"=IF(D{row}=0,0,G{row}/D{row})") |
|
|
|
# 累積売上 |
|
if row == 2: |
|
ws_calc.cell(row=row, column=9, value=f"=F{row}") |
|
else: |
|
ws_calc.cell(row=row, column=9, value=f"=I{row-1}+F{row}") |
|
|
|
# 移動平均 (10期) |
|
if row >= 11: |
|
ws_calc.cell(row=row, column=10, value=f"=AVERAGE(F{row-9}:F{row})") |
|
else: |
|
ws_calc.cell(row=row, column=10, value=f"=AVERAGE(F2:F{row})") |
|
|
|
# 標準偏差 (全期間) |
|
ws_calc.cell(row=row, column=11, value=f"=STDEV(F$2:F{row})") |
|
|
|
# Zスコア |
|
ws_calc.cell(row=row, column=12, value=f"=IF(K{row}=0,0,(F{row}-AVERAGE(F$2:F$201))/K{row})") |
|
|
|
# シート3: 月次集計 |
|
ws_monthly = wb.create_sheet("月次集計") |
|
|
|
# ヘッダー |
|
monthly_headers = ["月", "売上件数", "総売上", "平均売上", "最大売上", "最小売上", "前月比", "前年同月比", "目標達成率"] |
|
for col, header in enumerate(monthly_headers, 1): |
|
ws_monthly.cell(row=1, column=col, value=header) |
|
ws_monthly.cell(row=1, column=col).font = Font(bold=True) |
|
ws_monthly.cell(row=1, column=col).fill = PatternFill(start_color="70AD47", end_color="70AD47", fill_type="solid") |
|
ws_monthly.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
# 月次データの設定 |
|
for month in range(1, 13): |
|
row = month + 1 |
|
ws_monthly.cell(row=row, column=1, value=f"2024/{month:02d}") |
|
|
|
# 売上件数 (COUNTIFS) |
|
ws_monthly.cell(row=row, column=2, value=f"=COUNTIFS('売上データ'!B:B,\">=\"&DATE(2024,{month},1),'売上データ'!B:B,\"<\"&DATE(2024,{month+1 if month < 12 else 1},1))") |
|
|
|
# 総売上 (SUMIFS) |
|
ws_monthly.cell(row=row, column=3, value=f"=SUMIFS('計算シート'!F:F,'売上データ'!B:B,\">=\"&DATE(2024,{month},1),'売上データ'!B:B,\"<\"&DATE(2024,{month+1 if month < 12 else 1},1))") |
|
|
|
# 平均売上 |
|
ws_monthly.cell(row=row, column=4, value=f"=IF(B{row}=0,0,C{row}/B{row})") |
|
|
|
# 最大売上 |
|
ws_monthly.cell(row=row, column=5, value=f"=MAXIFS('計算シート'!F:F,'売上データ'!B:B,\">=\"&DATE(2024,{month},1),'売上データ'!B:B,\"<\"&DATE(2024,{month+1 if month < 12 else 1},1))") |
|
|
|
# 最小売上 |
|
ws_monthly.cell(row=row, column=6, value=f"=MINIFS('計算シート'!F:F,'売上データ'!B:B,\">=\"&DATE(2024,{month},1),'売上データ'!B:B,\"<\"&DATE(2024,{month+1 if month < 12 else 1},1))") |
|
|
|
# 前月比 |
|
if row > 2: |
|
ws_monthly.cell(row=row, column=7, value=f"=IF(C{row-1}=0,0,(C{row}-C{row-1})/C{row-1})") |
|
else: |
|
ws_monthly.cell(row=row, column=7, value=0) |
|
|
|
# 前年同月比 (仮想) |
|
ws_monthly.cell(row=row, column=8, value=f"=RANDBETWEEN(90,120)/100-1") |
|
|
|
# 目標達成率 (目標を1000万と仮定) |
|
ws_monthly.cell(row=row, column=9, value=f"=C{row}/10000000") |
|
|
|
# シート4: 地域別分析 |
|
ws_region = wb.create_sheet("地域別分析") |
|
|
|
# ヘッダー |
|
region_headers = ["地域", "売上件数", "総売上", "市場シェア", "成長率", "利益率", "ROI", "顧客単価", "リピート率"] |
|
for col, header in enumerate(region_headers, 1): |
|
ws_region.cell(row=1, column=col, value=header) |
|
ws_region.cell(row=1, column=col).font = Font(bold=True) |
|
ws_region.cell(row=1, column=col).fill = PatternFill(start_color="FFC000", end_color="FFC000", fill_type="solid") |
|
|
|
# 地域データ |
|
for idx, region in enumerate(regions, 2): |
|
ws_region.cell(row=idx, column=1, value=region) |
|
|
|
# 売上件数 |
|
ws_region.cell(row=idx, column=2, value=f"=COUNTIF('売上データ'!J:J,A{idx})") |
|
|
|
# 総売上 |
|
ws_region.cell(row=idx, column=3, value=f"=SUMIF('売上データ'!J:J,A{idx},'計算シート'!F:F)") |
|
|
|
# 市場シェア |
|
ws_region.cell(row=idx, column=4, value=f"=C{idx}/SUM(C$2:C$6)") |
|
|
|
# 成長率 (ランダム) |
|
ws_region.cell(row=idx, column=5, value=f"=RANDBETWEEN(5,25)/100") |
|
|
|
# 利益率 |
|
ws_region.cell(row=idx, column=6, value=f"=SUMIF('売上データ'!J:J,A{idx},'計算シート'!G:G)/C{idx}") |
|
|
|
# ROI |
|
ws_region.cell(row=idx, column=7, value=f"=F{idx}*1.5") |
|
|
|
# 顧客単価 |
|
ws_region.cell(row=idx, column=8, value=f"=C{idx}/B{idx}") |
|
|
|
# リピート率 |
|
ws_region.cell(row=idx, column=9, value=f"=RANDBETWEEN(60,90)/100") |
|
|
|
# シート5: 製品カテゴリ分析 |
|
ws_category = wb.create_sheet("カテゴリ分析") |
|
|
|
# ヘッダー |
|
cat_headers = ["カテゴリ", "売上数量", "売上高", "平均単価", "在庫回転率", "ABC分類", "需要予測", "季節指数"] |
|
for col, header in enumerate(cat_headers, 1): |
|
ws_category.cell(row=1, column=col, value=header) |
|
ws_category.cell(row=1, column=col).font = Font(bold=True) |
|
ws_category.cell(row=1, column=col).fill = PatternFill(start_color="7030A0", end_color="7030A0", fill_type="solid") |
|
ws_category.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
categories = ["電子機器", "周辺機器", "ストレージ"] |
|
for idx, category in enumerate(categories, 2): |
|
ws_category.cell(row=idx, column=1, value=category) |
|
|
|
# 売上数量 |
|
ws_category.cell(row=idx, column=2, value=f"=SUMIF('売上データ'!E:E,A{idx},'売上データ'!G:G)") |
|
|
|
# 売上高 |
|
ws_category.cell(row=idx, column=3, value=f"=SUMIF('売上データ'!E:E,A{idx},'計算シート'!F:F)") |
|
|
|
# 平均単価 |
|
ws_category.cell(row=idx, column=4, value=f"=C{idx}/B{idx}") |
|
|
|
# 在庫回転率 |
|
ws_category.cell(row=idx, column=5, value=f"=12*B{idx}/(B{idx}*0.15)") |
|
|
|
# ABC分類 |
|
ws_category.cell(row=idx, column=6, value=f"=IF(C{idx}/SUM(C$2:C$4)>0.5,\"A\",IF(C{idx}/SUM(C$2:C$4)>0.2,\"B\",\"C\"))") |
|
|
|
# 需要予測 (移動平均ベース) |
|
ws_category.cell(row=idx, column=7, value=f"=C{idx}*1.1") |
|
|
|
# 季節指数 |
|
ws_category.cell(row=idx, column=8, value=f"=1+SIN(PI()*{idx}/6)*0.2") |
|
|
|
# シート6: ダッシュボード |
|
ws_dashboard = wb.create_sheet("ダッシュボード") |
|
|
|
# タイトル |
|
ws_dashboard.cell(row=1, column=1, value="営業ダッシュボード 2024") |
|
ws_dashboard.cell(row=1, column=1).font = Font(size=20, bold=True) |
|
ws_dashboard.merge_cells("A1:H1") |
|
|
|
# KPI サマリー |
|
kpi_row = 3 |
|
ws_dashboard.cell(row=kpi_row, column=1, value="KPI指標") |
|
ws_dashboard.cell(row=kpi_row, column=1).font = Font(bold=True, size=14) |
|
|
|
# 総売上 |
|
ws_dashboard.cell(row=kpi_row+1, column=1, value="総売上高:") |
|
ws_dashboard.cell(row=kpi_row+1, column=2, value="=SUM('計算シート'!F:F)") |
|
ws_dashboard.cell(row=kpi_row+1, column=2).number_format = "#,##0" |
|
|
|
# 平均売上 |
|
ws_dashboard.cell(row=kpi_row+2, column=1, value="平均売上高:") |
|
ws_dashboard.cell(row=kpi_row+2, column=2, value="=AVERAGE('計算シート'!F:F)") |
|
ws_dashboard.cell(row=kpi_row+2, column=2).number_format = "#,##0" |
|
|
|
# 売上成長率 |
|
ws_dashboard.cell(row=kpi_row+3, column=1, value="売上成長率:") |
|
ws_dashboard.cell(row=kpi_row+3, column=2, value="=('月次集計'!C13-'月次集計'!C2)/'月次集計'!C2") |
|
ws_dashboard.cell(row=kpi_row+3, column=2).number_format = "0.0%" |
|
|
|
# 最高業績地域 |
|
ws_dashboard.cell(row=kpi_row+4, column=1, value="最高業績地域:") |
|
ws_dashboard.cell(row=kpi_row+4, column=2, value="=INDEX('地域別分析'!A:A,MATCH(MAX('地域別分析'!C:C),'地域別分析'!C:C,0))") |
|
|
|
# 最も売れた製品 |
|
ws_dashboard.cell(row=kpi_row+5, column=1, value="ベストセラー:") |
|
ws_dashboard.cell(row=kpi_row+5, column=2, value="=INDEX('売上データ'!D:D,MODE('売上データ'!A:A)+1)") |
|
|
|
# 平均粗利益率 |
|
ws_dashboard.cell(row=kpi_row+6, column=1, value="平均粗利益率:") |
|
ws_dashboard.cell(row=kpi_row+6, column=2, value="=AVERAGE('計算シート'!H:H)") |
|
ws_dashboard.cell(row=kpi_row+6, column=2).number_format = "0.0%" |
|
|
|
# トレンド分析 |
|
trend_row = kpi_row + 8 |
|
ws_dashboard.cell(row=trend_row, column=1, value="トレンド分析") |
|
ws_dashboard.cell(row=trend_row, column=1).font = Font(bold=True, size=14) |
|
|
|
# 売上トレンド |
|
ws_dashboard.cell(row=trend_row+1, column=1, value="売上トレンド:") |
|
ws_dashboard.cell(row=trend_row+1, column=2, value="=IF(SLOPE('月次集計'!C2:C13,ROW('月次集計'!C2:C13))>0,\"上昇傾向\",\"下降傾向\")") |
|
|
|
# 季節性 |
|
ws_dashboard.cell(row=trend_row+2, column=1, value="季節性指数:") |
|
ws_dashboard.cell(row=trend_row+2, column=2, value="=STDEV('月次集計'!C2:C13)/AVERAGE('月次集計'!C2:C13)") |
|
ws_dashboard.cell(row=trend_row+2, column=2).number_format = "0.00" |
|
|
|
# 予測精度 |
|
ws_dashboard.cell(row=trend_row+3, column=1, value="予測精度:") |
|
ws_dashboard.cell(row=trend_row+3, column=2, value="=1-ABS(AVERAGE('月次集計'!I2:I13)-1)") |
|
ws_dashboard.cell(row=trend_row+3, column=2).number_format = "0.0%" |
|
|
|
# 高度な分析セクション |
|
analysis_row = trend_row + 5 |
|
ws_dashboard.cell(row=analysis_row, column=1, value="高度な分析") |
|
ws_dashboard.cell(row=analysis_row, column=1).font = Font(bold=True, size=14) |
|
|
|
# 相関分析 |
|
ws_dashboard.cell(row=analysis_row+1, column=1, value="価格-数量相関:") |
|
ws_dashboard.cell(row=analysis_row+1, column=2, value="=CORREL('売上データ'!F:F,'売上データ'!G:G)") |
|
ws_dashboard.cell(row=analysis_row+1, column=2).number_format = "0.000" |
|
|
|
# 分散分析 |
|
ws_dashboard.cell(row=analysis_row+2, column=1, value="売上分散:") |
|
ws_dashboard.cell(row=analysis_row+2, column=2, value="=VAR('計算シート'!F:F)") |
|
ws_dashboard.cell(row=analysis_row+2, column=2).number_format = "#,##0" |
|
|
|
# 四分位数 |
|
ws_dashboard.cell(row=analysis_row+3, column=1, value="第1四分位:") |
|
ws_dashboard.cell(row=analysis_row+3, column=2, value="=QUARTILE('計算シート'!F:F,1)") |
|
ws_dashboard.cell(row=analysis_row+3, column=2).number_format = "#,##0" |
|
|
|
ws_dashboard.cell(row=analysis_row+4, column=1, value="中央値:") |
|
ws_dashboard.cell(row=analysis_row+4, column=2, value="=MEDIAN('計算シート'!F:F)") |
|
ws_dashboard.cell(row=analysis_row+4, column=2).number_format = "#,##0" |
|
|
|
ws_dashboard.cell(row=analysis_row+5, column=1, value="第3四分位:") |
|
ws_dashboard.cell(row=analysis_row+5, column=2, value="=QUARTILE('計算シート'!F:F,3)") |
|
ws_dashboard.cell(row=analysis_row+5, column=2).number_format = "#,##0" |
|
|
|
# 条件付き書式の追加 |
|
# 売上データシートに条件付き書式 |
|
ws_sales.conditional_formatting.add("F2:F201", |
|
ColorScaleRule(start_type="percentile", start_value=10, start_color="FF6B6B", |
|
mid_type="percentile", mid_value=50, mid_color="FFD93D", |
|
end_type="percentile", end_value=90, end_color="6BCB77")) |
|
|
|
# 計算シートに条件付き書式 |
|
ws_calc.conditional_formatting.add("L2:L201", |
|
DataBarRule(start_type="min", end_type="max", |
|
color="4472C4", showValue=True, minLength=None, maxLength=None)) |
|
|
|
# 月次集計にアイコンセット |
|
ws_monthly.conditional_formatting.add("I2:I13", |
|
IconSetRule("3Arrows", "percent", [33, 67], showValue=True, reverse=False)) |
|
|
|
# シート7: 営業担当分析 |
|
ws_sales_person = wb.create_sheet("営業担当分析") |
|
|
|
# ヘッダー |
|
sp_headers = ["営業担当", "売上件数", "総売上", "目標達成率", "成約率", "顧客満足度", "生産性指数", "ボーナス係数"] |
|
for col, header in enumerate(sp_headers, 1): |
|
ws_sales_person.cell(row=1, column=col, value=header) |
|
ws_sales_person.cell(row=1, column=col).font = Font(bold=True) |
|
ws_sales_person.cell(row=1, column=col).fill = PatternFill(start_color="E74C3C", end_color="E74C3C", fill_type="solid") |
|
ws_sales_person.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
for idx, person in enumerate(sales_persons, 2): |
|
ws_sales_person.cell(row=idx, column=1, value=person) |
|
|
|
# 売上件数 |
|
ws_sales_person.cell(row=idx, column=2, value=f"=COUNTIF('売上データ'!K:K,A{idx})") |
|
|
|
# 総売上 |
|
ws_sales_person.cell(row=idx, column=3, value=f"=SUMIF('売上データ'!K:K,A{idx},'計算シート'!F:F)") |
|
|
|
# 目標達成率 (個人目標を2000万と仮定) |
|
ws_sales_person.cell(row=idx, column=4, value=f"=C{idx}/20000000") |
|
|
|
# 成約率 (ランダム) |
|
ws_sales_person.cell(row=idx, column=5, value=f"=RANDBETWEEN(15,35)/100") |
|
|
|
# 顧客満足度 (ランダム) |
|
ws_sales_person.cell(row=idx, column=6, value=f"=RANDBETWEEN(75,95)/100") |
|
|
|
# 生産性指数 |
|
ws_sales_person.cell(row=idx, column=7, value=f"=D{idx}*E{idx}*F{idx}") |
|
|
|
# ボーナス係数 |
|
ws_sales_person.cell(row=idx, column=8, value=f"=IF(D{idx}>1,1.5,IF(D{idx}>0.8,1.2,IF(D{idx}>0.6,1,0.8)))") |
|
|
|
# シート8: 財務分析 |
|
ws_finance = wb.create_sheet("財務分析") |
|
|
|
# ヘッダー |
|
fin_headers = ["項目", "Q1", "Q2", "Q3", "Q4", "年間合計", "前年比", "計画比", "達成率"] |
|
for col, header in enumerate(fin_headers, 1): |
|
ws_finance.cell(row=1, column=col, value=header) |
|
ws_finance.cell(row=1, column=col).font = Font(bold=True) |
|
ws_finance.cell(row=1, column=col).fill = PatternFill(start_color="2E7D32", end_color="2E7D32", fill_type="solid") |
|
ws_finance.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
# 財務項目 |
|
fin_items = ["売上高", "売上原価", "粗利益", "販管費", "営業利益", "経常利益", "純利益"] |
|
|
|
for idx, item in enumerate(fin_items, 2): |
|
ws_finance.cell(row=idx, column=1, value=item) |
|
|
|
if item == "売上高": |
|
# 四半期ごとの売上 |
|
ws_finance.cell(row=idx, column=2, value="=SUM('月次集計'!C2:C4)") # Q1 |
|
ws_finance.cell(row=idx, column=3, value="=SUM('月次集計'!C5:C7)") # Q2 |
|
ws_finance.cell(row=idx, column=4, value="=SUM('月次集計'!C8:C10)") # Q3 |
|
ws_finance.cell(row=idx, column=5, value="=SUM('月次集計'!C11:C13)") # Q4 |
|
elif item == "売上原価": |
|
ws_finance.cell(row=idx, column=2, value=f"=B{idx-1}*0.6") |
|
ws_finance.cell(row=idx, column=3, value=f"=C{idx-1}*0.6") |
|
ws_finance.cell(row=idx, column=4, value=f"=D{idx-1}*0.6") |
|
ws_finance.cell(row=idx, column=5, value=f"=E{idx-1}*0.6") |
|
elif item == "粗利益": |
|
ws_finance.cell(row=idx, column=2, value=f"=B{idx-2}-B{idx-1}") |
|
ws_finance.cell(row=idx, column=3, value=f"=C{idx-2}-C{idx-1}") |
|
ws_finance.cell(row=idx, column=4, value=f"=D{idx-2}-D{idx-1}") |
|
ws_finance.cell(row=idx, column=5, value=f"=E{idx-2}-E{idx-1}") |
|
elif item == "販管費": |
|
ws_finance.cell(row=idx, column=2, value=f"=B{idx-3}*0.25") |
|
ws_finance.cell(row=idx, column=3, value=f"=C{idx-3}*0.25") |
|
ws_finance.cell(row=idx, column=4, value=f"=D{idx-3}*0.25") |
|
ws_finance.cell(row=idx, column=5, value=f"=E{idx-3}*0.25") |
|
elif item == "営業利益": |
|
ws_finance.cell(row=idx, column=2, value=f"=B{idx-2}-B{idx-1}") |
|
ws_finance.cell(row=idx, column=3, value=f"=C{idx-2}-C{idx-1}") |
|
ws_finance.cell(row=idx, column=4, value=f"=D{idx-2}-D{idx-1}") |
|
ws_finance.cell(row=idx, column=5, value=f"=E{idx-2}-E{idx-1}") |
|
elif item == "経常利益": |
|
ws_finance.cell(row=idx, column=2, value=f"=B{idx-1}*0.95") |
|
ws_finance.cell(row=idx, column=3, value=f"=C{idx-1}*0.95") |
|
ws_finance.cell(row=idx, column=4, value=f"=D{idx-1}*0.95") |
|
ws_finance.cell(row=idx, column=5, value=f"=E{idx-1}*0.95") |
|
elif item == "純利益": |
|
ws_finance.cell(row=idx, column=2, value=f"=B{idx-1}*0.7") |
|
ws_finance.cell(row=idx, column=3, value=f"=C{idx-1}*0.7") |
|
ws_finance.cell(row=idx, column=4, value=f"=D{idx-1}*0.7") |
|
ws_finance.cell(row=idx, column=5, value=f"=E{idx-1}*0.7") |
|
|
|
# 年間合計 |
|
ws_finance.cell(row=idx, column=6, value=f"=SUM(B{idx}:E{idx})") |
|
|
|
# 前年比 (ランダム) |
|
ws_finance.cell(row=idx, column=7, value=f"=RANDBETWEEN(90,120)/100") |
|
|
|
# 計画比 (ランダム) |
|
ws_finance.cell(row=idx, column=8, value=f"=RANDBETWEEN(85,115)/100") |
|
|
|
# 達成率 |
|
ws_finance.cell(row=idx, column=9, value=f"=H{idx}") |
|
|
|
# シート9: 予測モデル |
|
ws_forecast = wb.create_sheet("予測モデル") |
|
|
|
# ヘッダー |
|
forecast_headers = ["月", "実績", "線形予測", "指数平滑", "季節調整", "ARIMA", "アンサンブル予測", "信頼区間下限", "信頼区間上限", "予測精度"] |
|
for col, header in enumerate(forecast_headers, 1): |
|
ws_forecast.cell(row=1, column=col, value=header) |
|
ws_forecast.cell(row=1, column=col).font = Font(bold=True) |
|
ws_forecast.cell(row=1, column=col).fill = PatternFill(start_color="9C27B0", end_color="9C27B0", fill_type="solid") |
|
ws_forecast.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
# 予測データ |
|
for month in range(1, 25): # 24ヶ月分 |
|
row = month + 1 |
|
ws_forecast.cell(row=row, column=1, value=f"2024/{(month-1)%12+1:02d}") |
|
|
|
if month <= 12: |
|
# 実績データ参照 |
|
ws_forecast.cell(row=row, column=2, value=f"='月次集計'!C{month+1}") |
|
else: |
|
# 予測期間 |
|
ws_forecast.cell(row=row, column=2, value="") |
|
|
|
# 線形予測 |
|
if month <= 12: |
|
ws_forecast.cell(row=row, column=3, value=f"=FORECAST({month},'月次集計'!$C$2:$C$13,ROW('月次集計'!$C$2:$C$13))") |
|
else: |
|
ws_forecast.cell(row=row, column=3, value=f"=FORECAST({month},'月次集計'!$C$2:$C$13,ROW('月次集計'!$C$2:$C$13))*1.05") |
|
|
|
# 指数平滑 (簡易版) |
|
if row == 2: |
|
ws_forecast.cell(row=row, column=4, value=f"=B{row}") |
|
elif month <= 12: |
|
ws_forecast.cell(row=row, column=4, value=f"=0.3*B{row}+0.7*D{row-1}") |
|
else: |
|
ws_forecast.cell(row=row, column=4, value=f"=D{row-1}*1.02") |
|
|
|
# 季節調整 |
|
ws_forecast.cell(row=row, column=5, value=f"=C{row}*(1+SIN(2*PI()*{(month-1)%12}/12)*0.15)") |
|
|
|
# ARIMA (簡易版) |
|
if row <= 3: |
|
ws_forecast.cell(row=row, column=6, value=f"=C{row}") |
|
else: |
|
ws_forecast.cell(row=row, column=6, value=f"=0.5*C{row}+0.3*C{row-1}+0.2*C{row-2}") |
|
|
|
# アンサンブル予測 |
|
ws_forecast.cell(row=row, column=7, value=f"=(C{row}+D{row}+E{row}+F{row})/4") |
|
|
|
# 信頼区間 |
|
ws_forecast.cell(row=row, column=8, value=f"=G{row}*0.9") |
|
ws_forecast.cell(row=row, column=9, value=f"=G{row}*1.1") |
|
|
|
# 予測精度 |
|
if month <= 12 and row > 2: |
|
ws_forecast.cell(row=row, column=10, value=f"=1-ABS((B{row}-G{row})/B{row})") |
|
else: |
|
ws_forecast.cell(row=row, column=10, value="") |
|
|
|
# シート10: リスク分析 |
|
ws_risk = wb.create_sheet("リスク分析") |
|
|
|
# ヘッダー |
|
risk_headers = ["リスク項目", "発生確率", "影響度", "リスク値", "対策コスト", "期待損失", "ROI", "優先順位"] |
|
for col, header in enumerate(risk_headers, 1): |
|
ws_risk.cell(row=1, column=col, value=header) |
|
ws_risk.cell(row=1, column=col).font = Font(bold=True) |
|
ws_risk.cell(row=1, column=col).fill = PatternFill(start_color="D32F2F", end_color="D32F2F", fill_type="solid") |
|
ws_risk.cell(row=1, column=col).font = Font(color="FFFFFF", bold=True) |
|
|
|
risks = [ |
|
"市場競争激化", |
|
"供給チェーン混乱", |
|
"為替変動", |
|
"技術的陳腐化", |
|
"規制変更", |
|
"サイバーセキュリティ", |
|
"人材流出" |
|
] |
|
|
|
for idx, risk in enumerate(risks, 2): |
|
ws_risk.cell(row=idx, column=1, value=risk) |
|
|
|
# 発生確率 |
|
ws_risk.cell(row=idx, column=2, value=f"=RANDBETWEEN(10,80)/100") |
|
|
|
# 影響度 (1-10スケール) |
|
ws_risk.cell(row=idx, column=3, value=f"=RANDBETWEEN(3,10)") |
|
|
|
# リスク値 |
|
ws_risk.cell(row=idx, column=4, value=f"=B{idx}*C{idx}") |
|
|
|
# 対策コスト |
|
ws_risk.cell(row=idx, column=5, value=f"=RANDBETWEEN(100000,1000000)") |
|
|
|
# 期待損失 |
|
ws_risk.cell(row=idx, column=6, value=f"=B{idx}*C{idx}*1000000") |
|
|
|
# ROI |
|
ws_risk.cell(row=idx, column=7, value=f"=(F{idx}-E{idx})/E{idx}") |
|
|
|
# 優先順位 |
|
ws_risk.cell(row=idx, column=8, value=f"=RANK(D{idx},D$2:D$8,0)") |
|
|
|
# 列幅の自動調整 |
|
for sheet in wb.worksheets: |
|
for column_cells in sheet.columns: |
|
try: |
|
length = max(len(str(cell.value or "")) for cell in column_cells if cell.value is not None) |
|
if hasattr(column_cells[0], 'column_letter'): |
|
sheet.column_dimensions[column_cells[0].column_letter].width = min(length + 2, 30) |
|
except (ValueError, AttributeError): |
|
continue |
|
|
|
# ファイルを保存 |
|
filename = "complex_excel_workbook.xlsx" |
|
wb.save(filename) |
|
print(f"複雑なExcelワークブック '{filename}' を作成しました。") |
|
print(f"作成されたシート数: {len(wb.worksheets)}") |
|
print(f"シート名: {', '.join([ws.title for ws in wb.worksheets])}") |
|
|
|
return filename |
|
|
|
if __name__ == "__main__": |
|
create_complex_workbook() |