Numpy array with values that update - python

Is it possible to create a automatically updating Numpy array?
For example:
a = numpy.array([1,2,3,4])
b = numpy.array([a[0]+1,a[1]+2,a[2]+3,a[3]+4])
a[0] = 5
Output:
>>>print(b)
>>>[6, 4, 6, 8]

Not if the array elements are stored by value. However numpy supports arrays of objects, so you could store lamdas or something and achieve something similar...although it's probably not what you want.
Ex:
a = np.array([1])
b = np.array([ lambda: a[0] + 1 ])
a[0] = 5
print (b[0]())
# 6

Related

Array Prints like List but its a single integer in variable explorer? Why?

When ı print out the following code Q is prints like it suppose to be (3 5 7 9) sum of the numbers with the next one. but in the variable explorer its a single integer ı want to get the result Q as an array like
Q = [3, 5, 7, 9]
import numpy as np
A = [1, 2, 3, 4, 5]
for i in range(0,4):
Q = np.array(A[i]+A[i+1])
print(Q)
for i in range(0,4):
Q = []
Q.append(Q[i] + A[i]+A[i+1])
print(Q)
This also doesnt work
Currently you're just re-declaring Q each time and it's never added to some collection of values
Instead, start with an empty list (or perhaps a numpy array in your case) and outside of your loop and append the values to it at each loop cycle
Q is a numpy array, but it's not what you're expecting!
It has no dimensions and only references a single value
>>> type(Q)
<class 'numpy.ndarray'>
>>> print(repr(Q))
array(9)
>>> import numpy as np
>>> A = [1, 2, 3, 4, 5]
>>> Q = np.array([], dtype=np.uint8)
>>> for i in range(4):
... Q = np.append(Q, A[i]+A[i+1]) # reassign each time for np
...
>>> print(Q)
[3 5 7 9]
Note that numpy arrays should be reassigned via np.append, while a normal python list has a .append() method (which does not return the list, but directly appends to it)
>>> l = ['a', 'b', 'c'] # start with a list of values
>>> l.append('d') # use the append method
>>> l # display resulting list
['a', 'b', 'c', 'd']
If you're not forced to use a numpy array to begin with, this can be done with a list comprehension
The resulting list can also be made into a numpy array afterwards
>>> [(x + x + 1) for x in range(1, 5)]
[3, 5, 7, 9]
All together with simplified math
>>> np.array([x*2+3 for x in range(4)])
array([3, 5, 7, 9])
If you want to use Numpy, then use Numpy. Start with a Numpy array (one-dimensional, containing the values), which looks like this:
A = np.array([1, 2, 3, 4, 5])
(Yes, you initialize it from the list).
Or you can create that kind of patterned data using Numpy's built-in tool:
A = np.arange(1, 6) # it works similarly to the built-in `range` type,
# but it does create an actual array.
Now we can get the values to use on the left-hand and right-hand sides of the addition:
# You can slice one-dimensional Numpy arrays just like you would lists.
# With more dimensions, you can slice in each dimension.
X = A[:-1]
Y = A[1:]
And add the values together element-wise:
Q = X + Y # yes, really that simple!
And that last line is the reason you would use Numpy to solve a problem like this. Otherwise, just use a list comprehension:
A = list(range(1, 6)) # same as [1, 2, 3, 4, 5]
# Same slicing, but now we have to do more work for the addition,
# by explaining the process of pairing up the elements.
Q = [x + y for x, y in zip(A[:-1], A[1:])]

Adding value to array

I want to add values from one array to another array after making some calculation, here I did it using for loop but I want efficient way doing so. Please help me.. thanx
from numpy import *
arr = array([1,2,3,4,5])
arr1 = []
for i in arr:
arr1.append(i+5)
print(arr1)
nArray = array(arr1)
print(nArray)
Output :
[6, 7, 8, 9, 10]
[ 6 7 8 9 10]
You should have just done:
nArray = arr + 5
You could use the map builtin function from Python, it takes a function and an iterable as input and returns something that you can give to the list function, so for instance:
list(map(lambda x: x + 5, arr))
But this would be for python built-in list
Since you are using numpy however, you can just add 5 to the numpy array as arr1 = arr + 5 as suggested by fountainhead

Add values in numpy array successively, without looping [duplicate]

This question already has answers here:
Numpy sum elements in array based on its value
(2 answers)
Closed 4 years ago.
Maybe has been asked before, but I can't find it.
Sometimes I have an index I, and I want to add successively accordingly to this index to an numpy array, from another array. For example:
A = np.array([1,2,3])
B = np.array([10,20,30])
I = np.array([0,1,1])
for i in range(len(I)):
A[I[i]] += B[i]
print(A)
prints the expected (correct) value:
[11 52 3]
while
A[I] += B
print(A)
results in the expected (wrong) answer
[11 32 3].
Is there any way to do what I want in a vectorized way, without the loop?
If not, which is the fastest way to do this?
Use numpy.add.at:
>>> import numpy as np
>>> A = np.array([1,2,3])
>>> B = np.array([10,20,30])
>>> I = np.array([0,1,1])
>>>
>>> np.add.at(A, I, B)
>>> A
array([11, 52, 3])
Alternatively, np.bincount:
>>> A = np.array([1,2,3])
>>> B = np.array([10,20,30])
>>> I = np.array([0,1,1])
>>>
>>> A += np.bincount(I, B, minlength=A.size).astype(int)
>>> A
array([11, 52, 3])
Which is faster?
Depends. In this concrete example add.at seems marginally faster, presumably because we need to convert types in the bincount solution.
If OTOH A and B were float dtype then bincount would be faster.
You need to use np.add.at:
A = np.array([1,2,3])
B = np.array([10,20,30])
I = np.array([0,1,1])
np.add.at(A, I, B)
print(A)
prints
array([11, 52, 3])
This is noted in the doc:
ufunc.at(a, indices, b=None)
Performs unbuffered in place operation on operand ‘a’ for elements specified by ‘indices’. For addition ufunc, this method is equivalent to a[indices] += b, except that results are accumulated for elements that are indexed more than once. For example, a[[0,0]] += 1 will only increment the first element once because of buffering, whereas add.at(a, [0,0], 1) will increment the first element twice.

