Excelなどの表データをゴリゴリ加工する【Python x Pandas】

Pythonでデータ解析・Pandasの使い方
Pythonでデータ解析・Pandasの使い方

この記事では、Pythonを使ってデータ解析を簡単に行うことができるpandasの使い方を解説していきます。

Pandasとは、表データをPythonで簡単に扱えるようにするライブラリです。表データをDataFrameというオブジェクトへ変換し、並べ替えたり、特定の行や列を取り出したり、追加削除などの加工を簡単にプログラミングできます。 pandas - Python Data Analysis Library

本記事では、Pandasで読み込んだExcelデータから必要な情報だけ抽出し、並べ替えたり、グラフ表示させたりしていきます。いわゆるスクレイピングと呼ばれる作業のひとつになります。

はじめに

本記事を書くにあたって Python2年生 スクレイピングのしくみ 体験してわかる!会話でまなべる! を参考にさせていただきました。

こちらの本では、Beautiful Soup4を使ったWebクローリングをはじめ、表データをPandasやOpenPyXL、matplotでデータ解析、グラフ表示などのスクレイピングのやり方が分かりやすく説明されてます。図解が多いのでPython初心者の方でも読み進められる内容となってます。 また、本記事では、書籍に紹介されてないPandasの機能も紹介しております。

Pandasの準備

プログラミング作業に入る前に、Pandasの準備などを行なっていきます。なお本記事では、macOS上のPython 3.9.4で作業を行ないました。

Pandasのインストール

はじめに、必要なライブラリのインストールを行いましょう。pandas以外にも、グラフ表示を行うためmatplotと、その日本語文字化け対策にjapanize_matplotlib、また、Excelファイルを読み込むxlrdと書き込むxlwtもあわせてインストールします。pip3コマンドを使って、次のようにインストールしてください。

shell
$ pip3 install pandas
$ pip3 install matplotlib
$ pip3 install japanize_matplotlib
$ pip3 install japanize_matplotlib
$ pip3 install xlrd xlwt

▼ Pandas関連の本はとても充実してます。

表データの名称

表データの名称を確認しておきましょう。縦方向を列、横方向を行と呼びますので、行番号、列名、ヘッダー、要素はそれぞれ次の図のとおりです。

表データの名称
表データの名称

Pandasの使い方

それではpandasの使い方を説明していきます。

ライブラリをインポートする

PythonプログラムでPandasを使うときはimport pandas as pdのようにしてpdの名前で使えるようにします。matplotも使用しますので、次のように必要に応じてライブラリをインポートしてください。

py
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib

表データを読み込む(Excel、CSV)

PandasではExcelやCSVなどの表データを簡単に読み込むことができます。Pandasで読み込んだ表データはDataFrameというオブジェクトへ変換されます。これによって、表データをPythonで簡単に扱うことができます。 なおこの記事ではデータフレームの変数名をdfとします。

Excelファイルの読み込みの読み込みは次のように行います。sheet_nameでシートを指定できます。

py
df = pd.read_excel('ファイル名.xlsx', sheet_name='シート名')

CSVファイルの読み込みの読み込みは次のように行います。

py
df = pd.read_csv('ファイル名.csv') 

エンコードを指定して文字化け対処

CSVファイルがUTF-8でない場合、ファイルの読み込み時に次のようなエラーになります。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 0: invalid start byte

これを回避するには次のようにエンコードを指定してください。

df = pd.read_csv('ファイル名.csv', encoding="SHIFT-JIS") 

データ情報を表示する

読み込んだデータの情報を、次のようにして確認できます。

py
print(df) # データの中身
print(len(df)) # データの件数
print(df.columns.values) # ヘッダー(項目名一覧)
print(df.index.values) # インデックス一覧

行番号がインデックスとして登録されます。

列データや行データを抽出する

特定の列データを抽出したい場合、df['列名']で列データを抽出できます。また、df[['列名1', '列名2']]のように複数の指定も可能です。

py
column = df['列名']

行データを表示する場合は、df.loc[行番号]を使います。df.loc[[行番号1, 行番号2]]のように複数の指定も可能です。

py
row = df[行番号]

また、行番号と列名を指定すれば要素を取り出すことができます。

py
value = df.loc[行番号]['列名']

条件をつけてデータを抽出する

条件をつけてデータを抽出できます。

py
df = df[df['列名'] >= 70]

