Numpy methods are going to beat python loops almost always, so I am going to skip your 1.
As for 2, in this particular case the following works:
a = np.array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])
a = a.reshape(2, 3, 4)
>>> a
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
>>> np.mean(a, axis=1)
array([[ 4., 5., 6., 7.],
[ 16., 17., 18., 19.]])
The trick is in the reshape. For a general case where you want blocks of n columns, the following is an option
a = a.reshape((a.shape[0], -1, n))
Your concerns in 3 are mostly unwarranted. reshape returns a view of the original array, not a copy, so the conversion to 3D only requires altering the shape and strides attributes of the array, without having to copy any of the actual data.
EDIT To be sure that reshaping does not copy the array, but returns a view, do the reshape as
a.shape = a = a.reshape((a.shape[0], -1, n))
The example in the docs goes along the lines of:
>>> a = np.arange(12).reshape(3,4)
>>> b = a.T
>>> b.shape = (12,)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: incompatible shape for a non-contiguous array
And in general there are only problems if you have been doing transpose, rollaxis, swapaxes or the like on your array.
Numpy methods are going to beat python loops almost always, so I am going to skip your 1.
As for 2, in this particular case the following works:
a = np.array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])
a = a.reshape(2, 3, 4)
>>> a
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
>>> np.mean(a, axis=1)
array([[ 4., 5., 6., 7.],
[ 16., 17., 18., 19.]])
The trick is in the reshape. For a general case where you want blocks of n columns, the following is an option
a = a.reshape((a.shape[0], -1, n))
Your concerns in 3 are mostly unwarranted. reshape returns a view of the original array, not a copy, so the conversion to 3D only requires altering the shape and strides attributes of the array, without having to copy any of the actual data.
EDIT To be sure that reshaping does not copy the array, but returns a view, do the reshape as
a.shape = a = a.reshape((a.shape[0], -1, n))
The example in the docs goes along the lines of:
>>> a = np.arange(12).reshape(3,4)
>>> b = a.T
>>> b.shape = (12,)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: incompatible shape for a non-contiguous array
And in general there are only problems if you have been doing transpose, rollaxis, swapaxes or the like on your array.
I can answer ur number 1).
vstack([mean(a[:,4*i:4*(i+1)],axis=1) for i in range(3)]).T
If you are open to other packages, Pandas as a convenient groupby function:
out = (pd.Series(a.ravel(),
index = pd.MultiIndex.from_product((pairs,pairs)))
.groupby(level=(0,1)).mean()
.unstack().to_numpy()
)
Output:
array([[5.25 , 5. , 3.5 ],
[5.33333333, 3.11111111, 3.33333333],
[6.5 , 3.33333333, 4. ]])
The best I can imagine is to try to limit the number of loops. I will assume here that the 6x6 2D array is arr and that the communities definition is coms = np.array([0, 0, 1, 1, 1, 2]).
I would first compute slices per community:
dcoms = {k: slice(min(x), 1 + max(x)) for k in np.unique(coms)
for x in (np.where(coms==k)[0],)}
1 loop over coms
Then I can directly compute the resulting ndarray with 2 loops over dcoms:
resul = np.array([[arr[dcoms[i],dcoms[j]].mean() for j in dcoms] for i in dcoms])
It gives as expected:
array([[5.25 , 5. , 3.5 ],
[5.33333333, 3.11111111, 3.33333333],
[6.5 , 3.33333333, 4. ]])
If your array arr has a length divisible by 3:
np.mean(arr.reshape(-1, 3), axis=1)
Reshaping to a higher dimensional array and then performing some form of reduce operation on one of the additional dimensions is a staple of numpy programming.
For googlers looking for a simple generalisation for arrays with multiple dimensions: the function block_reduce in the scikit-image module (link to docs).
It has a very simple interface to downsample arrays by applying a function such as numpy.mean, but can also use others (maximum, median, ...). The downsampling can be done by different factors for different axes by supplying a tuple with different sizes for the blocks. Here's an example with a 2D array; downsampling only axis 1 by 5 using the mean:
import numpy as np
from skimage.measure import block_reduce
arr = np.stack((np.arange(1,20), np.arange(20,39)))
# array([[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38]])
arr_reduced = block_reduce(arr, block_size=(1,5), func=np.mean, cval=np.mean(arr))
# array([[ 3. , 8. , 13. , 17.8],
# [22. , 27. , 32. , 33. ]])
As it was discussed in the comments to the other answer: if the array in the reduced dimension is not divisible by block size, padding values are provided by the argument cval (0 by default).