summing element in a range for all element in an array - python

I have to get the total sum of a range from an array. However the array range needs to move from one element to another. for example if the array is 1,2,3,4,5,6 and if every two element needs to be added , then it should add 1+2 than 2+3 than 3+4 and so on.
I have tried but not getting right approach. I am sure there is a pythonic way of doing this.
here what I have tried
data = np.arange(0,20,.3)
for i in range (0,len(data)):
for j in range(i,len(data)):
get_range = data[j:5]
get_add = get_range.sum()
print("sum:",get_add)
I have tried to add every 5 element here.

You could use a list comprehension which retrieves a chunks list.
l = [1,2,3,4,5,6]
n = 2
output = [sum(l[i:i + n]) for i in range(0, len(l) - n + 1, 1)]
Output
[3, 5, 7, 9, 11]

There is a numpyic way to do this. It is more memory- and CPU- effective if your input data is big enougth.
import numpy as np
# input array: [1, 2, 3, 4, 5, 6]
data = np.arange(1, 7)
# cumulative sum: [1, 3, 6, 10, 15, 21]
data_cumsum = np.cumsum(data)
# append zero to start: [0, 1, 3, 6, 10, 15, 21]
data_cumsum = np.hstack([0, data_cumsum])
# calculate moving sum
window = 2
moving_sum = data_cumsum[window:] - data_cumsum[:-window]
print(moving_sum)
Output:
[ 3 5 7 9 11]

A minor change will solve the problem
data = np.arange(0,10)
for j in range(0,len(data)-1):
get_range = data[j:j+2] #changed from j to j+2
get_add = get_range.sum()
print("sum:",get_add)
OUTPUT
('sum:', 1)
('sum:', 3)
('sum:', 5)
('sum:', 7)
('sum:', 9)
('sum:', 11)
('sum:', 13)
('sum:', 15)
('sum:', 17)
You can easily condense above steps to form a list comprehension giving the same results with same complexity
[sum(data[j:j+2]) for j in range(0,len(data)-1)]
Another fancy approach could be using sliding_window function
from toolz.itertoolz import sliding_window
map(sum,list(sliding_window(2,list(range(0,10)))))
Output
[1, 3, 5, 7, 9, 11, 13, 15, 17]

Related

Use different list values in order to do the same sum with each

Please help, I need to have a moving value in my code based upon a list!
I have a list, the list is as follows:
my_list = [1, 2, 2, 3, 5, 6, 7, 7, 9, 10]
I have a part of my code which uses this list in order to do a sum, this is as follows:
val = my_list[0]+1
ans = val*9
What I want is to have val be replaced by each of the numbers in my_list i.e. the first time it would be 1x9 and then the next 2x9. However, I cannot find anywhere how to do this.
val = my_list[x]
val += 1
ans = val * 9
x += 1
this way you can just run your code, then add 1 to x
move the x += 1 line to whereever you want
Is your ans a list?
Do "(x+1)*9" for each elements?
ans = [(x+1)*9 for x in my_list]
What you want is vectorization - for which you can use the numpy package:
import numpy as np
my_list = [1, 2, 2, 3, 5, 6, 7, 7, 9, 10]
my_np_list = np.array(my_list)
ans = 9 * my_np_list
# vectorization applies to each element of my_np_list in parallel
# the `9 *` calculation.
## ans contains:
## array([ 9, 18, 18, 27, 45, 54, 63, 63, 81, 90])
## you can sum accross ans by the .sum() method
ans.sum() ## 468
It is as if you do:
ans = []
for x in my_list:
ans.append(9 * x)

How can I extract a centered window from a numpy array?