複数条件の場合は、次のように書きます。

df = df[(df['列名'] >= 0) & (df['列名'] < 70)]

条件演算子は、and&or|not~を使います。

インデックスを指定して読み込む

次のように、index_colでインデックスとなる列、headerでヘッダーとなる行を指定して読み込むことができます。

py
df = pd.read_excel('ファイル名.xlsx', index_col=インデックス列番号, header=ヘッダー行番号)

表データを読み込む際にindex_colでインデックスを指定すると、インデックス名で行を選択できます。

py
df.loc['インデックス名']['列名']

ただし、index_colを指定した場合、行番号では指定できなくなります。

後からインデックスの列を変更を行うには、次のようにして再定義できます。

py
df = df.set_index('列名')

データを追加・変更する

行データの追加と書き換えは次の通り行います。

py
df.loc[行番号 or 'インデックス'] = [データ1, データ2, ... , データN]

ただし、表データ読み込み時にindex_colを使用しているかどうかで、インデックスの指定が異なりますので注意してください。 また、すでに行にデータが存在する場合は、上書きされて書き換えられます。

また、表データと同じ項目数を代入しないとエラーになります。

ValueError: cannot set a row with mismatched columns

一方、列データの追加と書き換えは次の通り行います。

py
df['列名'] = [データ1, データ2, ... , データN]

行を追加する

append関数を使うと簡単に行を追加できます。
py
df = pd.DataFrame(index=[], columns=['date', 'description'])
df = df.append({'date': '20210921', 'description': 'hogehoge'}, ignore_index=True)
df = df.append({'date': '20210925', 'description': 'fugafuga'}, ignore_index=True)
return df

特定の要素を書き換える

特定の要素を指定して新しいデータで書き換える場合は注意が必要です。次のようにデータを更新しようとするとエラーになります。

df.loc[行番号]['列名'] = 新しいデータ

次のようなSettingWithCopyWarningというエラーが吐き出されました。

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

詳しい原因はわかりませんが、次ように指定すればエラーなく書き換えることができました。

df.loc[行番号, ['列名']] = 新しいデータ

列データや行データを削除する

列データの削除は、drop関数で列名とaxis=1を指定します。

py
df = df.drop('列名', axis=1)

行データの削除は、axis=0を指定します。

py
df = df.drop(行番号 or 'インデックス', axis=0)

nanデータを取り除く

表データにnanデータが入っていると都合が悪い場合があります。次のプログラムは、特定の列にnanデータが入っていたら、その行を取り除くことができます。

py
df = df[df['列名'].notnull()]

データを並べ替える

特定の列を基準にデータを昇順にソートします。

py
df = df.sort_values('列名')

特定の列を基準にデータを降順にソートします。

py
df = df.sort_values('列名', ascending=False)

データを集計する

次のように、列名を指定してデータを集計します。

py
df['列名'].max()
df['列名'].min()
df['列名'].mean()
df['列名'].median()
df['列名'].sum()

ちなみに、meanは平均値で、medianは中央値となります。中央値とは、データを大きさ順に並べた時の真ん中に位置する値のことです。

▼ 中央値は、 メディアンフィルタ としてノイズが多いデータから正しい値を抽出する時に活躍します。

行と列を入れ替える

行と列を入れ替えるには.Tを付与します。

py
df.T

リスト型や辞書型に変換する

データフレームをリスト型の配列に変換します。

py
list = df.values.tolist()

データフレームを辞書型の配列に変換します。

py
dict = df.to_dict()

データフレームをファイルに書き出す(Excel、CSV)

データフレームをExcelファイルに書き出します。

py
df.to_excel("ファイル名.csv", sheet_name='シート名')

データフレームをCSVファイルに書き出します。

py
df.to_csv("ファイル名.csv")

インデックスやヘッダーを削除して保存するには、次のように指定します。

py
df.to_csv("ファイル名.csv", index=False, header=False)

オープンデータを読み込んでみよう

ここまでで、一通りのpandasの使い方がわかりました。ここではオープンデータを使って実際にpandasで表データを読み込み、matplotでグラフ表示させます。

オープンデータとは

オープンデータとは、利用規約を守れば、誰でも自由に入手して利用することができるデータのことです。主に、政府や自治体、教育機関、企業などが公開してます。 たとえば「e-Stat」の 利用規約 を読みますと、「CC BY」ライセンスで公開されていることが確認できます。「CC BY」では著作者情報を記載してリンクを貼れば、自由に利用できるといった内容になります。 オープンデータのサイトには次のようなものがあります。

