pandas.DataFrameの行と列を入れ替える(転置)
pandas.DataFrame
の行と列を入れ替える(=転置する)には、T
属性かtranspose()
メソッドを使う。
どちらの方法も元のオブジェクトは変更されず、行と列が入れ替わった(=転置された)新たなオブジェクトが返される。各列のデータ型dtype
によってはコピーではなくビューが生成され、元のオブジェクトと転置されたオブジェクトの一方の値を変更するともう一方の値も変更されるので注意。
NumPy配列ndarray
や二次元リスト(リストのリスト)の転置については以下の記事を参照。
本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。
import pandas as pd
print(pd.__version__)
# 2.0.3
pandas.DataFrame.T
T
属性で転置したpandas.DataFrame
を取得できる。
df = pd.DataFrame({'X': [0, 1, 2], 'Y': [3, 4, 5]}, index=['A', 'B', 'C'])
print(df)
# X Y
# A 0 3
# B 1 4
# C 2 5
print(df.T)
# A B C
# X 0 1 2
# Y 3 4 5
pandas.DataFrame.transpose()
transpose()
メソッドでも転置したpandas.DataFrame
を取得できる。
df = pd.DataFrame({'X': [0, 1, 2], 'Y': [3, 4, 5]}, index=['A', 'B', 'C'])
print(df)
# X Y
# A 0 3
# B 1 4
# C 2 5
print(df.transpose())
# A B C
# X 0 1 2
# Y 3 4 5
元のオブジェクト自体を変更
元のオブジェクト自体を変更するinplace
のような引数は用意されていない。元のオブジェクト自体に代入すればよい。
df = pd.DataFrame({'X': [0, 1, 2], 'Y': [3, 4, 5]}, index=['A', 'B', 'C'])
print(df)
# X Y
# A 0 3
# B 1 4
# C 2 5
df = df.T
print(df)
# A B C
# X 0 1 2
# Y 3 4 5
型変換(キャスト)が行われる場合
pandas.DataFrame
は各列ごとにデータ型dtype
が設定されている。
すべての列が同じデータ型の場合はT
やtranspose()
で転置してもそのままのデータ型。
df = pd.DataFrame({'X': [0, 1, 2], 'Y': [3, 4, 5]}, index=['A', 'B', 'C'])
print(df)
# X Y
# A 0 3
# B 1 4
# C 2 5
print(df.dtypes)
# X int64
# Y int64
# dtype: object
print(df.T)
# A B C
# X 0 1 2
# Y 3 4 5
print(df.T.dtypes)
# A int64
# B int64
# C int64
# dtype: object
各列が異なるデータ型だと型変換(キャスト)が行われる。例えば、転置した結果、整数int
と浮動小数点数float
が混在する列が生じると、その列のデータ型はfloat
となる。
df_mix = pd.DataFrame({'col_int': [0, 1, 2], 'col_float': [0.1, 0.2, 0.3]}, index=['A', 'B', 'C'])
print(df_mix)
# col_int col_float
# A 0 0.1
# B 1 0.2
# C 2 0.3
print(df_mix.dtypes)
# col_int int64
# col_float float64
# dtype: object
print(df_mix.T)
# A B C
# col_int 0.0 1.0 2.0
# col_float 0.1 0.2 0.3
print(df_mix.T.dtypes)
# A float64
# B float64
# C float64
# dtype: object
再度転置しても元には戻らない。データ型を変換するにはastype()
を適用する必要がある。
print(df_mix.T.T)
# col_int col_float
# A 0.0 0.1
# B 1.0 0.2
# C 2.0 0.3
print(df_mix.T.T.dtypes)
# col_int float64
# col_float float64
# dtype: object
文字列str
などが要素である列はオブジェクト型となる。
df_mix2 = pd.DataFrame({'col_int': [0, 1, 2], 'col_float': [0.1, 0.2, 0.3], 'col_str': ['a', 'b', 'c']},
index=['A', 'B', 'C'])
print(df_mix2)
# col_int col_float col_str
# A 0 0.1 a
# B 1 0.2 b
# C 2 0.3 c
print(df_mix2.dtypes)
# col_int int64
# col_float float64
# col_str object
# dtype: object
print(df_mix2.T)
# A B C
# col_int 0 1 2
# col_float 0.1 0.2 0.3
# col_str a b c
print(df_mix2.T.dtypes)
# A object
# B object
# C object
# dtype: object
print(df_mix2.T.T)
# col_int col_float col_str
# A 0 0.1 a
# B 1 0.2 b
# C 2 0.3 c
print(df_mix2.T.T.dtypes)
# col_int object
# col_float object
# col_str object
# dtype: object
ビューとコピー
すべての列のデータ型が同じである場合、T
やtranspose()
はビューを返す。元のオブジェクトとビューはメモリを共有するので、一方の要素を変更するともう一方も変更される。
df = pd.DataFrame({'X': [0, 1, 2], 'Y': [3, 4, 5]}, index=['A', 'B', 'C'])
print(df)
# X Y
# A 0 3
# B 1 4
# C 2 5
df_T = df.T
print(df_T)
# A B C
# X 0 1 2
# Y 3 4 5
df_transpose = df.transpose()
print(df_transpose)
# A B C
# X 0 1 2
# Y 3 4 5
df.at['A', 'X'] = 100
print(df)
# X Y
# A 100 3
# B 1 4
# C 2 5
print(df_T)
# A B C
# X 100 1 2
# Y 3 4 5
print(df_transpose)
# A B C
# X 100 1 2
# Y 3 4 5
列ごとにデータ型dtype
が異なる場合、T
やtranspose()
はコピーを生成する。転置されたオブジェクトは新たなメモリ領域を確保するので、一方の値を変更してももう一方はそのまま。
df_mix = pd.DataFrame({'col_int': [0, 1, 2], 'col_float': [0.1, 0.2, 0.3]}, index=['A', 'B', 'C'])
print(df_mix)
# col_int col_float
# A 0 0.1
# B 1 0.2
# C 2 0.3
df_mix_T = df_mix.T
print(df_mix_T)
# A B C
# col_int 0.0 1.0 2.0
# col_float 0.1 0.2 0.3
df_mix_transpose = df_mix.transpose()
print(df_mix_transpose)
# A B C
# col_int 0.0 1.0 2.0
# col_float 0.1 0.2 0.3
df_mix.at['A', 'col_int'] = 100
print(df_mix)
# col_int col_float
# A 100 0.1
# B 1 0.2
# C 2 0.3
print(df_mix_T)
# A B C
# col_int 0.0 1.0 2.0
# col_float 0.1 0.2 0.3
print(df_mix_transpose)
# A B C
# col_int 0.0 1.0 2.0
# col_float 0.1 0.2 0.3
その後の処理で転置した方しか使わないのであれば特に気にしなくてもよいが、すべての列のデータ型が同じ場合に元のオブジェクトと転置したオブジェクトを別々に扱いたい場合、T
ではcopy()
で明示的にコピーを生成する。transpose()
では引数copy
をTrue
とするとコピーが生成される。
df = pd.DataFrame({'X': [0, 1, 2], 'Y': [3, 4, 5]}, index=['A', 'B', 'C'])
print(df)
# X Y
# A 0 3
# B 1 4
# C 2 5
df_T_copy = df.T.copy()
print(df_T_copy)
# A B C
# X 0 1 2
# Y 3 4 5
df_transpose_copy = df.transpose(copy=True)
print(df_transpose_copy)
# A B C
# X 0 1 2
# Y 3 4 5
df.at['A', 'X'] = 100
print(df)
# X Y
# A 100 3
# B 1 4
# C 2 5
print(df_T_copy)
# A B C
# X 0 1 2
# Y 3 4 5
print(df_transpose_copy)
# A B C
# X 0 1 2
# Y 3 4 5
transpose()
の引数copy
のデフォルトはFalse
で、可能な限りビューを生成する。上の例のように列ごとにデータ型dtype
が異なるときはデフォルト(copy=False
)であってもコピーが生成される。必ずビューとなるわけではない。