您可以使用np.unique
來獲得對應於字符串IDs
的數字IDs
。這些數字ID在計算mean
和std
時都會有用。
現在,平均計算,這些數字ID可作爲"weights"
與np.bincount
分檔,給我們對應於每個ID
數據元素的總和。接下來。使用每個ID的元素計數,然後可以得到平均值。這裏的執行 -
_,idx,counts = np.unique(IDs,return_inverse=True,return_counts=True)
mean_vals = np.bincount(idx,data.ravel())/counts
對於std
計算,一個辦法是進行排序的ID,使得相同的ID被連續放置。然後,重新排列數據以形成另一個2D陣列,使得對應於相同ID的所有數據元素在相同行中,並且將未填充位置設置爲NaNs
。這裏的想法是以列向量化的方式執行np.std
。將要填補的地方需要掩蔽。請注意,這可能是一個飢餓的方法,如果有一個ID相對較高的計數。實施將重新使用idx
和counts
從代碼更早,會是這個樣子 -
data_RO = np.empty((counts.size,counts.max()))
data_RO[:] = np.nan
data_RO[np.arange(counts.max()) < counts[:,None]] = data.ravel()[idx.argsort()]
std_vals = np.nanstd(data_RO,axis=1)
採樣運行和驗證輸出 -
1)輸入:
In [51]: data
Out[51]:
array([[0, 1, 6],
[2, 5, 0],
[6, 3, 6]])
In [52]: IDs
Out[52]:
array([['A', 'A', 'B'],
['A', 'B', 'C'],
['B', 'A', 'C']],
dtype='|S1')
2)代碼中列出的代碼輸出:
In [53]: unique_IDs = np.unique(IDs)
In [54]: results = []
In [55]: for ID in unique_IDs:
....: group_data = data[IDs == ID]
....: mean = np.mean(group_data)
....: stdev = np.std(group_data)
....: results.append([ID, mean, stdev])
....:
In [56]: results
Out[56]:
[['A', 1.5, 1.1180339887498949],
['B', 5.666666666666667, 0.47140452079103168],
['C', 3.0, 3.0]]
3)提出的解決方案輸出:
In [57]: _,idx,counts = np.unique(IDs,return_inverse=True,return_counts=True)
In [58]: np.bincount(idx,data.ravel())/counts
Out[58]: array([ 1.5 , 5.66666667, 3. ])
In [59]: data_RO = np.empty((counts.size,counts.max()))
In [60]: data_RO[:] = np.nan
In [61]: mask = np.arange(counts.max()) < counts[:,None]
In [62]: data_RO[mask] = data.ravel()[idx.argsort()]
In [63]: np.nanstd(data_RO,axis=1)
Out[63]: array([ 1.11803399, 0.47140452, 3. ])
我發現這種方法清晰明瞭,當使用5000 * 5000陣列和500個唯一ID進行測試時,其速度提高了40倍。 – Joe