pandas.DataFrameの行・列を任意の順に並べ替えるreindex
pandasでDataFrame
の行・列を任意の順番に並べ替えるにはreindex()
を使う。Series
にも同様のメソッドがある。ラベル(行名・列名)のリストを指定する。
- pandas.DataFrame.reindex — pandas 2.1.4 documentation
- pandas.Series.reindex — pandas 2.1.4 documentation
別のDataFrame
の行・列と同じように並べるreindex_like()
というメソッドもある。
- pandas.DataFrame.reindex_like — pandas 2.1.4 documentation
- pandas.Series.reindex_like — pandas 2.1.4 documentation
いずれのメソッドでも、既存の行・列を並べ替えるだけでなく、新たな行・列を追加することが可能。
以下のサンプルコードではDataFrame
を例とするが、Series
でも使い方は同じ。Series
にはcolumns
が無いのでindex
のみを指定する。
任意の順番ではなく昇順・降順に並べ替えたい場合はsort_index()
を使う。
都道府県名を都道府県コード順にソートするといった、任意のルールに従って並べ替えたい場合は以下の記事を参照。
本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。
import pandas as pd
print(pd.__version__)
# 2.1.4
reindex()の基本的な使い方
以下のDataFrame
を例とする。
df = pd.DataFrame({'A': [1, 2, 3], 'B': [10, 20, 30], 'C': [100, 200, 300]},
index=['One', 'Two', 'Three'])
print(df)
# A B C
# One 1 10 100
# Two 2 20 200
# Three 3 30 300
行・列の順番の指定: 引数index, columns
引数index
, columns
にそれぞれ行名・列名を任意の順番に並べたリストを指定すると、その通りに並べ替えられた新たなDataFrame
が返される。同時に指定することも可能。
print(df.reindex(index=['Two', 'Three', 'One']))
# A B C
# Two 2 20 200
# Three 3 30 300
# One 1 10 100
print(df.reindex(columns=['B', 'C', 'A']))
# B C A
# One 10 100 1
# Two 20 200 2
# Three 30 300 3
print(df.reindex(index=['Two', 'Three', 'One'], columns=['B', 'C', 'A']))
# B C A
# Two 20 200 2
# Three 30 300 3
# One 10 100 1
既存の行名・列名を全て使わなくてもよい。
print(df.reindex(columns=['B', 'A'], index=['Three', 'One']))
# B A
# Three 30 3
# One 10 1
第一引数labels
にリスト、引数axis
で行か列かを指定する方法もある。行の場合は0
または'index'
、列の場合は1
または'columns'
とする。
print(df.reindex(['Two', 'Three', 'One'], axis=0))
# A B C
# Two 2 20 200
# Three 3 30 300
# One 1 10 100
print(df.reindex(['B', 'C', 'A'], axis='columns'))
# B C A
# One 10 100 1
# Two 20 200 2
# Three 30 300 3
なお、列の並び替えはdf[列名のリスト]
とすることでも実現可能。
- 関連記事: pandasのインデックス指定で行・列を抽出
print(df[['B', 'C', 'A']])
# B C A
# One 10 100 1
# Two 20 200 2
# Three 30 300 3
reindex()で新たな行名・列名を指定する場合
reindex()
で新たな行名・列名を指定すると、デフォルトではすべての要素が欠損値NaN
として追加される。
df = pd.DataFrame({'A': [1, 2, 3], 'B': [10, 20, 30], 'C': [100, 200, 300]},
index=['One', 'Two', 'Three'])
print(df)
# A B C
# One 1 10 100
# Two 2 20 200
# Three 3 30 300
print(df.reindex(columns=['B', 'X', 'C'], index=['Two', 'One', 'Four']))
# B X C
# Two 20.0 NaN 200.0
# One 10.0 NaN 100.0
# Four NaN NaN NaN
行・列の追加については以下の記事も参照。
任意の値で穴埋め: 引数fill_value
引数fill_value
に任意の値を指定するとその値で穴埋めされる。
print(df.reindex(columns=['B', 'X', 'C'], index=['Two', 'One', 'Four'],
fill_value=0))
# B X C
# Two 20 0 200
# One 10 0 100
# Four 0 0 0
前後の要素の値で穴埋め: 引数method
元のDataFrame
のindex
が単調増加または単調減少である場合は、引数method
を使って前後の要素の値で穴埋めすることも可能。
以下のDataFrame
を例とする。
df = pd.DataFrame({'A': [1, 2], 'B': [10, 20], 'C': [100, 200]},
index=[10, 20])
print(df)
# A B C
# 10 1 10 100
# 20 2 20 200
引数method
を'bfill'
または'backfill'
とすると後方(下)の値、'ffill'
または'pad'
とすると前方(上)の値、'nearest'
とすると近い値(等距離の場合は後方の値)で穴埋めされる。
print(df.reindex(index=[5, 10, 15, 20, 25]))
# A B C
# 5 NaN NaN NaN
# 10 1.0 10.0 100.0
# 15 NaN NaN NaN
# 20 2.0 20.0 200.0
# 25 NaN NaN NaN
print(df.reindex(index=[5, 10, 15, 20, 25], method='bfill'))
# A B C
# 5 1.0 10.0 100.0
# 10 1.0 10.0 100.0
# 15 2.0 20.0 200.0
# 20 2.0 20.0 200.0
# 25 NaN NaN NaN
print(df.reindex(index=[5, 10, 15, 20, 25], method='ffill'))
# A B C
# 5 NaN NaN NaN
# 10 1.0 10.0 100.0
# 15 1.0 10.0 100.0
# 20 2.0 20.0 200.0
# 25 2.0 20.0 200.0
print(df.reindex(index=[5, 10, 15, 20, 25], method='nearest'))
# A B C
# 5 1 10 100
# 10 1 10 100
# 15 2 20 200
# 20 2 20 200
# 25 2 20 200
引数limit
に整数値を指定すると、欠損値NaN
が連続する場合にlimit
個のみ穴埋めされる。
print(df.reindex(index=[10, 12, 14, 16, 18, 20]))
# A B C
# 10 1.0 10.0 100.0
# 12 NaN NaN NaN
# 14 NaN NaN NaN
# 16 NaN NaN NaN
# 18 NaN NaN NaN
# 20 2.0 20.0 200.0
print(df.reindex(index=[10, 12, 14, 16, 18, 20], method='bfill', limit=2))
# A B C
# 10 1.0 10.0 100.0
# 12 NaN NaN NaN
# 14 NaN NaN NaN
# 16 2.0 20.0 200.0
# 18 2.0 20.0 200.0
# 20 2.0 20.0 200.0
引数index
やcolumn
で指定した順番とは関係なく、元のDataFrame
のindex
をもとに値が選択されるので注意。
print(df.reindex(index=[5, 10, 15, 20, 25], method='bfill'))
# A B C
# 5 1.0 10.0 100.0
# 10 1.0 10.0 100.0
# 15 2.0 20.0 200.0
# 20 2.0 20.0 200.0
# 25 NaN NaN NaN
print(df.reindex(index=[25, 20, 15, 10, 5], method='bfill'))
# A B C
# 25 NaN NaN NaN
# 20 2.0 20.0 200.0
# 15 2.0 20.0 200.0
# 10 1.0 10.0 100.0
# 5 1.0 10.0 100.0
その他の穴埋め・補間方法
欠損値NaN
の穴埋めにはfillna()
やffill()
, bfill()
、補間にはinterpolate()
を使う方法もある。
df = pd.DataFrame({'A': [1, 2], 'B': [10, 20], 'C': [100, 200]},
index=[10, 20])
print(df)
# A B C
# 10 1 10 100
# 20 2 20 200
print(df.reindex(index=[5, 10, 15, 20, 25]).bfill())
# A B C
# 5 1.0 10.0 100.0
# 10 1.0 10.0 100.0
# 15 2.0 20.0 200.0
# 20 2.0 20.0 200.0
# 25 NaN NaN NaN
print(df.reindex(index=[5, 10, 15, 20, 25]).interpolate())
# A B C
# 5 NaN NaN NaN
# 10 1.0 10.0 100.0
# 15 1.5 15.0 150.0
# 20 2.0 20.0 200.0
# 25 2.0 20.0 200.0
reindex()
では列を追加した場合に左右の要素からの穴埋めはできないが、fillna()
やffill()
, bfill()
, interpolate()
では可能。
print(df.reindex(columns=['A', 'X', 'C'], method='bfill'))
# A X C
# 10 1 NaN 100
# 20 2 NaN 200
print(df.reindex(columns=['A', 'X', 'C']).bfill(axis=1))
# A X C
# 10 1.0 100.0 100.0
# 20 2.0 200.0 200.0
print(df.reindex(columns=['A', 'X', 'C']).interpolate(axis=1))
# A X C
# 10 1.0 50.5 100.0
# 20 2.0 101.0 200.0
また、上述のように、reindex()
のmethod
で穴埋めできるのは元のindex
が単調増加または単調減少である場合に限られる。以下のような場合はエラーとなる。
df = pd.DataFrame({'A': [1, 2, 3], 'B': [10, 20, 30], 'C': [100, 200, 300]},
index=[20, 10, 30])
print(df)
# A B C
# 20 1 10 100
# 10 2 20 200
# 30 3 30 300
# print(df.reindex(index=[10, 15, 20], method='bfill'))
# ValueError: index must be monotonic increasing or decreasing
fillna()
やffill()
, bfill()
, interpolate()
ならば問題ない。
print(df.reindex(index=[10, 15, 20]))
# A B C
# 10 2.0 20.0 200.0
# 15 NaN NaN NaN
# 20 1.0 10.0 100.0
print(df.reindex(index=[10, 15, 20]).bfill())
# A B C
# 10 2.0 20.0 200.0
# 15 1.0 10.0 100.0
# 20 1.0 10.0 100.0
print(df.reindex(index=[10, 15, 20]).interpolate())
# A B C
# 10 2.0 20.0 200.0
# 15 1.5 15.0 150.0
# 20 1.0 10.0 100.0
なお、fillna()
やffill()
, bfill()
, interpolate()
を用いる場合、一度、欠損値NaN
を含むDataFrame
を経由する。NaN
が含まれるとデータ型dtype
が浮動小数点数float
となるため、上の例のように最終的に全ての値が整数値となってもdtype
はfloat
のまま。要注意。
reindex_like()の使い方
reindex_like()
を使うと、DataFrame
の行・列を別のDataFrame
と同じように並べ替えられる。
以下の2つのDataFrame
を例とする。
df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [10, 20, 30], 'C': [100, 200, 300]},
index=[10, 20, 30])
print(df1)
# A B C
# 10 1 10 100
# 20 2 20 200
# 30 3 30 300
df2 = pd.DataFrame({'A': [1, 1, 1], 'C': [100, 100, 100]},
index=[10, 15, 20])
print(df2)
# A C
# 10 1 100
# 15 1 100
# 20 1 100
reindex()
の引数columns
, index
に対象のDataFrame
のcolumns
, index
属性を指定すると、その通りの順番に並べ替えられたDataFrame
が生成される。
print(df1.reindex(columns=df2.columns, index=df2.index))
# A C
# 10 1.0 100.0
# 15 NaN NaN
# 20 2.0 200.0
同様のことがreindex_like()
を使うとより簡単に実現できる。
print(df1.reindex_like(df2))
# A C
# 10 1.0 100.0
# 15 NaN NaN
# 20 2.0 200.0
reindex_like()
でもindex
が単調増加または単調減少であれば引数method
やlimit
を指定できる。pandasバージョン2.1.4
時点では引数fill_value
は実装されていないが、fillna()
を使えばよい。
print(df1.reindex_like(df2, method='bfill'))
# A C
# 10 1 100
# 15 2 200
# 20 2 200
# print(df1.reindex_like(df2, fill_value=0))
# TypeError: NDFrame.reindex_like() got an unexpected keyword argument 'fill_value'
print(df1.reindex_like(df2).fillna(0))
# A C
# 10 1.0 100.0
# 15 0.0 0.0
# 20 2.0 200.0
時系列データに対するreindex(), reindex_like()
公式ドキュメントの例にもあるが、reindex()
やreindex_like()
は時系列データのindex
を揃えたい場合に便利。
以下のDataFrame
を例とする。pd.date_range()
でDatetimeIndex
を生成している。
df = pd.DataFrame({'A': [1, 3, 5], 'B': [10, 30, 50], 'C': [100, 300, 500]},
index=pd.date_range('2023-12-01', '2023-12-05', freq='2D'))
print(df)
# A B C
# 2023-12-01 1 10 100
# 2023-12-03 3 30 300
# 2023-12-05 5 50 500
print(df.index)
# DatetimeIndex(['2023-12-01', '2023-12-03', '2023-12-05'], dtype='datetime64[ns]', freq='2D')
reindex()
の例。interpolate()
で引数method
を'time'
とすると日時をもとに補間できる。
new_dt_index = pd.date_range('2023-12-01', '2023-12-05', freq='12H')
print(new_dt_index)
# DatetimeIndex(['2023-12-01 00:00:00', '2023-12-01 12:00:00',
# '2023-12-02 00:00:00', '2023-12-02 12:00:00',
# '2023-12-03 00:00:00', '2023-12-03 12:00:00',
# '2023-12-04 00:00:00', '2023-12-04 12:00:00',
# '2023-12-05 00:00:00'],
# dtype='datetime64[ns]', freq='12H')
print(df.reindex(index=new_dt_index))
# A B C
# 2023-12-01 00:00:00 1.0 10.0 100.0
# 2023-12-01 12:00:00 NaN NaN NaN
# 2023-12-02 00:00:00 NaN NaN NaN
# 2023-12-02 12:00:00 NaN NaN NaN
# 2023-12-03 00:00:00 3.0 30.0 300.0
# 2023-12-03 12:00:00 NaN NaN NaN
# 2023-12-04 00:00:00 NaN NaN NaN
# 2023-12-04 12:00:00 NaN NaN NaN
# 2023-12-05 00:00:00 5.0 50.0 500.0
print(df.reindex(index=new_dt_index, method='ffill'))
# A B C
# 2023-12-01 00:00:00 1 10 100
# 2023-12-01 12:00:00 1 10 100
# 2023-12-02 00:00:00 1 10 100
# 2023-12-02 12:00:00 1 10 100
# 2023-12-03 00:00:00 3 30 300
# 2023-12-03 12:00:00 3 30 300
# 2023-12-04 00:00:00 3 30 300
# 2023-12-04 12:00:00 3 30 300
# 2023-12-05 00:00:00 5 50 500
print(df.reindex(index=new_dt_index).interpolate(method='time'))
# A B C
# 2023-12-01 00:00:00 1.0 10.0 100.0
# 2023-12-01 12:00:00 1.5 15.0 150.0
# 2023-12-02 00:00:00 2.0 20.0 200.0
# 2023-12-02 12:00:00 2.5 25.0 250.0
# 2023-12-03 00:00:00 3.0 30.0 300.0
# 2023-12-03 12:00:00 3.5 35.0 350.0
# 2023-12-04 00:00:00 4.0 40.0 400.0
# 2023-12-04 12:00:00 4.5 45.0 450.0
# 2023-12-05 00:00:00 5.0 50.0 500.0
新しいインデックスとして文字列のリストなどを指定すると、reindex()
が返すDataFrame
のindex
はノーマルのIndex
となり時系列データではなくなるので注意。interpolate(method='time')
はDatetimeIndex
のDataFrame
でのみ実行可能。
new_index = ['2023-12-01', '2023-12-02', '2023-12-03']
print(df.reindex(index=new_index))
# A B C
# 2023-12-01 1.0 10.0 100.0
# 2023-12-02 NaN NaN NaN
# 2023-12-03 3.0 30.0 300.0
print(df.reindex(index=new_index).index)
# Index(['2023-12-01', '2023-12-02', '2023-12-03'], dtype='object')
print(df.reindex(index=new_index, method='bfill'))
# A B C
# 2023-12-01 1 10 100
# 2023-12-02 3 30 300
# 2023-12-03 3 30 300
# print(df.reindex(index=new_index).interpolate(method='time'))
# ValueError: time-weighted interpolation only works on Series or DataFrames with a DatetimeIndex
reindex_like()
の例は以下の通り。
df2 = pd.DataFrame({'A': [1, 1, 1, 1, 1], 'C': [100, 100, 100, 100, 100]},
index=pd.date_range('2023-12-01', '2023-12-05', freq='D'))
print(df2)
# A C
# 2023-12-01 1 100
# 2023-12-02 1 100
# 2023-12-03 1 100
# 2023-12-04 1 100
# 2023-12-05 1 100
print(df.reindex_like(df2))
# A C
# 2023-12-01 1.0 100.0
# 2023-12-02 NaN NaN
# 2023-12-03 3.0 300.0
# 2023-12-04 NaN NaN
# 2023-12-05 5.0 500.0
print(df.reindex_like(df2).interpolate(method='time'))
# A C
# 2023-12-01 1.0 100.0
# 2023-12-02 2.0 200.0
# 2023-12-03 3.0 300.0
# 2023-12-04 4.0 400.0
# 2023-12-05 5.0 500.0
時系列データのリサンプリングについては以下の記事も参照。