オープンデータのサイト一覧

政府統計の総合窓口 キッズすたっと~探そう統計データ~ データシティ鯖江ポータルサイト | Data City Sabae 気象庁|過去の気象データ・ダウンロード 郵便番号データダウンロード - 日本郵便 DATA GO JP Statcounter Global Stats - Browser, OS, Search Engine including Mobile Usage Share

2021年8月国内の年齢、男女別人口のデータ抽出

ここでは「e-Stat」のオープンデータから、次のデータを利用させてもらいました。

年齢(5歳階級)、男女別人口(2021年3月平成27年国勢調査を基準とする推計値、2021年8月概算値)

リンク先からExcelファイルをダウンロードし、次のようにデータを抽出してみました。

py
import pandas as pd

df = pd.read_excel('05k2-3.xlsx', header=3)
df = df.drop(['時間軸コード', '区分', '単位'], axis=1)  # 必要のない列の削除
df = df[df['年齢階級'].notnull()]  # nanデータのセルを取り除く
df = df[(df['人口区分'] == '総人口') & (df['時点'] == '2021年8月1日現在(概算値)')]  # 総数行の削除
df = df.drop(['人口区分', '時点'], axis=1)  # 必要のない列をふたたび削除
df = df.drop(range(22, 32, 1), axis=0)
df = df.drop(0, axis=0)

これで、次のような人口データを抽出できました。

年齢階級男女計
0歳~4歳453232221
5歳~9歳499255244
10歳~14歳533273260
15歳~19歳558286273
20歳~24歳635327308
25歳~29歳632327305
30歳~34歳645330315
35歳~39歳729370359
40歳~44歳814412402
45歳~49歳970490480
50歳~54歳908457451
55歳~59歳781390391
60歳~64歳738364373
65歳~69歳791384407
70歳~74歳972459513
75歳~79歳674301373
80歳~84歳554231323
85歳~89歳387140247
90歳~94歳19154137
95歳~99歳581247
100歳以上817

人口データの集計

先ほどの人口データから、もっとも多い年齢階級を調べて表示させてみました。

py
...
mf_max = df['男女計'].max()
m_max = df['男'].max()
f_max = df['女'].max()

df_mf_max = df[df['男女計'] == mf_max]
df_m_max = df[df['男'] == m_max]
df_f_max = df[df['女'] == f_max]
print('男女計でもっとも多い年齢階級: {}, {}万人'.format(df_mf_max['年齢階級'].values[0], int(mf_max)))
print('男計でもっとも多い年齢階級: {}, {}万人'.format(df_m_max['年齢階級'].values[0], int(m_max)))
print('女計でもっとも多い年齢階級: {}, {}万人'.format(df_f_max['年齢階級'].values[0], int(f_max)))

次のような結果です。

男女計でもっとも多い年齢階級: 70歳~74歳, 972万人
男計でもっとも多い年齢階級: 45歳~49歳, 490万人
女計でもっとも多い年齢階級: 70歳~74歳, 513万人

グラフ表示

最後にmatplotでグラフ表示してみましょう。pandasのデータフレームは、df.plotという形でそのままグラフ表示ができます。

py
...

import matplotlib.pyplot as plt
import japanize_matplotlib

...

df = df.set_index('年齢階級')  # インデックスの再定義
df[['男', '女']].plot.bar() # 棒グラフ
plt.show()

df['男女計'].T.plot.barh()  # 行と列を総入れ替えして横棒グラフ
plt.show()

次のようにグラフ表示ができました。

男女別人口のグラフ
男女別人口のグラフ

男女計の人口のグラフ
男女計の人口のグラフ

関連記事

最後までご覧いただきありがとうございます!

▼ 記事に関するご質問やお仕事のご相談は以下よりお願いいたします。
お問い合わせフォーム

Python学習にオススメの本をご紹介!
Pandasでデータサイエンスはじめよう!
スクレイピングにオススメの書籍

▼ Beautiful Soup4を使ったWebクローリングをはじめ、表データをpandasやOpenPyXL、matplotでデータ解析、グラフ表示などのスクレイピングのやり方が分かりやすく説明されてます。図解が多いのでPython初心者の方でも読み進められる内容となってます。

関連記事