便利ライブラリ Pandas③ mergeとconcat
Pandasについての第3回目です。
Pythonの基本⑤ ライブラリで扱ったcsvファイルを使用してデータ処理を行っていきます。csvをダウンロードし、ご自身のGoogleドライブ上に保存してから進んでください。
以下のコードで全体のデータを格納したdfと東北のデータを抜粋し列名を変更し、さらに2021年8月1日~2021年8月7日分を抽出したdf_tohokuを準備して先に進んでください。
import pandas as pd
from google.colab import drive
drive.mount('/content/drive')
file_path = "******************" # ←マウントしたGoogleドライブ上のファイルパスをコピーしペーストしてください
# ファイルの読み込み
df = pd.read_csv(file_path)
# データフレームの整形
df['Date'] = pd.to_datetime(df['Date'])
df_tohoku = df[['Date', 'ALL', 'Aomori', 'Iwate', 'Miyagi', 'Akita', 'Yamagata', 'Fukushima']]
df_tohoku.rename(columns={'Date': '年月日',
'ALL': '全国',
'Aomori': '青森',
'Iwate': '岩手',
'Miyagi': '宮城',
'Akita': '秋田',
'Yamagata': '山形',
'Fukushima': '福島'},
inplace=True
)
# 期間の絞り込み
df_tohoku = df_tohoku.query('"2021-08-01" <= 年月日 <= "2021-08-07"')
表を横に結合 merge
結合用の別のデータフレームを準備します。
練習を兼ねて以下の条件で、dfからdf_kitakantoを作成しましょう。
・Date、ALL、北関東の3県(Ibaraki、Tochigi、Gunma)を入れる
・列名を日本語に変換
・2021年8月4日~2021年8月10日を抽出
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
基本の使い方
df_kitakanto = df[['Date', 'ALL', 'Ibaraki', 'Tochigi', 'Gunma']]
df_kitakanto.rename(columns={'Date': '年月日',
'ALL': '全国',
'Ibaraki': '茨城',
'Tochigi': '栃木',
'Gunma': '群馬'},
inplace=True)
df_kitakanto = df_kitakanto.query('"2021-08-04" <= 年月日 <= "2021-08-10"')
サンプルコードの必要な箇所の項目を機械的に入れ替えれば、簡単に目的のデータフレームが作成できます。
ここからが本題で、df_tohokuとdf_kitakantoの2つの表を結合したいと思います。pd.merge()を使用し、引数にデータフレームを渡せば簡単に結合できます。
pd.merge(df_tohoku, df_kitakanto)
デフォルトでは(引数で特別な指示をしなければ)2つの表に共通する列名が複数存在する場合は、すべての列が結合キーとして処理されます。今回の場合、「年月日」、「全国」がキーとなっています。
結合する列名を指定 引数on
結合する列名を明示的に指定する場合は、onという引数を追加します。
pd.merge(df_tohoku, df_kitakanto,
on='年月日'
)
今回はonで「年月日」だけをキーとしているので、df_tohokuの「全国」とdf_kitakantoの「全国」は異なる列として扱われ、「全国_x」「全国_y」として残ります。
列名が異なる場合でもキーとなる列を指定することが出来ます。仮に、df_kitakantoの「年月日」の列名が「Date」のままだった場合、
pd.merge(df_tohoku, df_kitakanto,
left_on='年月日', right_on='Date',
)
のように、左右でそれぞれの列名を指定することも出来ます。
結合結果をどのように表示するか? 引数how
pd.merge(df_tohoku, df_kitakanto)で結合した場合、年月日・全国をキーに結合し、どちらの表にも共通して存在する2021年8月4日~2021年8月7日のデータが表示されました。このようにデフォルトでは、共通する行のみを表示されます。この設定は、howという引数で変更できます。
inner:両者に共通する行を表示(デフォルト)
outer:全ての行を表示(結合されてない行も表示される)
left:左側のdfの行はすべて表示(右側は共通する行のみ)
right:右側のdfの行はすべて表示(左側は共通する行のみ)
pd.merge(df_tohoku, df_kitakanto,
how='outer'
)
howに'outer'を指定すると、2021年8月1日~2021年8月10日までの全期間が表示され、結合した結果データが入ってないセルには「NaN」が表示されます。
表を縦に結合 concat
基本の使い方
次は、表を縦に結合する方法です。
以下のサンプルデータ(df_tohoku2)を追加します。df_tohokuの抽出期間が異なるデータを作成していますが、意図的に列名ALLは変更されないようにコメントアウトしています。
df_tohoku2 = df[['Date', 'ALL', 'Aomori', 'Iwate', 'Miyagi', 'Akita', 'Yamagata', 'Fukushima']]
df_tohoku2.rename(columns={'Date': '年月日',
#'ALL': '全国',
'Aomori': '青森',
'Iwate': '岩手',
'Miyagi': '宮城',
'Akita': '秋田',
'Yamagata': '山形',
'Fukushima': '福島'},
inplace=True
)
df_tohoku2 = df_tohoku2.query('"2022-08" <= 年月日 <= "2022-08-07"')
縦に繋げたいときは、pd.concat()を使用します。mergeと異なり、結合したいdfをリストとして渡します。
pd.concat([df_tohoku, df_tohoku2])
共通する列は縦に結合しています。全国とALLは列名が異なるので、別の列として残ります。
別の使い方
concatには結合する方向を指定することが出来ます。デフォルトは縦方向となっており、axis=0が省略されています。
axis=1とすると横方向に結合できます。…が、mergeの方が意図する結合になるので、あまり使ったことはありません。
pd.concat([df_tohoku, df_kitakanto], axis=1)
実務での活用例
実務では化療調製データなど同じ形式(列名)のデータが1日ごとExcelデータが出力され、月報を作成する際にすべてのデータを結合しなければいけないケースがあります。プログラミングを始める前は、手作業で一つ一つファイルを開いてコピー&ペーストしていましたが、Pythonを活用することで無駄作業から解放されます!
以下のコードでサンプルデータを作成します。2022年1月から4月の東海地方のデータを月別でExcelファイルして保存します。file_pathには、Googleドライブ上でExcelファイルを保存したい場所(フォルダ)を指定します。以下の例では、Googleドライブ上の任意のフォルダの中に「sample」というフォルダを準備したので、その中にExcelを保存するコードです。実行して、Excelファイルが4つ作成されていることを確認してください(作成は一瞬で終わりますが、表示までのタイムラグがあるのでブラウザの再読み込みをしてみてください)。
df_tokai = df[['Date', 'Aichi', 'Gifu', 'Mie']]
# データフレーム作成
df_tokai202201 = df_tokai.query("'2022-01' <= Date < '2022-02'")
df_tokai202202 = df_tokai.query("'2022-02' <= Date < '2022-03'")
df_tokai202203 = df_tokai.query("'2022-03' <= Date < '2022-04'")
df_tokai202204 = df_tokai.query("'2022-04' <= Date < '2022-05'")
# Excelファイルとして保存
file_path = '/content/drive/MyDrive/※※※※※※/sample/'
df_tokai202201.to_excel(file_path + 'tokai202201.xlsx', index=False)
df_tokai202202.to_excel(file_path + 'tokai202202.xlsx', index=False)
df_tokai202203.to_excel(file_path + 'tokai202203.xlsx', index=False)
df_tokai202204.to_excel(file_path + 'tokai202204.xlsx', index=False)
これで、とあるフォルダに結合したいExcelファイルが複数存在するという状態を作ることが出来ました。
それでは、globというライブラリを使用してsampleフォルダ内に含まれるExcelファイル(.xlsx)をリストとして取得します。ここで"*"はワイルドカードと呼ばれる文字で任意の文字列を示すので、sampleファルダ内にある.xlsxという拡張子をもつファイルが取得できます。
import glob
files = glob.glob(file_path + '*.xlsx')
files
実行すると、
['/content/drive/MyDrive/※※※※※/sample/tokai202201.xlsx', '/content/drive/MyDrive/※※※※※/sample/tokai202202.xlsx', '/content/drive/MyDrive/※※※※※/sample/tokai202203.xlsx', '/content/drive/MyDrive/※※※※※/sample/tokai202204.xlsx']
というように先ほど作成した4つのExcelファイルのパス(=ファイルまでのアドレス)をリスト形式で取得できています。
files[0]というように角カッコに要素番号を指定すれば、リスト内の各要素を取り出すことが出来るので、for文を組み合わせて連続的にファイルを縦に結合していきます。
df = pd.read_excel(files[0])
for i in range(1, len(files)):
df2 = pd.read_excel(files[i])
df = pd.concat([df, df2])
df.to_excel(file_path + f'tokai2022年1月~{len(files)}月.xlsx', index=False)
実行すると、sampleフォルダに「tokai2022年1月~4月.xlsx」というファイルが作成されます。中身を確認すると、4か月分のデータが結合されていることが分かります。
dfに最初のデータ(files[0])を代入し、df2に2番目以降のデータを順番に代入しconcatで結合し、dfを上書きしていくコードになっています。df2を作成するのをfor文でループ処理しています。2番目以降のファイルを指定するため、range()の第一引数は「1」をいれます(省略すると、「0」から始まるので1月データが重複してしまいます)。
ちなみに、フォルダ内のファイル数=処理した月の数(今回は4ファイル)なので、最終的なファイル名も自動で「4月」と入ります。
この方法ならファイルがいくつあっても一瞬で作業が終わります!
最近は、ExcelでもPower Queryを用いると上記のような作業もno codeで出来てしまいますが、自動的に出来すぎてちゃんと意図したように結合できているか心配になります(あくまで個人の感想です)。
コードを書く必要はありますが、どれとどれを結合して・・・というようにミスを起こしにくくする(気づきやすくする)には、過程があとから分かるというのも大事なことです。
この記事が気に入ったらサポートをしてみませんか?