Averaging over n elements - python

I have a numpy array like this [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Let's assume I want the average of 3 elements, my target array should then look like this:
[2, 2, 2, 5, 5, 5, 8, 8, 8, 10]
Notice that when there is no triplet available I want to calculate the average over the remaining elements
Is there a neat way to do that with array operations?

You could reshape the array to use the mean function, for example:
a = np.arange(1,11)
b = a[:a.size//3*3]
b.shape = (-1,3)
c = np.mean(b, axis=1)
# c == array([2., 5., 8.])
Then reassign the results in the original array:
c.shape = (-1,1) # i.e. (len(b), 1)
b[:] = c
print(a)
# array([ 2, 2, 2, 5, 5, 5, 8, 8, 8, 10])
Note that this works because b is a sub-view of a. Also the last element is not as you asked the average (I left it untouched), but it'll be easy to fix, with e.g.:
a[9:] = np.mean(a[9:])

I have done most of it in a one liner just for fun :D
*Notice I'm using sum() to flatten the list.. (that's some weird python trick)
def custom_avg(group: int, arr):
out = list()
[out.append(list(np.full( (1, group), np.sum(arr[i:i+group])/ (1 if i + group > len(arr) else group), dtype=int))) for i in range(0, len(arr), group) ]
return sum(out,[])
Enjoy! good luck.

Related

How to reverse a numpy array and then also switch each 'pair' of positions?

For example, how would you do this sequence of operations on a np 1D array, x:
[1,2,3,4,5,6,7,8]
[8,7,6,5,4,3,2,1]
[7,8,5,6,3,4,1,2]
The transition from state 1 to state 2 can be done with numpy.flip(x):
x = numpy.flip(x)
How can you go from this intermediate state to the final state, in which each 'pair' of positions switches positions
Notes: this is a variable length array, and will always be 1D
It is assumed that the length is always even. At this time, you only need to reshape, reverse and flatten:
>>> ar = np.arange(1, 9)
>>> ar.reshape(-1, 2)[::-1].ravel()
array([7, 8, 5, 6, 3, 4, 1, 2])
This always creates a copy, because the elements in the original array cannot be continuous after transformation, but ndarray.ravel() must create a continuous view.
If it is necessary to transition from state 2 to state 3:
>>> ar = ar[::-1]
>>> ar # state 2
array([8, 7, 6, 5, 4, 3, 2, 1])
>>> ar.reshape(-1, 2)[:, ::-1].ravel()
array([7, 8, 5, 6, 3, 4, 1, 2])
This should work (assumin you have a even number of elements, otherwise you might want to check this before)
x = x.reshape((len(x)//2, 2)) #split in two wolumns
x[:,0], x[:,1] = x[:,1], x[:,0].copy() # switch the columns
x = x.reshape(2*len(x)) # reshape back in a 1D array
You can do:
import numpy as np
arr = np.array([8,7,6,5,4,3,2,1])
result = np.vstack((arr[1::2], arr[::2])).T.flatten()
output:
array([7, 8, 5, 6, 3, 4, 1, 2])

How can I get each combination of a set of arrays in python

How can I (efficiently) get each combination of a group of 1D-arrays into a 2D array?
Let's say I have arrays A, B, C, and D and I want to create a 2D array with each combination such that I would have 2D arrays that represent AB, AC, AD, ABC, ABD, ..., CD.
For clarity on my notation above:
A = np.array([1,2,3,4,5])
B = np.array([2,3,4,5,6])
C = np.array([3,4,5,6,7])
so
AB = np.array([1,2,3,4,5], [2,3,4,5,6])
ABC = np.array([1,2,3,4,5], [2,3,4,5,6],[3,4,5,6,7])
So far I have tried something like:
A = np.array([1,2,3,4,5])
B = np.array([2,3,4,5,6])
C = np.array([3,4,5,6,7])
D = np.array([4,5,6,7,8])
stacked = np.vstack((A,B,C,D), axis=0)
combos = []
it2 = itertools.combinations(range(4), r=2)
for i in list(it2):
combos.append(i)
it3 = itertools.combinations(range(4), r=3)
for i in list(it3):
combos.append(i)
it4 = itertools.combinations(range(4), r=4)
for i in list(it4):
combos.append(i)
which gets me a list of all the possible combos. then I can apply something like:
for combo in combos:
stacked[combo,:]
#Then I do something with each combo
And this is where I get stuck
This is fine when it's only A,B,C,D but if I have A,B,C,... X,Y,Z then the approach above doesn't scale as I'd have to call itertools 20+ times.
How can I overcome this and make it more flexible (in practice the number of arrays will likely be 5-10)?
As others have also recommended, use itertools.combinations
import numpy as np
from itertools import combinations
A = np.array([1,2,3,4,5])
B = np.array([2,3,4,5,6])
C = np.array([3,4,5,6,7])
arrays = [A, B, C]
combos = []
for i in range(2, len(arrays) + 1):
combos.extend(combinations(arrays, i))
for combo in combos:
arr = np.vstack(combo) # do stuff with array
You can use an additional outer for-loop:
arrays = np.array([ # let's say your input arrays are stored as one 2d array
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
...
])
combos = []
for r in range(2, len(arrays)+1):
combos.extend(it.combinations(range(len(arrays)), r=r))
When you have N items, there are 2^N combinations, so this will take 2^N iterations.
You can go through these 2^N iterations with a single loop if you use a for loop for the range 0 <= n < (2^N) and use bitwise operations to select the items from the list of items according the the current n.
You could try this:
from itertools import combinations
A = np.array([1,2,3,4,5])
B = np.array([2,3,4,5,6])
C = np.array([3,4,5,6,7])
lst = [A,B,C]
[list(combinations(lst, i)) for i in range(1,len(lst)+1)]
out:
# [[(array([1, 2, 3, 4, 5]),),
# (array([2, 3, 4, 5, 6]),),
# (array([3, 4, 5, 6, 7]),)],
# [(array([1, 2, 3, 4, 5]), array([2, 3, 4, 5, 6])),
# (array([1, 2, 3, 4, 5]), array([3, 4, 5, 6, 7])),
# (array([2, 3, 4, 5, 6]), array([3, 4, 5, 6, 7]))],
# [(array([1, 2, 3, 4, 5]), array([2, 3, 4, 5, 6]), array([3, 4, 5, 6, 7]))]]

How can I merge rows in np matrix?

I've got a numpy matrix that has 2 rows and N columns, e.g. (if N=4):
[[ 1 3 5 7]
[ 2 4 6 8]]
The goal is create a string 1,2,3,4,5,6,7,8.
Merge the rows such that the elements from the first row have the even (1, 3, ..., N - 1) positions (the index starts from 1) and the elements from the second row have the odd positions (2, 4, ..., N).
The following code works but it isn't really nice:
xs = []
for i in range(number_of_cols):
xs.append(nums.item(0, i))
ys = []
for i in range(number_of_cols):
ys.append(nums.item(1, i))
nums_str = ""
for i in range(number_of_cols):
nums_str += '{},{},'.format(xs[i], ys[i])
Join the result list with a comma as a delimiter (row.join(','))
How can I merge the rows using built in functions (or just in a more elegant way overall)?
Specify F order when flattening (or ravel):
In [279]: arr = np.array([[1,3,5,7],[2,4,6,8]])
In [280]: arr
Out[280]:
array([[1, 3, 5, 7],
[2, 4, 6, 8]])
In [281]: arr.ravel(order='F')
Out[281]: array([1, 2, 3, 4, 5, 6, 7, 8])
Joining rows can be done this way :
>>> a = np.arange(12).reshape(3,4)
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> np.hstack([a[i,:] for i in range(a.shape[0])])
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
Then it's simple to convert this array into string.
Here's one way of doing it:
out_str = ','.join(nums.T.ravel().astype('str'))
We are first transposing the array with .T, then flattening it with .ravel(), then converting each element from int to str, and then applying `','.join() to combine all the str elements
Trying it out:
import numpy as np
nums = np.array([[1,3,5,7],[2,4,6,8]])
out_str = ','.join(nums.T.ravel().astype('str'))
print (out_str)
Result:
1,2,3,4,5,6,7,8

Remove elements from several lists simultaneously

I have three lists with the same length and another list that stores indexes of elements that I need to remove from all three lists. This is an example of what I mean:
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]
(all have len()=9)
The other list contains the indexes of those elements I need to remove from all three lists:
d = [8,5,3]
(note that it is already sorted)
I know I can remove one element at the time from the three lists with:
for indx in d:
del a[indx]
del b[indx]
del c[indx]
How could I do this in one single line?
Not one line, but concise, readable, and completely idiomatic Python:
for indx in d:
for x in a, b, c:
del x[indx]
However, the fact that you're doing this in the first place implies that maybe rather than 3 separate list variables, you should have a list of 3 lists, or a dict of three lists keyed by the names 'a', 'b', and 'c'.
If you really want it in one line:
for indx in d: a.pop(indx), b.pop(indx), c.pop(indx)
But that's really terrible. You're calling pop when you don't care about the values, and building up a tuple you don't need.
If you want to play code golf, you can save a few characters by using a list comprehension—which adds one more language abuse, and builds another, larger object you don't actually want—as in Ioan Alexandru Cucu's answer:
[x.pop(indx) for indx in d for x in a, b, c]
Of course the best way to write it in one line is to factor it out into a function:
def delemall(indices, *lists):
for index in indices:
for x in lists:
del x[indx]
And now, each of the 300 times you need to do this, it's just:
delemall(d, a, b, c)
Maybe numpy is useful for something like this, if your three lists were a 2D numpy.array deleting specified columns would be very easy.
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]
big_array = np.array([a,b,c])
d = [8,5,3]
Result:
>>> big_array
array([[ 3, 4, 5, 12, 6, 8, 78, 5, 6],
[ 6, 4, 1, 2, 8, 784, 43, 6, 2],
[ 8, 4, 32, 6, 1, 7, 2, 9, 23]])
>>> np.delete(big_array, d, axis=1)
array([[ 3, 4, 5, 6, 78, 5],
[ 6, 4, 1, 8, 43, 6],
[ 8, 4, 32, 1, 2, 9]])
I think just your code is OK, to make it a single line:
In [234]: for i in d: del a[i], b[i], c[i]
In [235]: a,b,c
Out[235]: ([3, 4, 5, 6, 78, 5], [6, 4, 1, 8, 43, 6], [8, 4, 32, 1, 2, 9])
but I still like leaving that for loop two lines ;)
import operator
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]
d = [8,5,3]
for _ in (operator.delitem(q,i) for q in (a,b,c) for i in d): pass
print(a,b,c)

Sort list values to get a new order of its index, Python way

Sorry for the vague of my question's title.
My question is, I have a list a = [6, 9, 8, 10, 7, 5, 2, 3, 1, 4]
I need to get the new order b = [4, 2, 3, 5, 1, 6, 10, 8, 7, 9], where the first element of b is 4 because the 4th element of a 10 is the largest number in a. Similarly, the 2nd element in b is 2 because the second large number in a is its second number 9
So, hopefully you got my question: Sort the list a and get the new order b.
Currently, I get it done by using list.sort with some prepare.
tmp = zip(range(1,11), a)
tmp.sort(key=lambda x:(-x[1],x[0]))
b = [x[0] for x in tmp]
I wonder whether there are better python way to achieve my goal?
Thanks for any suggestions~
I would just use the key argument to sort range(1, len(a) + 1) by using a's values.
sorted(range(1, len(a) + 1), key=lambda i: a[i-1], reverse=True)
That's basically the idea, but you can do:
import operator
tmp = sorted(enumerate(a,1),key=itemgetter(1,0),reverse=True)
b = [x[0] for x in tmp]
#In python2.x, the following are equivalent to the list comprehension.
#b = zip(*tmp)[0]
#b = map(itemgetter(0),tmp)
I think that enumerate is a little cleaner than zip with range and itemgetter is a little cleaner than lambda.
You could use sorted and enumerate:
print [el[0] for el in sorted(enumerate(a, start=1), key=lambda L: L[1], reverse=True)]
# [4, 2, 3, 5, 1, 6, 10, 8, 7, 9]
For completeness an alternative using numpy (should you happen to use it any time in the near future):
np.argsort(a)[::-1] + 1
a = [6, 9, 8, 10, 7, 5, 2, 3, 1, 4]
b = [6, 9, 8, 10, 7, 5, 2, 3, 1, 4]
a.sort(reverse = True)
print(a)
print(b)
c = [b.index(y)+1 for y in a ]
print(c)
i have just got this stupid answers...

Categories