1
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が返る

Posted at

環境

  • Python 3.12.4
  • pandas 2.2.3
  • numpy 1.26.4

「Copy-on-Write」で分からなかったこと

pandasの「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は"only one NumPy array"を含んでいる

分かったこと

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列はint64, b列はfloat64)"more than one array"を含んでいました。

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

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個でした。

再度確認する

複数の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`はメモリを共有していないことの確認
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]])

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

補足

mode.copy_on_write = "warn"を指定しても「Read-only NumPy arrays」にならない

pd.options.mode.copy_on_write = "warn"を指定した場合、to_numpy()が返すarrayは書き換え可能です。

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
  1. https://pandas.pydata.org/docs/user_guide/basics.html#attributes-and-underlying-data 引用

1
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
1
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?