7

NumPy には、3 バイトおよび 6 バイトの型 (別名uint24およびuint48. これらの型を使用する大規模なデータ セットがあり、それを numpy にフィードしたいと考えています。私が現在行っていること(uint24の場合):

import numpy as np
dt = np.dtype([('head', '<u2'), ('data', '<u2', (3,))])
# I would like to be able to write
#  dt = np.dtype([('head', '<u2'), ('data', '<u3', (2,))])
#  dt = np.dtype([('head', '<u2'), ('data', '<u6')])
a = np.memmap("filename", mode='r', dtype=dt)
# convert 3 x 2byte data to 2 x 3byte
# w1 is LSB, w3 is MSB
w1, w2, w3 = a['data'].swapaxes(0,1)
a2 = np.ndarray((2,a.size), dtype='u4')
# 3 LSB
a2[0] = w2 % 256
a2[0] <<= 16
a2[0] += w1
# 3 MSB
a2[1] = w3
a2[1] <<=8
a2[1] += w2 >> 8
# now a2 contains "uint24" matrix

100MB の入力に対しては機能しますが、効率が悪いように見えます (100 GB のデータを考えてみてください)。より効率的な方法はありますか?たとえば、データの一部をマスクする特別な種類の読み取り専用ビューを作成すると便利です (「2 つの MSB が常にゼロの uint64」タイプのようなもの)。データへの読み取り専用アクセスのみが必要です。

4

3 に答える 3

8

あなたが求めていることを行う方法があるとは思いません(一部のアーキテクチャでは非常に非効率的な非整列アクセスが必要になります)。ファイルからの任意のバイト長の整数の読み取りと保存からの私の解決策は、データをインプロセス配列に転送するのにより効率的かもしれません。

a = np.memmap("filename", mode='r', dtype=np.dtype('>u1'))
e = np.zeros(a.size / 6, np.dtype('>u8'))
for i in range(3):
    e.view(dtype='>u2')[i + 1::4] = a.view(dtype='>u2')[i::3]

stridesコンストラクターパラメーターを使用して、アライメントされていないアクセスを取得できます。

e = np.ndarray((a.size - 2) // 6, np.dtype('<u8'), buf, strides=(6,))

ただし、これでは各要素が次の要素とオーバーラップするため、実際に使用するには、アクセス時に上位バイトをマスクする必要があります。

于 2012-08-15T10:11:27.533 に答える
2

これに対する答えは次のとおりです: How do I create a Numpy dtype that includes 24 bit integers?

それは少し醜いですが、まさにあなたが望むことをします.dtypeのようにndarrayにインデックスを付ける<u3ことができるのでmemmap()、ディスクから大きなデータを取得できます.
重複する 4 番目のバイトをクリアするためにビットマスクを手動で適用する必要がありますが、これはアクセス後にスライスされた (多次元) 配列に適用できます。

トリックは、インデックス作成が機能するように、ndarray の「ストライド」部分を悪用することです。制限について文句を言わずに機能させるために、特別なトリックがあります。

于 2015-12-07T07:34:18.450 に答える
0

以下のコードを使用すると、ビッグ エンディアンまたはリトル エンディアンとしてコード化された任意のサイズの整数を読み取ることができます。

def readBigEndian(filename, bytesize):
    with (open(filename,"rb")) as f:
         str = f.read(bytesize)
         while len(str)==bytesize:
             int = 0;
             for byte in map(ord,str):
                 print byte
                 int = (int << 8) | byte
             yield(int)
             str = f.read(bytesize)

def readLittleEndian(filename, bytesize):
    with (open(filename,"rb")) as f:
         str = f.read(bytesize)
         while len(str)==bytesize:
             int = 0;
             shift = 0
             for byte in map(ord,str):
                 print byte
                 int |= byte << shift
                 shift += 8
             yield(int)
             str = f.read(bytesize)

for i in readLittleEndian("readint.py",3):
    print i
于 2012-08-15T12:20:43.883 に答える