Skip to content

5. データ操作の基礎 - pandas

第 5 回では pandas を用いたデータ操作について学びます。

5.1 pandas の概要

pandas は、Python でデータ操作やデータ分析を行うためのライブラリで、NumPy を基盤として構築されており、NumPy よりも柔軟にデータを扱えるように設計されています。

pandas が提供する主要なデータ構造には、SeriesDataFrame があります。

5.1.1 pandas のインポート

pandas は以下のようにインポートして使います。

import pandas as pd

5.2 Series

Series(シリーズ)は、一次元のラベル付きデータを格納することができます。リストや配列と似ていますが、インデックス(ラベル)を使ってアクセスできる特徴があります。

Series は以下のように、pandas.Series() 関数で作ることができます。

リストから Series の作成
import pandas as pd

data = [10, 20, 30]
s = pd.Series(data)
print(s)
Output
0    10
1    20
2    30
dtype: int64

インデックスを指定して Series を作成するには以下のようにします。

インデックスを指定した Series の作成
s = pd.Series([10, 20, 30], index=["a", "b", "c"])
print(s)
Output
a    10
b    20
c    30
dtype: int64

以下のように辞書から Series を作成することもできます。

辞書から Series の作成
data = {"apple": 100, "banana": 200, "orange": 300}
s = pd.Series(data)
print(s)
Output
apple     100
banana    200
orange    300
dtype: int64

値にアクセスする際は、ブラケット ([]) を使う方法と、pandas.Series.at() 関数を使う方法があります。

  • [] はスライス操作などができる柔軟性を持ちます。
  • at は要素へのアクセスに特化しているため高速に動作します。
Series の値へのアクセス
print(s["banana"])      # 出力: 200
print(s.at["banana"])   # 出力: 200

Series は内部で NumPy 配列を利用しているため、NumPy のブロードキャストと同様の演算操作が可能です。例えば、各要素に対して以下のように演算を行うことができます。

Series の要素に対する演算(消費税計算)
s = s * 1.08
print(s)
Output
apple     108.0
banana    216.0
orange    324.0
dtype: float64

条件式による要素抽出も可能です。

Series における要素の抽出
print(s[s > 200])
Output
banana    216.0
orange    324.0
dtype: float64

5.3 DataFrame

DataFrame(データフレーム)は、複数の Series を列にまとめた二次元の表形式のデータ構造です。DataFrame は Excel や SQL などの多くの表形式のデータとの連携が容易であること、実務データは複数の変数(列)を持つことが一般的であること、Series を包含していることなどから、実務では圧倒的に DataFrame が使用されることが多いです。

5.3.1 DataFrame の作り方

DataFrame を作るためには、pandas.DataFrame() 関数を使用します。

以下は、3 人分の「名前」「年齢」「身長」の情報を含む二次元のリストから DataFrame を作成する例です。columns で列名を指定することができ、これを省略すると整数のインデックス(0, 1, 2, ...)が列名として使用されます。

リストから DataFrame の作成
import pandas as pd

data = [
    ["太郎", 25, 170],
    ["花子", 30, 160],
    ["次郎", 22, 175]
]

df = pd.DataFrame(data, columns=["名前", "年齢", "身長"])
print(df)
Output
   名前  年齢   身長
0  太郎   25   170
1  花子   30   160
2  次郎   22   175

デフォルトでは各行に整数のインデックス(0, 1, 2, ...)が振られますが、Series と同様に任意のインデックス(ラベル)を指定することもできます。

リストから DataFrame の作成(インデックスを指定)
import pandas as pd

data = [
    ["太郎", 25, 170],
    ["花子", 30, 160],
    ["次郎", 22, 175]
]

df = pd.DataFrame(data, columns=["名前", "年齢", "身長"], index=["A", "B", "C"])
print(df)
Output
   名前  年齢   身長
A  太郎   25   170
B  花子   30   160
C  次郎   22   175

