我有一個腳本,累積(計數)包含在兩個文件中的字節。字節類似於C類unsigned char
0到255之間的整數值。有沒有辦法增加不太慢的numpy數組?
該累加器腳本的目標是計算這兩個文件中字節的聯合計數或頻率。可能將其擴展到多個文件/維度。
這兩個文件的大小相同,但它們非常大,約爲6TB左右。
我正在使用numpy.uint64
值,因爲我使用Python的int
類型出現溢出問題。
我有一個長度爲255**2
的1D累加器陣列,用於存儲關節計數。
我計算從逐列到陣列偏移計算的偏移量,以便在正確的索引處增加聯合頻率。我以字節塊(n_bytes
)遍歷這兩個文件,將它們解壓縮並增加頻率計數器。
下面的代碼的草圖:
import numpy
import ctypes
import struct
buckets_per_signal_type = 2**(ctypes.c_ubyte(1).value * 8)
total_buckets = buckets_per_signal_type**2
buckets = numpy.zeros((total_buckets,), dtype=numpy.uint64)
# open file handles to two files (omitted for brevity...)
# buffer size that is known ahead of time to be a divisible
# unit of the original files
# (for example, here, reading in 2.4e6 bytes per loop iteration)
n_bytes = 2400000
total_bytes = 0L
# format used to unpack bytes
struct_format = "=%dB" % (n_bytes)
while True:
# read in n_bytes chunk from each file
first_file_bytes = first_file_handle.read(n_bytes)
second_file_bytes = second_file_handle.read(n_bytes)
# break if both file handles have nothing left to read
if len(first_file_bytes) == 0 and len(second_file_bytes) == 0:
break
# unpack actual bytes
first_bytes_unpacked = struct.unpack(struct_format, first_file_bytes)
second_bytes_unpacked = struct.unpack(struct_format, second_file_bytes)
for index in range(0, n_bytes):
first_byte = first_bytes_unpacked[index]
second_byte = second_bytes_unpacked[index]
offset = first_byte * buckets_per_signal_type + second_byte
buckets[offset] += 1
total_bytes += n_bytes
# repeat until both file handles are both EOF
# print out joint frequency (omitted)
與我曾經int
的版本相比,這是令人難以置信的速度慢,一個數量級上的速度較慢。原來的作業在大約8個小時內完成(錯誤地,由於溢出),並且這個基於numpy的版本必須儘早退出,因爲它似乎需要大約12-14天才能完成。
在這個基本任務中numpy的速度非常慢,或者我沒有像Python那樣用numpy做累加器。我懷疑後者,這就是我爲什麼要求幫助的原因。
我讀了numpy.add.at
,但我將添加到buckets
數組中的解壓字節數組沒有偏移值,這些值自然地轉換爲buckets
數組的「形狀」。
是否有一種方法來存儲和增加一個(長)整數數組,不溢出,哪個是合理的高性能?
我可以在C中重寫這個,我猜,但我希望有一些numpy的東西,我忽略了這個問題很快就能解決。謝謝你的建議。
更新
我有舊版本numpy的和SciPy的那不支持numpy.add.at
。所以這是另一個需要研究的問題。
我會嘗試以下,看看如何繼續下去:
first_byte_arr = np.array(first_bytes_unpacked)
second_byte_arr = np.array(second_bytes_unpacked)
offsets = first_byte_arr * buckets_per_signal_type + second_byte_arr
np.add.at(buckets, offsets, 1L)
希望它運行快一點!
更新II
使用np.add.at
和np.array
,這個工作將需要大約12天的完成。我現在要放棄numpy
,並回到用C讀取原始字節,其中運行時間更合理。謝謝你的建議!
「我閱讀了關於'numpy.add.at',但我將添加到'buckets'數組的解壓字節數組沒有偏移值自然而然地轉化爲「水桶」陣列的「形狀」。「 - 你能強制使用'np.digitize'嗎?不幸的是,我不能跟着你正在用'struct'完成的事情,以便給出關於'numpy'的良好答案。' –
'struct'在這裏用於從每個字節快速生成0到255之間的整數數組。我從映射到字節或整數A的第一個文件中獲得一個字節,並從映射到字節/整數B的第二個文件獲取一個字節。我計算了看到A和B在一起的次數。 我似乎沒有從'numpy.digitize'文檔中獲得足夠的信息來查看它是如何應用於此處的,但我會多查看一下,看看它是否有幫助。感謝指針。 –
那麼這個和'int'版本的唯一區別是''bucket''的'dtype'?只有在一次調用中爲重複元素編制索引時,add.at'纔有用。在你的代碼中'offset'只是一個標量,對吧? – hpaulj