5

numpy で構造化配列を使用していくつかの作業を行っています (最終的には pandas データフレームに変換します)。

ここで、いくつかのデータを読み取り (実際には一部のデータをメマッピングします)、ユーザー指定の制約でフィルター処理することにより、この構造化配列を生成します。次に、このデータを、読み取った形式 (読み取り元のファイルのスペースを節約するためにすべてが int である) から、より使いやすい形式に変換して、いくつかの単位変換を行うことができるようにします (つまり、にアップコンバートします)。フロート)。

構造化されたデータ型を変更する途中で、興味深い成果物 (または何か) に気付きました。データを読み取ると、次によって作成されるのと同じ構造化配列が得られるとします (実際のコードでは、dtype ははるかに長く複雑ですが、mwe にはこれで十分です)。

import numpy as np

names = ['foo', 'bar']
formats = ['i4', 'i4']

dtype = np.dtype({'names': names, 'formats': formats})

data = np.array([(1, 2), (3, 4)], dtype=dtype)
print(data)
print(data.dtype)

これにより、

[(1, 2) (3, 4)]
[('foo', '<i4'), ('bar', '<i4')]

構造化配列として

ここで、2 番目のコンポーネントの名前を変更しながら、これらの dtype の両方を double にアップコンバートしたいとします。それは簡単なはずです

names[1] = 'baz'

formats[0] = np.float
formats[1] = np.float

dtype_new = np.dtype({'names': names, 'formats': formats})

data2 = data.copy().astype(dtype_new)

print(data2)
print(data2.dtype)

しかし結果は予想外

(1.0, 0.0) (3.0, 0.0)]
[('foo', '<f8'), ('baz', '<f8')]

2 番目のコンポーネントのデータはどうなりましたか? この変換を行うことができますが、物事を分割すると

dtype_new3 = np.dtype({'names': names, 'formats': formats})

data3 = data.copy().astype(dtype_new3)

print(data3)
print(data3.dtype)

names[1] = 'baz'
data4 = data3.copy()
data4.dtype.names = names

print(data4)
print(data4.dtype)

その結果、正しい出力が得られます

[(1.0, 2.0) (3.0, 4.0)]
[('foo', '<f8'), ('bar', '<f8')]
[(1.0, 2.0) (3.0, 4.0)]
[('foo', '<f8'), ('baz', '<f8')]

astype構造化された dtype で呼び出されると、numpy は各コンポーネントの名前を照合し、指定された型をコンテンツに適用するようです (ここで推測するだけで、ソース コードを見ていません)。この変換をすべて一度に行う方法はありますか (つまり、形式の名前とアップコンバージョン)、それとも単に手順を実行する必要がありますか? (段階的に行う必要がある場合は大したことではありませんが、これを行うための単一のステップの方法がないのは奇妙に思えます。)

4

2 に答える 2

5

recarray(したがって、構造化された配列) で動作するように設計された関数のライブラリがあります。隠れているので探してみようと思います。フィールドの名前変更、フィールドの追加と削除などの機能があります。アクションの一般的なパターンは、ターゲット dtype で新しい配列を作成し、フィールドを 1 つずつコピーすることです。通常、配列には多くの要素と少数のフィールドがあるため、これによって速度が大幅に低下することはありません。

このastypeメソッドは、そのコードの一部、または同じように動作するコンパイル済みコードを使用しているようです。

そうです、フィールドの dtype と名前を別々の手順で変更する必要があるようです。

In [1279]: data=np.array([(1,2),(3,4)],dtype='i,i')
In [1280]: data
Out[1280]: 
array([(1, 2), (3, 4)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])
In [1281]: dataf=data.astype('f8,f8')     # change dtype, same default names
In [1282]: dataf
Out[1282]: 
array([(1.0, 2.0), (3.0, 4.0)], 
      dtype=[('f0', '<f8'), ('f1', '<f8')])

簡単な名前変更:

In [1284]: dataf.dtype.names=['one','two'] 
In [1285]: dataf
Out[1285]: 
array([(1.0, 2.0), (3.0, 4.0)], 
      dtype=[('one', '<f8'), ('two', '<f8')])

In [1286]: data.astype(dataf.dtype)
Out[1286]: 
array([(0.0, 0.0), (0.0, 0.0)], 
      dtype=[('one', '<f8'), ('two', '<f8')])

名前astypeが一致しない はzero、 と同様に配列を生成しnp.zeros(data.shape,dataf.dtype)ます。dtype 内の位置ではなく名前を一致させることで、値を並べ替えたり、フィールドを追加したりできます。

In [1291]: data.astype([('f1','f8'),('f0','f'),('f3','i')])
Out[1291]: 
array([(2.0, 1.0, 0), (4.0, 3.0, 0)], 
      dtype=[('f1', '<f8'), ('f0', '<f4'), ('f3', '<i4')])
于 2016-08-12T16:41:58.030 に答える