以下のように、辞書から DataFrame を作成することもできます。

辞書から DataFrame の作成
import pandas as pd

data = {
    "名前": ["太郎", "花子", "次郎"],
    "年齢": [25, 30, 22],
    "身長": [170, 160, 175]
}

df = pd.DataFrame(data)
print(df)
Output
   名前  年齢   身長
0  太郎   25   170
1  花子   30   160
2  次郎   22   175

5.3.2 DataFrame の読み込み

DataFrame はリストや辞書から作成する以外に、外部から読み込ませて扱うケースも多くあります。

サンプルデータセットの利用

インターネット上に存在する多くのサンプルデータセットは、DataFrame の形式で提供されています。例えば、第 3 回の「データ可視化」で扱った Seaborn のサンプルデータセットも DataFrame 形式であり、以下のようにして読み込ませることができます。

Seaborn の penguins データセットの読み込み
import seaborn as sns
penguins = sns.load_dataset("penguins")
print(penguins.head())
Output
  species     island  bill_length_mm  ...  flipper_length_mm  body_mass_g     sex
0  Adelie  Torgersen            39.1  ...              181.0       3750.0    Male
1  Adelie  Torgersen            39.5  ...              186.0       3800.0  Female
2  Adelie  Torgersen            40.3  ...              195.0       3250.0  Female
3  Adelie  Torgersen             NaN  ...                NaN          NaN     NaN
4  Adelie  Torgersen            36.7  ...              193.0       3450.0  Female

外部ファイルの読み込み

pandas.read_csv() 関数や pandas.read_excel() 関数を使うことで、CSV ファイル Excel ファイルを DataFrame として読み込ませることができます。

CSV ファイルの読み込み
import pandas as pd
df = pd.read_csv("data.csv")
print(df.head())
Excel ファイルの読み込み
import pandas as pd
df = pd.read_excel("data.xlsx")
print(df.head())

pandas.read_excel() 関数では、sheet_name パラメータで読み込むシート名を、usecols パラメータで読み込む列を指定することも可能です。

CSV ファイル

CSV(Comma-Separated Values)は、データをカンマ(,)で区切ったテキスト形式のファイルです。CSV は Excel で開くことが多いかもしれませんが、中身は単純なテキストデータなので、メモ帳などで開くこともできます。

5.3.3 DataFrame の操作

DataFrame を操作する方法を見ていきましょう。df という名前で以下の DataFrame があるものとします。

DataFrame
   名前  年齢   身長
0  太郎   25   170
1  花子   30   160
2  次郎   22   175

並び替え(ソート)

DataFrame の任意の列を並べ替えたい(ソートしたい)場合は、DataFrame.sort_values() 関数を用います。並び替えの対象とする列は by= パラメータで指定します。

年齢の低い順(昇順)にソート
sorted_df = df.sort_values(by="年齢")
print(sorted_df)
Output
   名前  年齢   身長
2  次郎  22  175
0  太郎  25  170
1  花子  30  160

デフォルトでは上の例のように、数字の小さい順(昇順)での並び替えが行われます。数字の大きい順(降順)での並び替えをしたい場合は、以下のように ascending=False パラメータを追加します。

年齢の高い順(降順)にソート
sorted_df = df.sort_values(by="年齢", ascending=False)
print(sorted_df)
Output
   名前  年齢   身長
1  花子  30  160
0  太郎  25  170
2  次郎  22  175

列の抽出

DataFrame から列を抽出したい場合は、以下のように列名を指定します。このとき、一次元の Series データが抽出されます。

DataFrame から列の抽出
print(df["名前"])
Output
0    太郎
1    花子
2    次郎
Name: 名前, dtype: object

列名をリストで指定することで、複数の列を同時に抽出することもできます。このとき、抽出したデータも DataFrame となります。

DataFrame から複数列の抽出
print(df[["年齢", "身長"]])
Output
   年齢   身長
