表形式のデータをPandasのDataFrameでいい感じに扱うメモ
表形式のデータを扱っている時に、「列Aのデータと別Bのデータに◯◯処理した値を使ってグラフ作りたい」
みたいなシチュエーションが、稀によくあります。そういう時、Pandas
のDataFrame
を使うと表形式の
データを柔軟に扱えて何かと便利です。
この記事では、DataFrame
を使った列同士の演算処理など、毎回「どうやるんだっけ?💦」ってなりがちな内容を
メモして、必要な時にすぐ参照できるようにしたいと思います。
📄 サンプルデータを準備
何かサンプルデータがあった方が処理内容を理解しやすそうなので、気象庁のHPから気象データをダウンロードして
使おうと思います。CSV
形式でダウンロードします。
今回の例では「項目を選ぶ」のページで、以下の項目を選択しました。
- 気温 - 日平均気温
- 湿度 - 日平均相対湿度
地域は「大阪府 - 大阪市」と「静岡県 - 静岡市」を、それぞれ別々のCSVとしてダウンロードしました。
📖 データを読み込んでDataFrameを作成
データの前処理
では読み込んで行きましょう・・と言いたいところですが、ダウンロードしたCSV
ファイルは純粋な表形式ではなく、
そのままでは意図したように処理できません。
下図のように「メタ情報が冒頭に書かれている」「列ヘッダが複数行に分かれて記述されている」といった問題があります。
不要な行を削除しつつ、「品質情報」や「均質情報」の列は今回の例では使わないので削除して整えます。
その際、VSCode
ならEdit CSVを使うとExcel
やNumbers
ライクな表形式画面で視覚的に行と列の操作ができて安心です。
pandasで読み込み
文字コードがShift-JIS
なCSVファイルなので、encoding
パラメータも指定しながら読み込みます。
import pandas as pd
osaka_df = pd.read_csv('osaka.csv', encoding='shift_jis')
osaka_df.head()
📊 データの活用
特定列の値を処理して別の新しい列を作る
温度列の値は単位が摂氏
のデータなので、これに演算処理を施して華氏
の温度列を作ります。なお、round関数を使って少数点以下が一桁の数値にしています。
華氏
= (摂氏
x9÷5) + 32
osaka_df['平均気温(°F)'] = round( (osaka_df['平均気温(℃)']*9/5) + 32, 1)
複数列の値を使って別の新しい列を作る
温度
列と湿度
列の値を使って不快指数
列を作りたいと思います。計算式は wiki 参照。
osaka_df['不快指数'] = round( (0.81*osaka_df['平均気温(℃)'] + 0.01*osaka_df['平均湿度(%)'] * ( 0.99*osaka_df['平均気温(℃)'] - 14.3) ) + 46.3, 1)
複数の表をマージする
「大阪府-大阪市」のデータと「静岡県-静岡市」の表データを結合して一つのデータにします。(この後のピボットテーブルの例のための伏線です。)
from datetime import datetime
# 「静岡県-静岡市」のデータにも、ここまでの例と同様の処理を行う。
shizuoka_df = pd.read_csv('shizuoka.csv', encoding='shift_jis')
shizuoka_df.insert(1, '地域', '静岡県-静岡市')
shizuoka_df['平均気温(°F)'] = round( (shizuoka_df['平均気温(℃)'] * 9 / 5) + 32, 1)
shizuoka_df['不快指数'] = round( (0.81*shizuoka_df['平均気温(℃)'] + 0.01*shizuoka_df['平均湿度(%)'] * ( 0.99*shizuoka_df['平均気温(℃)'] - 14.3) ) + 46.3, 1)
cat_df = pd.concat( [osaka_df, shizuoka_df])
# Seriesの各値に複雑な処理をしたい場合は、map関数を使うとうまくいく。
cat_df['年月日'] = cat_df['年月日'].map(lambda x: datetime.strptime(x, "%Y/%m/%d"))
ピボットテーブルを使って特定の値に着目した表にする
「不快指数」に着目して、地域と年月日で整理した表を作ります。
pd.pivot_table(cat_df, values="不快指数", index=["年月日"], columns=["地域"])
下図のような表が得られる。
seabornを使ってグラフにする
不快指数の推移を地域ごとにグラフ化してみます。きれいにしたいので seaborn を使います。
import seaborn as sns
from matplotlib import rcParams
import matplotlib.dates as mdates
sns.set_theme(style="whitegrid")
# 凡例などの日本語が表示されるように、日本語フォントを指定しましょう。
rcParams['font.family'] = 'HackGen35Nerd'
ax = sns.lineplot(
data=cat_df,
x="年月日", y="不快指数", hue="地域"
)
ax.set_title("2025年夏の大阪市と静岡市における不快指数の推移")
ax.xaxis.label.set_text('日付')
# 日付情報は適当に間引かないと潰れて見えなくなるので、X軸のメモリ表示を調整する。
locator = mdates.AutoDateLocator(minticks=5, maxticks=7)
ax.xaxis.set_major_locator(mdates.DayLocator(bymonthday=None, interval=7, tz=None))
# 2025年のデータであることをタイトルなどで示して「◯月□日」という日付にする。
# ゼロ埋めじゃない数字にするため書式をいじってる。Windowsではハイフンをシャープにするといいらしい。
formatter = mdates.DateFormatter("%-m月%-d日")
ax.xaxis.set_major_formatter(formatter)
sns.move_legend(ax, "upper left", bbox_to_anchor=(1, 1))
なお、グラフを日本語化する方法として「japanize-matplotlibをインポートしよう」という記事が多いのですが、私の環境ではうまく動作せず、試行錯誤の末に「seabornのテーマ適用後に日本語対応フォントを指定する」という方法を採用しました。ここでは、超お気に入りで数年使い続けているHackGenフォントのNerd版を指定しました👍️
このグラフではX軸にdatetime
型のデータを指定したのですが、適度に間引かないと文字が重なった読めなくなってしまってました。そこで、Locator
の仕組みを使って「7日間ごとにX軸の目盛りの数値を描画する」というように調整しています。また、Formatter
の仕組みで「◯月□日」というフォーマットに変更しています。このあたりの仕組みは、以下の記事を参考にしました。
- Matplotlib 時系列データの軸設定|自由に時間軸を設定!
- matplotlib.datesで時系列データのグラフの軸目盛の設定をする
- 【Python】datetimeの日時を0埋めせずに文字列整形する
出力結果のグラフは下図のようになります。
🎁 おまけ
この記事で実践した内容を記したJupiter Notebook
をGistに貼り付けましたので、手元で確認するなど活用ください。