Deleting values from multiple arrays that have a particular value

Lets say I have two arrays: a = array([1,2,3,0,4,5,0]) and b = array([1,2,3,4,0,5,6]). I am interested in removing the instances where a and bare 0. But I also want to remove the corresponding instances from both lists. Therefore what I want to end up with is a = array([1,2,3,5]) and b = array([1,2,3,5]). This is because a[3] == 0 and a[6] == 0, so both b[3] and b[6] are also deleted. Likewise, since b[4] == 0, a[4] is also deleted.Its simple to do this for say two arrays:
import numpy as np
a = np.array([1,2,3,0,4,5,0])
b = np.array([1,2,3,4,0,5,6])
ix = np.where(b == 0)
b = np.delete(b, ix)
a = np.delete(a, ix)
ix = np.where(a == 0)
b = np.delete(b, ix)
a = np.delete(a, ix)
However this solution doesnt scale up if I have many many arrays (which I do). What would be a more elegant way to do this?
If I try the following:
import numpy as np
a = np.array([1,2,3,0,4,5,0])
b = np.array([1,2,3,4,0,5,6])
arrays = [a,b]
for array in arrays:
ix = np.where(array == 0)
b = np.delete(b, ix)
a = np.delete(a, ix)
I get a = array([1, 2, 3, 4]) and b = array([1, 2, 3, 0]), not the answers I need. Any idea where this is wrong?
Assuming both/all arrays always have the same length, you can use masks:
ma = a != 0 # mask elements which are not equal to zero in a
mb = b != 0 # mask elements which are not equal to zero in b
m = ma * mb # assign the intersection of ma and mb to m
print a[m], b[m] # [1 2 3 5] [1 2 3 5]
You can of course also do it in one line
m = (a != 0) * (b != 0)
Or use the inverse
ma = a == 0
mb = b == 0
m = ~(ma + mb) # not the union of ma and mb
This is happening because when you return from np.delete, you get an array that is stored in b and a inside the loop. However, the arrays stored in the arrays variable are copies, not references. Hence, when you're updating the arrays by deleting them, it deletes with regard to the original arrays. The first loop will return the corrects indices of 0 in the array but the second loop will return ix as 4 (look at the original array).Like if you display the arrays variable in each iteration, it is going to remain the same.
You need to reassign arrays once you are done processing one array so that it's taken into consideration the next iteration. Here's how you'd do it -
a = np.array([1, 2, 3, 0, 4, 5, 0])
b = np.array([1, 2, 3, 4, 0, 5, 6])
arrays = [a,b]
for i in range(0, len(arrays)):
ix = np.where(arrays[i] == 0)
b = np.delete(b, ix)
a = np.delete(a, ix)
arrays = [a, b]
Of course you can automate what happens inside the loop. I just wanted to give an explanation of what was happening.
A slow method involves operating over the whole list twice, first to build an intermediate list of indices to delete, and then second to delete all of the values at those indices:
import numpy as np
a = np.array([1,2,3,0,4,5,0])
b = np.array([1,2,3,4,0,5,6])
arrays = [a, b]
vals = []
for array in arrays:
ix = np.where(array == 0)
vals.extend([y for x in ix for y in x.tolist()])
vals = list(set(vals))
new_array = []
for array in arrays:
new_array.append(np.delete(array, vals))
Building up on top of Christoph Terasa's answer, you can use array operations instead of for loops:
arrays = np.vstack([a,b]) # ...long list of arrays of equal length
zeroind = (arrays==0).max(0)
pos_arrays = arrays[:,~zeroind] # a 2d array only containing those columns where none of the lines contained zeros

Reverse part of an array using NumPy

I am trying to use array slicing to reverse part of a NumPy array. If my array is, for example,
a = np.array([1,2,3,4,5,6])
then I can get a slice b
b = a[::-1]
Which is a view on the original array. What I would like is a view that is partially reversed, for example
1,4,3,2,5,6
I have encountered performance problems with NumPy if you don't play along exactly with how it is designed, so I would like to avoid "fancy" indexing if it is possible.
If you don't like the off by one indices
>>> a = np.array([1,2,3,4,5,6])
>>> a[1:4] = a[1:4][::-1]
>>> a
array([1, 4, 3, 2, 5, 6])
>>> a = np.array([1,2,3,4,5,6])
>>> a[1:4] = a[3:0:-1]
>>> a
array([1, 4, 3, 2, 5, 6])
You can use the permutation matrices (that's the numpiest way to partially reverse an array).
a = np.array([1,2,3,4,5,6])
new_order_for_index = [1,4,3,2,5,6] # Careful: index from 1 to n !
# Permutation matrix
m = np.zeros( (len(a),len(a)) )
for index , new_index in enumerate(new_order_for_index ):
m[index ,new_index -1] = 1
print np.dot(m,a)
# np.array([1,4,3,2,5,6])

Categories