0   25   170
1   30   160
2   22   175

行の抽出

DataFrame から行を抽出したい場合は、pandas.loc[] インデクサまたは pandas.iloc[] インデクサを使用します。loc ではインデックス名を指定するのに対し、iloc では整数インデックスを指定します。

DataFrame から行の抽出(iloc も同様)
print(df.loc[1])
Output
名前     花子
年齢      30
身長     160
Name: 1, dtype: object

複数の行を抽出するには、リストで指定するか、スライスを使用します。

DataFrame から複数行の抽出(リストで指定)
print(df.loc[[0, 1]])
DataFrame から複数行の抽出(スライスを使用)
print(df.iloc[:2])
Output
   名前  年齢   身長
0  太郎   25   170
1  花子   30   160

デフォルトの整数インデックスの場合、lociloc は同じように使うことができます。ただし、スライスを使用する場合、iloc はリストのスライスと同様に終端を含まない範囲を抽出する一方で、loc では終端を含む点に注意が必要です。上のスライスを使用する例で ilocloc に置き換える場合は、df.loc[:1] となります。

行・列の抽出

df.loc[行ラベル, 列ラベル] とすることで、行と列を同時に指定して抽出することもできます。すべての行と列を取得するには、以下のようにします。

DataFrame からすべての行と列を抽出
print(df.loc[:, :])

行ラベル(インデックス)が 1 、列ラベルが "名前" の値を抽出したい場合は以下のようにします。

DataFrame から行と列を指定して抽出
print(df.loc[1, "名前"])
Output
花子

行ラベル(インデックス)が 1 以降、列ラベルが "名前""年齢" の値を抽出したい場合は以下のようにします。

DataFrame から行と列を指定して抽出
print(df.loc[1:, ["名前", "年齢"]])
Output
   名前  年齢
1  花子   30
2  次郎   22

条件式による抽出

条件式を用いることで、DataFrame から効率的にデータを抽出することが可能になります。

  • 条件式には、==, !=, <, >, <=, >= などの比較演算子を使用します。
  • 複数の条件を指定する場合は、& (AND), | (OR), ~ (NOT) などの論理演算子を使用します。

例えば、年齢が 25 歳以上の人を抽出するには、以下のようにします。

年齢が25歳以上の人を抽出
print(df.loc[df["年齢"] >= 25])
Output
   名前  年齢   身長
0  太郎   25   170
1  花子   30   160

年齢が 25 歳以上かつ身長が 170 cm 未満の人を抽出するには、以下のようにします。

年齢が25歳以上かつ身長が170cm未満の人を抽出
print(df.loc[(df["年齢"] >= 25) & (df["身長"] < 170)])
Output
   名前  年齢   身長
1  花子   30   160

複数条件を利用する際の注意

DataFrame におけるデータ抽出において、& (AND) や '|' (OR) を用いて複数の条件を指定する際は、それぞれの条件式を括弧 () で囲う必要がある点に注意してください。

✅️ df.loc[(df["年齢"] >= 25) & (df["身長"] < 170)] ❌️ df.loc[df["年齢"] >= 25 & df["身長"] < 170]

これらの抽出方法をうまく組み合わせることで、複雑な条件でも効率的にデータ抽出をすることができるようになります。

演習

演習 5-1

与えられた都道府県データ [都道府県番号, 人口(万人), 面積(km²), 緯度, 経度] の DataFrame に対し、「人口密度」の列を追加してください。また、人口が250万人以上の都道府県を抽出し、人口密度の高い順に並べ替えて棒グラフで可視化してください。

演習 5-2

Seaborn に含まれる diamonds データセットを使い、ダイヤモンドのカラットを [0, 0.5), [0.5, 1), [1, 2), [2, ∞) の4つの区分に分けて、2x2 のサブプロットを作成しててください。各サブプロットには、対応するカラット区分のダイヤモンドの価格(price)分布をヒストグラムで描画してください。