pandas.DataFrame, SeriesとNumPy配列ndarrayを相互に変換
pandasのDataFrame
, Series
とNumPy配列ndarray
を相互に変換する方法を説明する。
DataFrame
, Series
をndarray
に変換するにはto_numpy()
メソッドかvalues
属性、ndarray
をDataFrame
, Series
に変換するにはそれぞれのコンストラクタを使う。
DataFrame
, Series
とPython組み込みのリスト型list
の相互変換、DataFrame
とSeries
の相互変換については以下の記事を参照。
本記事のサンプルコードのpandasとNumPyのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。
import pandas as pd
import numpy as np
print(pd.__version__)
# 2.1.4
print(np.__version__)
# 1.26.2
pandasのDataFrame, SeriesをNumPy配列ndarrayに変換
DataFrame
, Series
をndarray
に変換するには、to_numpy()
メソッドかvalues
属性を使う。
to_numpy()メソッド
DataFrame
, Series
のto_numpy()
メソッドでNumPy配列ndarray
に変換できる。
- pandas.DataFrame.to_numpy — pandas 2.1.4 documentation
- pandas.Series.to_numpy — pandas 2.1.4 documentation
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]}, index=['X', 'Y'])
print(df)
# A B
# X 1 3
# Y 2 4
print(df.to_numpy())
# [[1 3]
# [2 4]]
print(type(df.to_numpy()))
# <class 'numpy.ndarray'>
s = df['A']
print(s)
# X 1
# Y 2
# Name: A, dtype: int64
print(s.to_numpy())
# [1 2]
print(type(s.to_numpy()))
# <class 'numpy.ndarray'>
行名index
や列名columns
は無視され、データ列のみが変換される。index
をデータとして扱いたい場合はreset_index()
を使う。
以下、DataFrame
を例とするが、引数などの基本的な使い方はSeries
の場合も同じ。
データ型の指定: 引数dtype
DataFrame
の各列のデータ型dtype
が同じ場合、そのデータ型のndarray
が生成される。
df_int = pd.DataFrame({'A': [1, 2], 'B': [3, 4]}, index=['X', 'Y'])
print(df_int)
# A B
# X 1 3
# Y 2 4
print(df_int.dtypes)
# A int64
# B int64
# dtype: object
print(df_int.to_numpy())
# [[1 3]
# [2 4]]
print(df_int.to_numpy().dtype)
# int64
DataFrame
の各列のデータ型dtype
が異なる場合、型変換できる共通の型のndarray
が生成される。例えば整数int
と浮動小数点数float
の列が混在するDataFrame
は、float
型のndarray
に変換される。
df_int_float = pd.DataFrame({'A': [1, 2], 'B': [0.1, 0.2]}, index=['X', 'Y'])
print(df_int_float)
# A B
# X 1 0.1
# Y 2 0.2
print(df_int_float.dtypes)
# A int64
# B float64
# dtype: object
print(df_int_float.to_numpy())
# [[1. 0.1]
# [2. 0.2]]
print(df_int_float.to_numpy().dtype)
# float64
型変換できる共通の型が無い場合、例えば数値と文字列の列が混在するDataFrame
は、object
型のndarray
となる。object
型では要素がそれぞれの型を持つ。
df_int_str = pd.DataFrame({'A': [1, 2], 'B': ['abc', 'xyz']}, index=['X', 'Y'])
print(df_int_str)
# A B
# X 1 abc
# Y 2 xyz
print(df_int_str.dtypes)
# A int64
# B object
# dtype: object
print(df_int_str.to_numpy())
# [[1 'abc']
# [2 'xyz']]
print(df_int_str.to_numpy().dtype)
# object
print(df_int_str.to_numpy()[0, 0])
# 1
print(type(df_int_str.to_numpy()[0, 0]))
# <class 'int'>
print(df_int_str.to_numpy()[0, 1])
# abc
print(type(df_int_str.to_numpy()[0, 1]))
# <class 'str'>
to_numpy()
の引数dtype
にデータ型を指定可能。変換できない型を指定するとエラーになる。
print(df_int_float.to_numpy(dtype='float32'))
# [[1. 0.1]
# [2. 0.2]]
print(df_int_float.to_numpy(dtype=int))
# [[1 0]
# [2 0]]
# print(df_int_str.to_numpy(dtype=int))
# ValueError: invalid literal for int() with base 10: 'abc'
pandasおよびNumPyのデータ型についての詳細は以下の記事を参照。
DataFrame
の特定のデータ型の列のみndarray
に変換したい場合はselect_dtypes()
を使う。数値列のみを抽出することも可能。
df_int_float_str = pd.DataFrame({'A': [1, 2], 'B': [0.1, 0.2], 'C': ['abc', 'xyz']}, index=['X', 'Y'])
print(df_int_float_str)
# A B C
# X 1 0.1 abc
# Y 2 0.2 xyz
print(df_int_float_str.select_dtypes('number').to_numpy())
# [[1. 0.1]
# [2. 0.2]]
コピーを生成するか指定: 引数copy
デフォルトではto_numpy()
は可能な限りビューを生成する。生成されたndarray
が元のDataFrame
のビューの場合、二つのオブジェクトはメモリを共有し、一方を変更すると他方も変更される。
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]}, index=['X', 'Y'])
a = df.to_numpy()
print(np.shares_memory(df, a))
# True
a[0, 0] = 100
print(a)
# [[100 3]
# [ 2 4]]
print(df)
# A B
# X 100 3
# Y 2 4
to_numpy()
の引数copy
をTrue
とするとコピーが生成され、メモリを共有しない。
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]}, index=['X', 'Y'])
a_copy = df.to_numpy(copy=True)
print(np.shares_memory(df, a_copy))
# False
a_copy[0, 0] = 100
print(a_copy)
# [[100 3]
# [ 2 4]]
print(df)
# A B
# X 1 3
# Y 2 4
copy=True
は必ずコピーを返すが、copy=False
(デフォルト)は必ずビューを返すとは限らないので注意。例えば、DataFrame
の各列のデータ型dtype
が異なる場合はビューが生成できずコピーが生成される。
df_int_float = pd.DataFrame({'A': [1, 2], 'B': [0.1, 0.2]}, index=['X', 'Y'])
a_float = df_int_float.to_numpy()
print(np.shares_memory(df_int_float, a_float))
# False
pandasおよびNumPyにおけるビューとコピーについての詳細は以下の記事を参照。
values属性
DataFrame
, Series
のvalues
属性でもNumPy配列ndarray
に変換できる。
- pandas.DataFrame.values — pandas 2.1.4 documentation
- pandas.Series.values — pandas 2.1.4 documentation
公式ドキュメントではto_numpy()
メソッドの使用が推奨されているが、pandas 2.1.4時点ではvalues
属性を使っても警告などは出ない。
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]}, index=['X', 'Y'])
print(df)
# A B
# X 1 3
# Y 2 4
print(df.values)
# [[1 3]
# [2 4]]
print(type(df.values))
# <class 'numpy.ndarray'>
s = df['A']
print(s)
# X 1
# Y 2
# Name: A, dtype: int64
print(s.values)
# [1 2]
print(type(s.values))
# <class 'numpy.ndarray'>
values
属性の動作はto_numpy()
のデフォルトの動作と同じ。
DataFrame
の各列のデータ型dtype
が異なる場合は型変換できる共通の型のndarray
が生成され、型変換できる共通の型が無い場合はobject
型のndarray
が生成される。
df_int_float = pd.DataFrame({'A': [1, 2], 'B': [0.1, 0.2]}, index=['X', 'Y'])
print(df_int_float.values)
# [[1. 0.1]
# [2. 0.2]]
print(df_int_float.values.dtype)
# float64
df_int_str = pd.DataFrame({'A': [1, 2], 'B': ['abc', 'xyz']}, index=['X', 'Y'])
print(df_int_str.values)
# [[1 'abc']
# [2 'xyz']]
print(df_int_str.values.dtype)
# object
可能な限りビューを生成するが、ビューを生成できない場合はコピーが生成される。
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]}, index=['X', 'Y'])
print(np.shares_memory(df, df.values))
# True
df_int_float = pd.DataFrame({'A': [1, 2], 'B': [0.1, 0.2]}, index=['X', 'Y'])
print(np.shares_memory(df_int_float, df_int_float.values))
# False
必ずコピーを生成するにはcopy()
を使う。
print(np.shares_memory(df, df.values.copy()))
# False
NumPy配列ndarrayをpandasのDataFrame, Seriesに変換
ndarray
をDataFrame
, Series
に変換するにはそれぞれのコンストラクタを使う。コンストラクタの第一引数data
にndarray
を指定できる。
pandas.DataFrame()
コンストラクタpd.DataFrame()
の第一引数data
にndarray
を指定してDataFrame
を生成できる。
a_2d = np.array([[1, 2], [3, 4]])
print(a_2d)
# [[1 2]
# [3 4]]
print(pd.DataFrame(a_2d))
# 0 1
# 0 1 2
# 1 3 4
一次元配列の場合は一列のDataFrame
が生成されるが、三次元以上の場合はエラーになる。
a_1d = np.array([1, 2])
print(a_1d)
# [1 2]
print(pd.DataFrame(a_1d))
# 0
# 0 1
# 1 2
a_3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print(a_3d)
# [[[1 2]
# [3 4]]
#
# [[5 6]
# [7 8]]]
# print(pd.DataFrame(a_3d))
# ValueError: Must pass 2-d input. shape=(2, 2, 2)
行名index
や列名columns
、データ型dtype
などを引数で指定可能。
print(pd.DataFrame(data=a_2d, index=['X', 'Y'], columns=['A', 'B'], dtype=float))
# A B
# X 1.0 2.0
# Y 3.0 4.0
コンストラクタpd.DataFrame()
の詳細は以下の記事を参照。
ビューとコピー(メモリの共有)
第一引数data
にndarray
を指定する場合、デフォルトではpd.DataFrame()
は可能な限りビューを生成する。生成されたDataFrame
が元のndarray
のビューの場合、二つのオブジェクトはメモリを共有し、一方を変更すると他方も変更される。
a = np.array([[1, 2], [3, 4]])
df = pd.DataFrame(a)
print(np.shares_memory(a, df))
# True
a[0, 0] = 100
print(a)
# [[100 2]
# [ 3 4]]
print(df)
# 0 1
# 0 100 2
# 1 3 4
pd.DataFrame()
の引数copy
をTrue
とするとコピーを生成する。
a = np.array([[1, 2], [3, 4]])
df_copy = pd.DataFrame(a, copy=True)
print(np.shares_memory(a, df_copy))
# False
a[0, 0] = 100
print(a)
# [[100 2]
# [ 3 4]]
print(df_copy)
# 0 1
# 0 1 2
# 1 3 4
copy=True
は必ずコピーを返すが、copy=False
(ndarray
を指定したときのデフォルト)は必ずビューを返すとは限らないので注意。例えば、引数dtype
を指定して型が変換される場合はビューが生成できずコピーが生成される。
a = np.array([[1, 2], [3, 4]])
df_float = pd.DataFrame(a, dtype=float)
print(np.shares_memory(a, df_float))
# False
pandas.Series()
コンストラクタpd.Series()
も基本的な使い方はpd.DataFrame()
と同じ。
第一引数data
に一次元のndarray
を指定してSeries
を生成できる。
a_1d = np.array([1, 2])
print(a_1d)
# [1 2]
print(pd.Series(a_1d))
# 0 1
# 1 2
# dtype: int64
二次元以上の場合はエラー。
a_2d = np.array([[1, 2], [3, 4]])
print(a_2d)
# [[1 2]
# [3 4]]
# print(pd.Series(a_2d))
# ValueError: Data must be 1-dimensional, got ndarray of shape (2, 2) instead
ラベルindex
や名前name
、データ型dtype
などを引数で指定可能。
print(pd.Series(a_1d, index=['A', 'B'], name='my_series', dtype=float))
# A 1.0
# B 2.0
# Name: my_series, dtype: float64
ビューとコピー(メモリの共有)についてもpd.DataFrame()
と同様。
デフォルトではpd.Series()
は可能な限りビューを生成し、引数copy
をTrue
とするとコピーを生成する。copy=False
(デフォルト)は必ずビューを返すとは限らず、例えば引数dtype
を指定して型が変換される場合はビューが生成できずコピーが生成される。
a = np.array([1, 2])
print(np.shares_memory(a, pd.Series(a)))
# True
print(np.shares_memory(a, pd.Series(a, copy=True)))
# False
print(np.shares_memory(a, pd.Series(a, dtype=float)))
# False