pandas
のDataFrame
では、インデックス名やカラム名を使ってデータにアクセスしますね。
とは言っても、pandas
の操作に慣れていないうちは、ちょっとしたインデックス操作も難しいですよね。例えばこんな疑問も…。
- そもそもインデックスはどういう仕組みになの?
- インデックス内のデータってどうやって検索するの?
- 並べかえたり、最大値・最小値を見つけたりすることってできるの?
そこで、この記事では次の内容をサンプルコード付きで解説していきます:
- インデックスの基本構造、インデックス内要素へのアクセス方法
- 基本的なインデックス操作:データ探索、並べ替え、重複処理、欠損値処理
インデックスの基本操作をマスターして、自由にpandas
を操作できるようになりましょう!
この記事ではインデックスの基本操作について解説しています。
インデックスへのラベルの設定(再設定や一部変更含む)については次の記事を参考にしてください。
インデックス、カラムの基本構造
そもそもインデックスやカラムとは、どういったものなのでしょうか?
まずはインデックスの正体についても解説していきます!
そもそもインデックスとカラムはどっちがどっち?
まずDataFrame
のインデックスやカラムについて整理しましょう。
インデックス、カラムはそれぞれDataFrame
の次の要素です。
- インデックス:縦方向のラベル
- カラム:横方向のラベル
DataFrame
のインデックスやカラムは、表で言うところの行や列のタイトルのようなものですね。
次の図のように、インデックスやカラムには名前を付けることも可能です。
概要がわかったところで、次にインデックスやカラムの構造をもっと詳しく見ていきましょう。
インデックスの正体とは?!
実は、インデックスやカラムの正体はpd.Index
系列のオブジェクトです。
インデックスを横向きにすればカラムになるので、カラムもpd.Index
系列のオブジェクトで表現されます。
pd.Index
系列のオブジェクトの代表例としては次のようなものがあります。
初めはpd.Index
の使い方を覚えて、必要に応じて他のオブジェクトの使い方も覚えていきたいですね。
pd.Index 系列の例 |
説明 |
---|---|
pd.Index |
いろいろなデータに対応する基本的なインデックス |
pd.RangeIndex |
連番に特化したインデックス Ex) 0 , 1 , 2 … |
pd.DatetimeIndex |
日付、時刻に特化したインデックス Ex) 2021-06-07 , 2021-06-08 … |
pd.MultiIndex |
階層型インデックス Ex) Apple 1 , Apple 2 , Banana 1 , Banana 2 など |
まずはpd.Index
を例にインデックスの基本を理解しましょう。
pd.Index
系列は次の2つの基本要素から構成されています。
インデックス名
:インデックスやコラムのタイトルのようなものインデックスのデータ
:個々のラベル名
例えば、次のようにDataFrame
のインデックスやコラムにpd.Index
を設定可能です。
data = [[0, 1],
[10, 11],
[20, 21]]
df = pd.DataFrame(data, columns=pd.Index(["Data1", "Data2"]))
df.set_axis( pd.Index(['Name1', 'Name2', "Name3"], name="Names"), inplace=True)
以下では、インデックスの操作について解説しますが、元のオブジェクトは同じなのでカラムでもほぼ同等の操作が可能です。
インデックスの基本操作
インデックスの基本操作として、次の内容を解説します。
- インデックス、カラムのオブジェクトを取得
- インデックスの要素にアクセス
- インデックス名にアクセス
インデックスのオブジェクトを取得|df.index
インデックスやカラムを操作するためには、まずはそれらのオブジェクトを取得する必要があります。
それぞれDataFrame
の次の要素に対応しています。
- インデックス:
df.index
- カラム:
df.columns
print()
関数で出力してみましょう。
data = [[0, 1],
[10, 11],
[20, 21]]
df = pd.DataFrame(data, columns=pd.Index(["Data1", "Data2"]))
df.set_axis( pd.Index(['Name1', 'Name2', "Name3"], name="Names"), inplace=True)
print(df.index)
# Index(['Name1', 'Name2', 'Name3'], dtype='object', name='Names')
print(df.columns)
# Index(['Data1', 'Data2'], dtype='object')
インデックス、カラムのpd.Index
オブジェクトの中身が表示されていますね。
各要素にアクセス|df.index[ ]
pythonのリストと同じように、インデックス番号でインデックスの各要素にアクセスできます。
サンプルコードでいくつかアクセスしてみましょう。
df.index[0]
# Name0
df.index[2]
# Name2
df.columns[1]
# Data1
スライスや負の値でのアクセスも可能です。
スライスの場合はpd.Index
オブジェクトで返されます。
df.index[0:2]
# Index(['Name0', 'Name1'], dtype='object', name='Names')
負の値で指定する場合も、リストと挙動は同じです。
df.index[-1]
# Name3
インデックス名にアクセス|df.index.name
pd.Index
のname
属性からインデックス名やカラム名にアクセスできます。
- インデックス名:
df.index.name
- カラム名:
df.columns.name
次のdf
を例にインデックス名の表示、書き換え例を紹介します。
data = [[0, 1],
[10, 11],]
df = pd.DataFrame(data, columns=pd.Index(["Data0", "Data1"]))
df.set_axis( pd.Index(['Name0', 'Name1'], name="Names"), inplace=True)
今は、インデックス名は"Names"
になっていますね。
実際にdf.index.name
にアクセスして、インデックス名を表示してみましょう。
df.index.name
# Names
次にインデックス名を書き換えてみます。
df.index.name = "ind_name"
無事、インデックス名が変更できました。
pd.Index
のrename()
メソッドでインデックス名を変更することもできます。
df.index.rename("Ind_name", inplace=True)
インデックス内の検索
インデックス内のデータを検索する方法として、次の2つを紹介します。
- ラベル名からインデックス番号を検索
- 最大、最小値の検索
ラベル名からインデックス番号検索|df.index.get_loc
ラベル名に対応するインデックス番号を検索するには、get_loc()
メソッドを使用します。
df.index.get_loc("検索するラベル名")
|インデックス内のラベル位置を検索
"検索するラベル名"
に対応するインデックス番号が返されます。
# df
# c0 c1
# ind
# i0 0 1
# i1 10 11
# i2 20 21
# インデックス内の"i2"を検索
df.index.get_loc("i2")
# 2
# カラム内の"c0"を検索
df.columns.get_loc("c0")
# 0
df.index.get_loc("i999")
# KeyError: 'i999'
存在しないラベル名を検索するとKeyError
になります。
最大・最小値の検索|df.index.max(), .argmax()
インデックスが数値の場合は、pd.Index
のメソッドで最大値、最小値の検索、それらのインデックス番号の検索が可能です。
メソッド一覧は次の通りです。
検索内容 | 最大値 | 最小値 |
---|---|---|
最大・最小の値 | df.index.max() |
df.index.min() |
最大・最小値のインデックス番号 | df.index.argmax() |
df.index.argmin() |
カラムの最大・最小値を検索する場合には、df.index
の代わりにdf.cloumns
でカラムにアクセスします。
次のデータフレームを例に最大、最小値の検索例を紹介します。
data = [[10, 11, 12],
[-10, -11, -22],
[30, 31, 32],
[20, 21, 22]]
df = pd.DataFrame(data, columns=["c0", "c1", "c2"]).set_index("c0")
このdf
のインデックスの最大値、最小値とその位置を出力してみましょう。
# 最大値
print(f"インデックス内最大値:{df.index.max()}")
print(f"最大値のインデックス番号:{df.index.argmax()}")
# インデックス内最大値:30
# 最大値のインデックス番号:2
# 最小値
print(f"インデックス内最小値:{df.index.min()}")
print(f"最小値のインデックス番号:{df.index.argmin()}")
# インデックス内最小値:-10
# 最小値のインデックス番号:1
簡単ですね。
細かなメソッドの存在を知っているか知らないかだけがポイントですね。
インデックスの便利な操作
覚えておくと便利なインデックスの操作を3つ紹介します。
- インデックスの並べ替え
- 欠損値の検索、処理
- 重複の検索、処理
インデックスの内容で並べ替え|df.sort_index()
DataFrame
をインデックスの内容で昇順、降順に並べ替えるには、DataFrame
のメソッドdf.sort_index()
を使用します。
df.sort_index()
|df
をインデックスの内容で昇順、降順に並べ替え
引数名 | 型 | 説明 |
---|---|---|
ascending |
真偽値:True or False |
True (デフォルト):昇順 Ex) 1, 2, 3… 、A, B, C… False :降順 Ex) 100, 99, 98… 、D, C, B… |
inplace |
真偽値:True or False |
True :df そのものを上書きFalse (デフォルト):新しいdf を返す(元のdf は変化なし) |
次のDataFrame
を例に昇順、降順の並べ替えを紹介します。
data = [[0, 1],
[10, 11],
[20, 21]]
df = pd.DataFrame(data, columns=["Data0", "Data1"])
df.index= pd.Index(['Banana', 'Apple', "Carotte"], name='Item')
インデックスの内容で昇順に並べ替えてみます。
df.sort_index(inplace=True)
次にascending = False
を指定して、降順に並べ替えます。
df.sort_index(ascending=False, inplace=True)
欠損値の検索、処理
インデックス内の欠損値の検索、処理に関して次の内容を紹介します。
次のDataFrame
を例にそれぞれの使い方を見ていきましょう。
data = [[0, 1],
[10, 11],
[20, 21],
[30, 31]]
df = pd.DataFrame(data, columns=["c0", "c1"])
df.index= pd.Index(['i0', None, "i2", None], name='ind')
①インデックスに欠損値があるか判定|df.index.hasnans
DataFrame
のインデックスに一つでもNone
があると、True
を返します。
# c0 c1
# ind
# i0 0 1
# NaN 10 11
# i2 20 21
# NaN 30 31
df.index.hasnans
# True
シンプルですが、欠損値があるかないかだけを知りたいときは便利です。
②各インデックス要素が欠損値か真偽値で出力|df.index.isna()
インデックス内の各データが欠損値かどうかを、真偽値配列で返します。
# c0 c1
# ind
# i0 0 1
# NaN 10 11
# i2 20 21
# NaN 30 31
df.index.isna()
# array([False, True, False, True])
真偽値の配列で返ってくることがポイントです。
df.loc[]
で、DataFrame
の一部を切り出せる機能と組み合わせると、DataFrame
を抽出できます。
df.loc[df.index.isna()]
で、インデックスが欠損値の行を抽出できます。
df.loc[ df.index.isna() ]
# c0 c1
# ind
# NaN 10 11
# NaN 30 31
③欠損値の行を除去|df.index.dropna()
df.index.dropna()
を使用すると欠損値を除去したpd.Index
を生成されます。
これをdf.loc[]
に渡すことでも、インデックスが欠損値でない行を抽出することができます。
# 欠損値を除去したインデックスを生成
df.index.dropna()
# Index(['i0', 'i2'], dtype='object', name='ind')
# インデックスが欠損値でない行を抽出
df.loc[df.index.dropna()]
# c0 c1
# ind
# i0 0 1
# i2 20 21
④欠損値を他の値で置き換え|df.index.fillna("代入値")
df.index.fillna("代入値")
で、インデックス内の欠損値を"代入値"
に置き換えたpd.Index
を生成できます。
これで既存のインデックスdf.index
を上書きすれば、欠損値が"代入値"
で置き換わります。
df.index = df.index.fillna("i_nan")
# c0 c1
# ind
# i0 0 1
# i_nan 10 11
# i2 20 21
# i_nan 30 31
欠損値が複数ある場合には、インデックスの重複が生じてしまいますね。
重複検索、処理
インデックス内の重複値の検索、処理に関して次の内容を紹介します。
内容 | df の属性 or メソッド |
出力 |
---|---|---|
インデックスに重複値があるか判定 | df.index.has_duplicates |
真偽値:True or False |
インデックスが重複無しか判定 | df.index.is_unique |
真偽値:True or False |
各要素が重複値か真偽値で出力 | df.index.duplicated() |
真偽値の配列: 重複値の位置が True 、それ以外はFalse |
重複値の行を除去 | ~df.index.duplicated() (これを df.loc[] に渡す) |
真偽値の配列: 重複値の位置が False 、それ以外はTrue |
次のDataFrame
を例にそれぞれの使い方を見ていきましょう。
data = [[0, 1],
[10, 11],
[20, 21],
[30, 31]]
df = pd.DataFrame(data, columns=["c0", "c1"])
df.index= pd.Index(['i0', "i_dup", "i2", "i_dup"], name='ind')
①インデックスに重複値があるか判定|df.index.has_duplicates
DataFrame
のインデックスに重複値が一つでもあると、True
を返します。
# c0 c1
# ind
# i0 0 1
# i_dup 10 11
# i2 20 21
# i_dup 30 31
df.index.has_duplicates
# True
シンプルですが、重複があるかないかだけを知りたいときは便利です。
②インデックスがユニーク(重複無し)か判定|df.index.is_unique
インデックスがユニークかの判定は、df.index.is_unique
で可能です。
df.index.is_unique
# False
df.index.has_duplicates
の否定ですね。
③各インデックス要素が重複値か真偽値で出力|df.index.duplicated()
インデックス内の各データが重複値かどうかを、真偽値配列で返します。
重複値の位置はTrue
で表現されます。
デフォルトでは重複値のうち、一つ目の位置にはFalse
が格納されて、二つ目以降が重複値として扱われます。
引数によって、重複値のうち最後の位置にFalse
を格納させたり、重複値全ての位置にTrue
を設定させたりできます。
値 | 説明 |
---|---|
"first" (デフォルト) |
一つ目を除いた重複値位置をTrue にする |
"last" |
最後のものを除いた重複値位置をTrue にする |
False |
全部の重複値位置をTrue にする |
挙動の違いを具体的なサンプルコードで確認してみましょう。
# c0 c1
# ind
# i0 0 1
# i_dup 10 11 # ←重複値①の行
# i2 20 21
# i_dup 30 31 # ←重複値②の行
df.index.duplicated("first") # firstはデフォルト値なので省略可能
# [False False False True]
df.index.duplicated("last")
# [False True False False]
df.index.duplicated(False)
#[False True False True]
それぞれでTrue
として、重複値判定された位置が異なっていますね。
重複行のみ抽出したdf
を生成したい場合には、df.loc[]
にdf.index.duplicated()
を渡します。
df.loc[df.index.duplicated(False)]
# c0 c1
# ind
# i_dup 10 11
# i_dup 30 31
④重複値の行を除去|~df.index.duplicated()
インデックスの重複した行を除去したDataFrame
を生成する場合には、~df.index.duplicated()
をdf.loc[]
に渡すのが最も簡単だと思います。
# c0 c1
# ind
# i0 0 1
# i_dup 10 11 # ←重複値①の行
# i2 20 21
# i_dup 30 31 # ←重複値②の行
df.loc[df.index.duplicated("first")] # firstはデフォルト値なので省略可能
# c0 c1
# ind
# i0 0 1
# i_dup 10 11 # ←重複値①の行
# i2 20 21
df.loc[~df.index.duplicated("last")]
# c0 c1
# ind
# i0 0 1
# i2 20 21
# i_dup 30 31 # ←重複値②の行
df.loc[~df.index.duplicated(False)]
# c0 c1
# ind
# i0 0 1
# i2 20 21
おわりに|padans関連おススメ追加コンテンツ
今回はpandas
のインデックスの設定、変更に関する内容を紹介しました。
pandas
は便利すぎて操作方法がわかりにくいことがよくあります…。
結局はコツコツ学ぶのが、pandas
マスターの近道ですよね!≫【ブログカテゴリー:pandas】
Twitter@YutaKaでは、ほぼ毎日pythonに関する情報を発信しています。
気楽にツイートしているので、気軽にフォローしてください!