⬛
春闘における一時金の支給状況PDFの加工
連合は春季に賃金交渉の結果を公表している。
しかし公表形式はPDFとなっており、時系列での評価をするためには手間がかかる。
このため、今回は特に一時金の支給状況に限定して、pdfの表をpythonを用いて加工する。
なお、今回の作業は環境構築を含め、githubにあるリポジトリから再現可能。
まず、今回の階層構造は以下の通り。
.
├── code
│ ├── pdf_list.json
│ └── test.ipynb
└── data
pdf_list.jsonは以下のように、pdfのリンクとなっている。なお、冬季の2023年は本稿執筆時点でまだ第一回しか公表されていないため、過去についても第一回を用いている。
{
"summer":{
"y2017" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2017/yokyu_kaito/kaito_no7_ichiji_20170705.pdf?2718",
"y2018" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2018/yokyu_kaito/kaito/no7/kaito_no7_ichiji.pdf?6213",
"y2019" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2019/yokyu_kaito/kaito/no6/kaito_no6_ichiji.pdf?5180",
"y2020" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2020/yokyu_kaito/kaito/no7/kaito_no7_ichiji.pdf?9029",
"y2021" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2021/yokyu_kaito/kaito/kaito_no7_ichiji.pdf?890",
"y2022" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2022/yokyu_kaito/kaito/kaito_no7_ichiji.pdf?9996",
"y2023" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2023/yokyu_kaito/kaito/kaito_no7_ichiji.pdf?6229"
},
"winter":{
"y2017" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2017/yokyu_kaito/nenmatsu_ichiji_01.pdf?1851",
"y2018" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2018/yokyu_kaito/kaito/nenmatsu/ichiji_01.pdf?3961",
"y2019" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2019/yokyu_kaito/kaito/nenmatsu/ichiji_01.pdf?7778",
"y2020" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2020/yokyu_kaito/kaito/nenmatsu/ichiji_01.pdf?1209",
"y2021" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2021/yokyu_kaito/kaito/nenmatsu/ichiji_01.pdf?1586",
"y2022" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2022/yokyu_kaito/kaito/nenmatsu/ichiji_01.pdf?6298",
"y2023" : "https://www.jtuc-rengo.or.jp/activity/roudou/shuntou/2023/yokyu_kaito/kaito/nenmatsu/ichiji_01.pdf?6229"
}
}
まずはパッケージを読み込む。tabulaの使用にはJAVAがインストールされていることが必要なので注意。
import tabula
import pandas as pd
import json
f = json.load(open('pdf_list.json', 'r'))
jsonファイル中、'summer'のリンク先のデータを処理する。
colnames = ['属性', '組合数', '組合人員数', '加重平均‗要求', '加重平均‗回答', '加重平均‗前年実績', '単純平均‗要求', '単純平均‗回答', '単純平均‗前年実績']
# for文で得られたdfをすべて縦に結合する為の空のdfを作成する
master_df = pd.DataFrame()
for i in f['summer']:
pdfpath = f['summer'][i]
dfs = tabula.read_pdf(pdfpath,
pages="all",
lattice=True
)
# dfsの中身をすべて縦に結合する
df = pd.concat(dfs, axis=0)
# 業種別がNaNである時、構成組織の値をとる
df['業種別'] = df['業種別'].fillna(df['構成組織'])
# 業種別がNaNである行を削除する
df = df.dropna(subset=['業種別'])
# 構成組織の列を削除する
df = df.drop(columns=['構成組織'])
# index列を削除してから、先頭にyear列を挿入する
df = df.reset_index(drop=True)
# 列名をcolnamesに変更する
df.columns = colnames
df.insert(0, '集計年', i[1:])
# 加重平均‗要求列を、','を削除してからfloat型に変換する
df['加重平均‗要求'] = df['加重平均‗要求'].str.replace(',', '').astype(float)
# '集計年'列の一つ後ろに、加重平均‗要求列の値が100以下であれば'月数'を、そうでなければ'金額'をとる列を挿入する
df.insert(2, '集計カテゴリ', df.apply(lambda x: '月数' if x['加重平均‗要求'] <= 100 else '金額', axis=1))
# '属性'と'集計カテゴリ'の両方からなるグループを作って、それぞれのグループごとにソートする。その後、グループの中でindexの小さい順に数字を1から順番に振る。
df = df.sort_values(['属性', '集計カテゴリ']).reset_index(drop=True)
df.insert(0, 'id', df.groupby(['属性', '集計カテゴリ']).cumcount() + 1)
# 'id'が1の時は'年間',2の時は'夏季'という文字列を'集計カテゴリ'の後ろに追加する
df['集計カテゴリ'] = df.apply(lambda x: x['集計カテゴリ'] + '(年間)' if x['id'] == 1 else x['集計カテゴリ'] + '(夏季)', axis=1)
df = df.drop(columns=['id'])
# dfをdf‗masterに追加していく
master_df = pd.concat([master_df, df], axis=0)
master_df.to_csv('../data/summer_bonus.csv', index=False, encoding='utf-8-sig')
同様に、'winter'のリンク先のデータを処理する。
colnames = ['属性', '組合数', '組合人員数', '加重平均‗回答', '加重平均‗前年実績','単純平均‗回答', '単純平均‗前年実績']
# for文で得られたdfをすべて縦に結合する為の空のdfを作成する
master_df = pd.DataFrame()
for i in f['winter']:
pdfpath = f['winter'][i]
dfs = tabula.read_pdf(pdfpath,
pages="all",
lattice=True
)
# dfsの中身をすべて縦に結合する
df = pd.concat(dfs, axis=0)
# 業種別がNaNである時、構成組織の値をとる
df['業種別'] = df['業種別'].fillna(df['構成組織'])
# 業種別がNaNである行を削除する
df = df.dropna(subset=['業種別'])
# 構成組織の列を削除する
df = df.drop(columns=['構成組織'])
# もし変数の数が9個であれば,前の2つの変数を補完してからdfの後ろ2列を削除する
if len(df.columns) == 9:
df[df.columns[1]] = df[df.columns[1]].fillna(df[df.columns[-2]])
df[df.columns[2]] = df[df.columns[2]].fillna(df[df.columns[-1]])
df = df.drop(columns=[df.columns[-1], df.columns[-2]])
# index列を削除してから、先頭にyear列を挿入する
df = df.reset_index(drop=True)
# 列名をcolnamesに変更する
df.columns = colnames
df.insert(0, '集計年', i[1:])
# 加重平均‗回答列を、','を削除してからfloat型に変換する
df['加重平均‗回答'] = df['加重平均‗回答'].str.replace(',', '').astype(float)
# '集計年'列の一つ後ろに、加重平均‗要求列の値が100以下であれば'月数'を、そうでなければ'金額'をとる列を挿入する
df.insert(2, '集計カテゴリ', df.apply(lambda x: '月数(冬季)' if x['加重平均‗回答'] <= 100 else '金額(冬季)', axis=1))
# dfをdf‗masterに追加していく
master_df = pd.concat([master_df, df], axis=0)
master_df.to_csv('../data/winter_bonus.csv', index=False, encoding='utf-8_sig')
Discussion