Suppose I have the following numpy array:
>>> a = np.arange(0,21,1)
>>> a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
Now suppose that I want to pick a window of length N, where 2 < N <= a.shape[0], such that the window is "centered" around one of the elements of the array a. For example, if I want to center a window of length N = 5 around the element 10 in array a, then this window would be:
>>> idx = 10 # index of the array element 10
>>> N = 5 # window size
>>> a[idx - N//2:idx + N//2 + 1]
array([ 8, 9, 10, 11, 12])
This method generalizes well for windows that are not near the edges of the array, but I can't make it work otherwise. For example, if I want to extract a window of length N = 7 around the element 2 in a, then what I get is:
>>> idx = 2
>>> N = 7
>>> a[idx - N//2:idx + N//2 + 1]
array([], dtype=int32)
However what I want is:
>>> a[0:7]
array([0, 1, 2, 3, 4, 5, 6])
How can I generalize this method for windows near the edges of a?
Try with:
idx = 2
start = min(idx - N//2, 0)
a[start:start + N]
Note that this is not centered at idx=2.
Based on Quang Hoang's answer, here is what worked:
import numpy as np
a = np.arange(0,21,1)
idx = 5 # desired element index
N = 7 # window length
if N % 2: # if window length is odd
step = N // 2
else: # if window length is even
step = int(N/2 - 1)
# make sure starting index is between 0 and a.shape[0] - N
start = min(max(idx-step,0),a.shape[0] - N)
window = a[start:start + N]

Generating a list of N pseudo-random integers, drawn from a specific range, with the list summing to a specific value

In Python:
How can I generate a list of N (e.g. 10) pseudo-random integers, each drawn from a specific range (e.g. between 3 and 9), with the list summing up to a specific value (e.g. 58)?
For this example the solution would look like this:
solution = [3, 7, 7, 9, 3, 6, 4, 8, 8, 3]
sum(solution)
58
That is, 10 numbers, each between 3 and 9, summing up to 58.
I've tried a solution approaches with np.random.dirichlet or np.random.multinomial as suggested in related questions here, but these do not allow for choosing the integers from a specific range.
import random
N = 10
s = 58
i, j = 3, 9
out = [i] * N
while sum(out) != s:
idx = random.randint(0, N-1)
if out[idx] < j:
out[idx] += 1
print(out)
Prints (for example):
[9, 7, 6, 4, 5, 8, 3, 5, 5, 6]
One idea I've just had is to initialise a list with n values that are the average value (so, as close to being all the same value as possible) and then randomly select a pair of values and increase one while decreasing the other while ensuring values are kept with the required range, so don't increase/decrease if the value will go out of bounds.
Repeat until success?
a = []
while sum(a) != 58:
a = random.choices(range(3, 10), k=10)
Takes about 17 attempts on average.

Single line chunk re-assignment

As shown in the following code, I have a chunk list x and the full list h. I want to reassign back the values stored in x in the correct positions of h.
index = 0
for t1 in range(lbp, ubp):
h[4 + t1] = x[index]
index = index + 1
Does anyone know how to write it in a single line/expression?
Disclaimer: This is part of a bigger project and I simplified the questions as much as possible. You can expect the matrix sizes to be correct but if you think I am missing something please ask for it. For testing you can use the following variable values:
h = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x = [20, 21]
lbp = 2
ubp = 4
You can use slice assignment to expand on the left-hand side and assign your x list directly to the indices of h, e.g.:
h = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x = [20, 21]
lbp = 2
ubp = 4
h[4 + lbp:4 + ubp] = x # or better yet h[4 + lbp:4 + lbp + len(x)] = x
print(h)
# [1, 2, 3, 4, 5, 6, 20, 21, 9, 10]
I'm not really sure why are you adding 4 to the indexes in your loop nor what lbp and ubp are supposed to mean, tho. Keep in mind that when you select a range like this, the list you're assigning to the range has to be of the same length as the range.

NumPy first and last element from array

I am trying to dynamically get the first and last element from an array.
So, let us suppose the array has 6 elements.
test = [1,23,4,6,7,8]
If I am trying to get the first and last = 1,8, 23,7 and 4,6. Is there a way to get elements in this order?
I looked at a couple of questions Link Link2. I took help of these links and I came up with this prototype..
#!/usr/bin/env python
import numpy
test = [1,23,4,6,7,8]
test1 = numpy.array([1,23,4,6,7,8])
len_test = len(test)
first_list = [0,1,2]
len_first = len(first_list)
second_list = [-1,-2,-3]
len_second = len(second_list)
for a in range(len_first):
print numpy.array(test)[[first_list[a] , second_list[a]]]
print test1[[first_list[a], second_list[a]]]
But this prototype won't scale for if you have more than 6 elements. So, I was wondering if there is way to dynamically get the pair of elements.
Thanks!
I ended here, because I googled for "python first and last element of array", and found everything else but this. So here's the answer to the title question:
a = [1,2,3]
a[0] # first element (returns 1)
a[-1] # last element (returns 3)
How about:
In [10]: arr = numpy.array([1,23,4,6,7,8])
In [11]: [(arr[i], arr[-i-1]) for i in range(len(arr) // 2)]
Out[11]: [(1, 8), (23, 7), (4, 6)]
Depending on the size of arr, writing the entire thing in NumPy may be more performant:
In [41]: arr = numpy.array([1,23,4,6,7,8]*100)
In [42]: %timeit [(arr[i], arr[-i-1]) for i in range(len(arr) // 2)]
10000 loops, best of 3: 167 us per loop
In [43]: %timeit numpy.vstack((arr, arr[::-1]))[:,:len(arr)//2]
100000 loops, best of 3: 16.4 us per loop
arr = np.array([1,2,3,4])
arr[-1] # last element
Using Numpy's fancy indexing:
>>> test
array([ 1, 23, 4, 6, 7, 8])
>>> test[::-1] # test, reversed
array([ 8, 7, 6, 4, 23, 1])
>>> numpy.vstack([test, test[::-1]]) # stack test and its reverse
array([[ 1, 23, 4, 6, 7, 8],
[ 8, 7, 6, 4, 23, 1]])
>>> # transpose, then take the first half;
>>> # +1 to cater to odd-length arrays
>>> numpy.vstack([test, test[::-1]]).T[:(len(test) + 1) // 2]
array([[ 1, 8],
[23, 7],
[ 4, 6]])
vstack copies the array, but all the other operations are constant-time pointer tricks (including reversal) and hence are very fast.
>>> test = [1,23,4,6,7,8]
>>> from itertools import izip_longest
>>> for e in izip_longest(test, reversed(test)):
print e
(1, 8)
(23, 7)
(4, 6)
(6, 4)
(7, 23)
(8, 1)
Another option
>>> test = [1,23,4,6,7,8]
>>> start, end = iter(test), reversed(test)
>>> try:
while True:
print map(next, [start, end])
except StopIteration:
pass
[1, 8]
[23, 7]
[4, 6]
[6, 4]
[7, 23]
[8, 1]
You can simply use take method and index of element (Last index can be -1).
arr = np.array([1,2,3])
last = arr.take(-1)
# 3
How about this?
>>> import numpy
>>> test1 = numpy.array([1,23,4,6,7,8])
>>> forward = iter(test1)
>>> backward = reversed(test1)
>>> for a in range((len(test1)+1)//2):
... print forward.next(), backward.next()
...
1 8
23 7
4 6
The (len(test1)+1)//2 ensures that the middle element of odd length arrays is also returned:
>>> test1 = numpy.array([1,23,4,9,6,7,8]) # additional element '9' in the middle
>>> forward = iter(test1)
>>> backward = reversed(test1)
>>> for a in range((len(test1)+1)//2):
... print forward.next(), backward.next()
1 8
23 7
4 6
9 9
Using just len(test1)//2 will drop the middle elemen of odd length arrays.
This does it. Note that with an odd number of elements the one in the middle won't be included.
test = [1, 23, 4, 6, 7, 8, 5]
for i in range(len(test)/2):
print (test[i], test[-1-i])
Output:
(1, 5)
(23, 8)
(4, 7)
How about this:
xs = [1,23,4,6,7,8]
np.array(list(zip(xs[:len(xs)//2], xs[::-1])))
array([[ 1, 8],
[23, 7],
[ 4, 6]])
Assuming the list has a even number of elements, you could do:
test = [1,23,4,6,7,8]
test_rest = reversed(test[:len(test)/2])
for n in len(test_rest):
print [test[n], test_test[n]]

Categories