全体まとめページは↓より。
やりたいこと
複数のカテゴリ変数を集計して、主カテゴリ別における副カテゴリの合計値を新しい列に転記する。
今回は「行き先」別の「目的」の数を集計したい。
単一カテゴリの集計は↓より。
フォルダ構成
VSCodeで実行するときはprg配下を開いてpyファイルを作り実行する。
実装
★部分が今回のポイント。
単一カテゴリ集計の処理を基本に、副カテゴリを集計関数の引数として追加している。メイン処理のソートは主カテゴリと副カテゴリの順に行い、辞書リストとして集計関数に渡す。
集計は基本的に副カテゴリで行い、「主カテゴリが変わっても副カテゴリが変わらなかった場合の集計漏れ」が起きないように集計をいったん区切る処理を加えている。
import os
import openpyxl
from operator import itemgetter
#辞書リストの作成関数
def make_shipment(sh):
shipment_list = []
for row in sh.iter_rows():
if row[0].row == 1:
header_cells = row
else:
row_dic = {}
for v, k in zip(header_cells, row):
row_dic[v.value] = k.value
shipment_list.append(row_dic)
return shipment_list
#★集計関数(複数系列)
#キーが同じなら集計値を加算していき、キーが異なったら
#集計値を確定して集計列に転記する
#引数
#1.shipment_list: 辞書リスト
#2.category: 集計するカテゴリ変数名
#3.category_sub:集計するカテゴリ変数名(サブ)
#戻り値
#1.sum_list: 合計値を格納するリスト(合計ではない行には0を格納)
def sum_mulcategory(sorted_list,category, category_sub):
old_key_sub = ""
old_key = ""
sum_key = 0
sum_list = [0]
sum_list_no = 0 #合計値リスト用のカウンタ
#処理中行は新しいキーなので、1行前に合計値を格納できるよう0スタートにする
for dic in sorted_list:
if old_key_sub == "":
old_key_sub = dic[category_sub] #最初のold_keyを格納する
if old_key == "":
old_key = dic[category]
if old_key_sub != dic[category_sub]:
old_key_sub = dic[category_sub]
old_key = dic[category]
sum_list[sum_list_no] = sum_key #1行目を合計値で更新する
sum_key = 1 #集計値を初期化する。処理行ですでに1つあるので初期値は1。
#メインカテゴリが違うがサブカテゴリが同じ並びになっていた場合、サブカテゴリの
#集計漏れを防ぐためにいったん集計を区切る
elif old_key != dic[category] and old_key_sub == dic[category_sub]:
old_key = dic[category]
sum_list[sum_list_no] = sum_key
sum_key = 1
elif old_key != dic[category]:
old_key = dic[category]
else:
sum_key += 1
sum_list.append(0)
sum_list_no += 1
#最終行処理
if sum_list_no == len(sorted_list):
sum_list[sum_list_no] = sum_key
return sum_list
#項目リスト
collist = ["index","行き先","目的"]
#ファイル名を入力させる
print("ファイル名を入力:")
filename = input()
#読み込みファイルパスを作成
infile_path = os.path.join("..\indata" , filename)
#読み込みファイルからオブジェクトを生成
iwb = openpyxl.load_workbook(infile_path)
ish = iwb.active
#出力ファイルオブジェクトを生成
owb = openpyxl.Workbook()
osh = owb.active
#出力ファイルパスを作成
outfile_path = os.path.join("..\outdata", filename)
#辞書リストを作成
shipment_list = make_shipment(ish)
#★集計したい列でソートする
#行き先別に目的の数を集計したいので、1.行き先、2.目的でソートする
sorted_list = sorted(shipment_list,key=itemgetter("行き先","目的"))
#集計処理
sum_category_list = sum_mulcategory(sorted_list,"行き先","目的")
#転記先ヘッダ処理
for col in range(len(collist)):
osh.cell(1,col+1).value = collist[col]
#転記処理
list_row = 1
for dic in sorted_list:
list_row += 1
for col in range(len(collist)):
colname = collist[col]
osh.cell(list_row,col+1).value = dic[colname]
col += 1
#集計列のヘッダ処理
osh.cell(1,len(collist)+1).value = "目的合計(行き先別)"
#集計列転記処理
for row in range(1,len(sum_category_list)):
osh.cell(row+1,col+1).value = sum_category_list[row]
#出力ファイルを保存
owb.save(outfile_path)
出力結果
集計値列が追加され、それぞれの副カテゴリの最後の行に集計値が転記されている。
集計行以外はゼロを埋めている。
以上