2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

すべての列でdtypeが同じであるDataFrameに対して、`to_numpy()`を実行すると、DataFrameとメモリを共有しているnumpy arrayが返る

Last updated at Posted at 2024-11-21

環境

  • Python 3.12.4
  • pandas 2.2.3
  • numpy 1.26.4

Pandasの Copy-on-Write で分からなかったこと

Copy-on-Writeの「Read-only NumPy arrays」に関して、以下の内容が理解できませんでした。

The array is a copy if the initial DataFrame consists of more than one array:

In [49]: df = pd.DataFrame({"a": [1, 2], "b": [1.5, 2.5]})

In [50]: df.to_numpy()
Out[50]: 
array([[1. , 1.5],
       [2. , 2.5]])

The array shares data with the DataFrame if the DataFrame consists of only one NumPy array:

In [51]: df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})

In [52]: df.to_numpy()
Out[52]: 
array([[1, 3],
       [2, 4]])

上記の文章を読んで、以下の疑問が発生しました。

  • なぜIn [49]のDataFrameは複数の配列("more than one array")を含んでいるのか?
  • なぜIn [51]のDataFrameは1個のNumPy配列("only one NumPy array")を含んでいるのか?
  • DataFrameが含んでいる配列を、どのように確認できるのか?

分かったこと

DataFrameはすべての列でdtypeが同じ場合、1個のnumpy arrrayを保持しているようです。

When your DataFrame only has a single data type for all the columns, DataFrame.to_numpy() will return the underlying data: 1

In [49]のDataFrameは、各列でdtypeが異なるため(a列のdtypeはint64b列のdtypeはfloat64)"more than one array"を含んでいました。

保持しているnumpy arrayの構成は、DataFrame._mgrプロパティで確認できました。

In [490]: df1 = pd.DataFrame({"a": [1, 2], "b": [1.5, 2.5]})

In [491]: df1.dtypes
Out[491]:
a      int64
b    float64
dtype: object

In [493]: df1._mgr
Out[493]:
BlockManager
Items: Index(['a', 'b'], dtype='object')
Axis 1: RangeIndex(start=0, stop=2, step=1)
NumpyBlock: slice(0, 1, 1), 1 x 2, dtype: int64
NumpyBlock: slice(1, 2, 1), 1 x 2, dtype: float64

In [494]: df2 = pd.DataFrame({"a": [1, 2], "b": [3, 4]})

In [495]: df2.dtypes
Out[495]:
a    int64
b    int64
dtype: object

In [496]: df2._mgr
Out[496]:
BlockManager
Items: Index(['a', 'b'], dtype='object')
Axis 1: RangeIndex(start=0, stop=2, step=1)
NumpyBlock: slice(0, 2, 1), 2 x 2, dtype: int64

df1._mgrではNumpyBlockが2個あるのに対して、df2._mgrではNumpyBlockは1個でした。

再度確認する

「Read-only NumPy arrays」に書かれている内容が理解できたところで、再度挙動を確認しました。

複数のnumpy arrayを含むDataFrameの場合

In [499]: pd.options.mode.copy_on_write = True

In [500]: df1 = pd.DataFrame({"a": [1, 2], "b": [1.5, 2.5]})

In [501]: arr1 = df1.to_numpy()

# `df1`と`arr1`はメモリを共有していない(`arr1`は`df1`のコピー)ことの確認
In [502]: np.shares_memory(df1, arr1)
Out[502]: False

# `arr1`は書き換え可能であることの確認
In [513]: arr1.flags.writeable
Out[513]: True

In [507]: arr1[(0,0)]
Out[507]: 1.0

In [508]: arr1[(0,0)] = 100

In [509]: arr1
Out[509]:
array([[100. ,   1.5],
       [  2. ,   2.5]])

# `arr1`を書き換えても`df1`は変更されない
In [510]: df1
Out[510]:
   a    b
0  1  1.5
1  2  2.5

arr1df1のコピーなので、arr1を書き換えてもdf1は変更されないことを確認できました。

1個のnumpy arrayを含むDataFrameの場合

In [514]: pd.options.mode.copy_on_write = True

In [515]: df2 = pd.DataFrame({"a": [1, 2], "b": [3, 4]})

In [516]: arr2 = df2.to_numpy()

# `df2`と`arr2`はメモリを共有していることの確認
In [517]: np.shares_memory(df2, arr2)
Out[517]: True

# `arr1`は書き換え不可であることの確認
In [518]: arr2.flags.writeable
Out[518]: False

In [520]: arr2[(0,0)] = 100
---------------------------------------------------------------------------
ValueError: assignment destination is read-only

arr2は書き込み不可なので、arr2を書き込もうとするとValueErrorが発生することを確認できました。

補足

mode.copy_on_write = "warn"を設定したときの挙動

pd.options.mode.copy_on_write = "warn"を設定すると、Copy-on-Writeの振る舞いが変わった操作に警告が発生します。

that will warn for every operation that will change behavior with CoW. 2

しかし、1個のnumpy arrayを含むDataFrameに対してto_numpy()を実行した場合は、警告は発生しません。
(Copyしていないから?)

In [537]: pd.options.mode.copy_on_write = "warn"

In [538]: df2 = pd.DataFrame({"a": [1, 2], "b": [3, 4]})

In [539]: arr2 = df2.to_numpy()

In [540]: arr2.flags.writeable
Out[540]: True

DataFrame.to_numpy()を利用しているコードでは、一度pd.options.mode.copy_on_write = Trueを設定して、「読み込み専用のnumpy arrayに書き込もうとしてValueErrorが発生していないか」を確認した方がよいかもしれません。

  1. https://pandas.pydata.org/docs/user_guide/basics.html#attributes-and-underlying-data 引用

  2. https://pandas.pydata.org/docs/user_guide/copy_on_write.html#migrating-to-copy-on-write 引用

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?