web-dev-qa-db-ja.com

NumPy配列/混合型の行列

私はNumPy配列/行列(Nx3)を混合データ型(文字列、整数、整数)で作成しようとしています。しかし、データを追加してこのマトリックスを追加すると、エラーが発生します:TypeError:無効な型の昇格。誰か、私がこの問題を解決するのを手伝ってくれる?

サンプルデータを含む配列を作成すると、NumPyは行列のすべての列を1つの 'S'データ型にキャストします。そして、配列のデータ型を指定することはできません。これを行うとres = np.array(["TEXT"、1、1]、dtype = 'S、i4、i4')になるためです。 -エラーが表示されます:TypeError:読み取り可能なバッファオブジェクトが必要です

templates.py

import numpy as np
from pprint import pprint

test_array = np.zeros((0, 3), dtype='S, i4, i4')
pprint(test_array)

test_array = np.append(test_array, [["TEXT", 1, 1]], axis=0)
pprint(test_array)

print("Array example:")
res = np.array(["TEXT", 1, 1])
pprint(res)

出力:

array([], shape=(0L, 3L), 
  dtype=[('f0', 'S'), ('f1', '<i4'), ('f2', '<i4')])

 Array example:
 array(['TEXT', '1', '1'], dtype='|S4')

エラー:

Traceback (most recent call last):

File "templates.py", line 5, in <module>
test_array = np.append(test_array, [["TEXT", 1, 1]], axis=0)

File "lib\site-packages\numpy\lib\function_base.py", line 3543, in append
return concatenate((arr, values), axis=axis)

TypeError: invalid type promotion
11
Vit D

問題はデータにあります。これを試して:

res = np.array(("TEXT", 1, 1), dtype='|S4, i4, i4')

または

res = np.array([("TEXT", 1, 1), ("XXX", 2, 2)], dtype='|S4, i4, i4')

データはタプルまたはタプルのリストでなければなりません。エラーメッセージからは明らかではないでしょうか?

また、テキストデータを実際に保存するには、テキストフィールドの長さを指定する必要があることに注意してください。テキストをオブジェクト(配列内の参照のみ)として保存する場合:

res = np.array([("TEXT", 1, 1), ("XXX", 2, 2)], dtype='object, i4, i4')

これも非常に便利です。

9
DrV

Numpyと結婚していない場合は、 pandas DataFrame が最適です。または、配列の文字列フィールドをpythonオブジェクト(例としてdtype = 'O、i4、i4')として指定できます。また、追加はリストではなくタプルのリストのように見えますリストの可変性と関係があると思いますが、よくわかりません。

4
sirlark

まず、numpyは固定物理レコードサイズを使用して配列要素を格納します。したがって、レコードオブジェクトはすべて同じ物理サイズである必要があります。このため、numpyに文字列のサイズを通知するか、別の場所に格納されている文字列へのポインタを保存する必要があります。レコード配列では、「S」は長さがゼロの文字列に変換されますが、それはおそらく意図したものではありません。

Appendメソッドは、実際には配列全体をより大きな物理スペースにコピーして、新しい要素に対応します。たとえば、次のことを試してください。

import numpy as np
mtype = 'S10, i4, i4'
ta = np.zeros((0), dtype=mtype)
print id(ta)
ta = np.append(ta, np.array([('first', 10, 11)], dtype=mtype))
print id(ta)
ta = np.append(ta, np.array([('second', 20, 21)], dtype=mtype))
print id(ta)

この方法を追加するたびに、メモリが大きくなるたびに、より多くのメモリを割り当ててコピーする必要があるため、コピーが遅くなります。これが、追加するたびにidが異なる値を返す理由です。配列にかなりの数のレコードが必要な場合は、最初から十分なスペースを割り当てるか、リストにデータを蓄積して、完了時にリストを数の多い構造化配列に収集することをお勧めします。これにより、最長の文字列を保持するのに十分な長さを保ちながら、mtypeの文字列の長さを可能な限り短くすることができます。

3
Frank M

これはあなたが達成しようとしていることだと思います-目的のdtypeの空の配列を作成し、それに1つ以上のデータセットを追加します。結果は(N、3)ではなく(N、)の形状になります。

コメントで述べたように、np.appendnp.concatenateを使用しているので、私もそれを使用しています。また、test_arrayxの両方の1d配列を作成する必要があります(それぞれ形状(0、)および(1))。また、dtypeフィールドはS10であり、 'TEXT'を含めるのに十分な大きさです。

In [56]: test_array = np.zeros((0,), dtype='S10, i4, i4')

In [57]: x = np.array([("TEST",1,1)], dtype='S10, i4, i4')

In [58]: test_array = np.concatenate((test_array, x))

In [59]: test_array = np.concatenate((test_array, x))

In [60]: test_array
Out[60]: 
array([('TEST', 1, 1), ('TEST', 1, 1)], 
      dtype=[('f0', 'S'), ('f1', '<i4'), ('f2', '<i4')])

これはタプルのリストから配列を構築する例です:

In [75]: xl=('test',1,1)

In [76]: np.array([xl]*3,dtype='S10,i4,i4')
Out[76]: 
array([('test', 1, 1), ('test', 1, 1), ('test', 1, 1)], 
      dtype=[('f0', 'S10'), ('f1', '<i4'), ('f2', '<i4')])
1
hpaulj