Changing the value of some indexes of an array in python - python

I am trying this simple code to search in an array and replace the elements that are greater than 1 to 1:
import numpy as np
j = np.array([[1],[3],[1],[0],[9]])
for x in j:
if abs(x) > 1 :
j[x] = 1
But I get such errors:
IndexError: index 9 is out of bounds for axis 0 with size 5

If all you're doing is making all values if absolute(j[i]) is greater than 1 to 1 then numpy has this capability built in and it's so simple it can be done in one line and more efficient than any python loop:
j[np.absolute(j) > 1] = 1
To show you how this would work:
#made 3 a negitive value to prove absolute works.
j = np.array([[1],[-3],[1],[0],[9]])
j[np.absolute(j) > 1] = 1
j is now:
[[1]
[1]
[1]
[0]
[1]]

When you traverse an array in a for loop you are actually accessing the elements, not the index. After all, you are comparing x against 1. You can retrieve the index in many ways, one of the common ones is to use enumerate, like so:
import numpy as np
j = np.array([[1],[3],[1],[0],[9]])
for i,x in enumerate(j): # i is the index, x is the value
if abs(x) > 1 :
j[i] = 1

Try to change the for loop using enumerate to :
import numpy as np
j = np.array([[1],[3],[1],[0],[9]])
for i,x in enumerate(j):
if abs(x) > 1 :
j[i] = 1

as you see in your error output
IndexError: index 9 is out of bounds for axis 0 with size 5
you are trying to update a value at index 9 but your array is of size 5.
which clearly means you are not using the index of array but actually the value at index.
enumerate your array and run a loop with both index & value
for i,x in enumerate(j):
if abs(x) > 1 :
j[i] = 1

Are you trying to make a two dimensional array? You have your elements in brackets within brackets "[[1],[3],[1],[0],[9]]" .... also, you're iterating over values, not indices: x is an array value "[3]" not an index "1".
Change to:
import numpy as np
j = np.array([1,3,1,0,9])
# Keep track of index starting at 0
i = 0
for x in j:
if abs(x) > 1 :
# change value at index i
j[i] = 1
# increment index
i += 1

You may want to replace the for statement with this:
for x in range(len(j))

Related

Can numpy help me quickly find the index of an array, at which its sum is negativ for the first time?

I need to do something like this
import numpy as np
a = np.random.rand(1000)
a -= .55
a[0] = 1
b = 0
for i in range(len(a)):
b += a[i]
if b < 0:
print(i)
break
a lot, and preferably it should be swift. Can NumPy help me with that? I understand that NumPy is built for vector calculation and not for this. Still, it can calculate the sum of an array blazingly fast - can I give it this specific condition (the sum is negative for the first time) to stop and tell me the index number?
You can use numpy.cumsum() and numpy.argmax(). First, compute the cumulative sum of the elements. Then return True/False that elements < 0 and return the first index that is True for element < 0 with argmax().
>>> (a.cumsum() < 0).argmax()
check both codes:
import numpy as np
a = np.random.rand(1000)
a -= .55
a[0] = 1
def check_1(a):
b = 0
for i in range(len(a)):
b += a[i]
if b < 0:
print(i)
break
def check_2(a):
return (a.cumsum() < 0).argmax()
Output: (Generate base random input)
>>> check_1(a)
6
>>> check_2(a)
6

ValueError The truth value of an array with more than one element is ambiguous Use a any or a all

So I'm trying to create an array of the same size as [A]. What I want is a for-loop that checks if the 1st value of the ith element in the Array == 0, However it keeps telling me that there is more than one element in the truth value of an array when there shouldn't be as I indexed the 1st value of the ith element in my array. Here is my code:
n = 4
N = [i for i in range(1,n+1)]
V = [0] + N
K = N + [5]
M = [0,1]
A = np.array([(i,j,k) for i in V for j in K for k in M if i!=j])
C=[]
for i in A:
if A[i][0]==0:
C.append([0.7])
elif abs(A[i][0]-A[i][1])<=1:
C.append([1])
else:
C.append([0])
When you go through your for loop, i is already each list in A, you can check this with the below:
for i in A:
print(i)
Which returns:
[0 1 0]
[0 1 1]
[0 2 0]
[0 2 1]...
So then calling A[i][0] gives an array each time rather than an integer, so the comparison A[i][0] == 0 is not possible. To fix your problem, either do the below, which will change your i to get an index for every element in A:
for i in range(len(A)):
if A[i][0]==0:
C.append([0.7])
elif abs(A[i][0]-A[i][1])<=1:
C.append([1])
else:
C.append([0])
Or change all instances of A[i][x] to i[x], and use the each list element of A that way, as follows:
for i in A:
if i[0]==0:
C.append([0.7])
elif abs(i[0]-i[1])<=1:
C.append([1])
else:
C.append([0])

How to find the max of the sums of the absolute values of each column in a matrix

I am trying to write a function to find the maximum value of the sums of each value in each column of a matrix without using a numpy function.
For example, given the following array, I want the answer 2.7657527806024733.
A = np.array([[0.94369777, 0.34434054, 0.80366952, 0.665736],
[0.82367659, 0.13791176, 0.6993436, 0.44473609],
[0.82337673, 0.56936686, 0.46648214, 0.50403736]])
This is the code I have so far:
def L1Norm(M):
x = 0
S = np.shape(M)
N = S[0]
P = S[1]
answer = np.zeros((1, P))
for j in range(P):
t = 0
for i in M:
t += np.abs(i[j])
answer = np.append(answer, t)
s = np.shape(answer)
n = s[0]
p = s[1]
for j in range(p):
if answer[0][j] > x:
x = answer[0][j]
return x
But I keep getting the following error:
IndexError Traceback (most recent call last)
<ipython-input-113-e06e08ab836c> in <module>
----> 1 L1Norm(A)
<ipython-input-112-624908415c12> in L1Norm(M)
12 s = np.shape(answer)
13 n = s[0]
---> 14 p = s[1]
15 for j in range(p):
16 if answer[0][j] > x:
IndexError: tuple index out of range
Any ideas about how I could fix this?
Heres my solve. I loop over the columns and push each sum into an array. Then i loop over that array to find the largest value. It's very verbose but it doesn't use numpy for anything but creating the matrix.
import numpy as np
matrix = np.array([[0.94369777, 0.34434054, 0.80366952, 0.665736],
[0.82367659, 0.13791176, 0.6993436, 0.44473609],
[0.82337673, 0.56936686, 0.46648214, 0.50403736]])
matrixShape = np.shape(matrix)
i = 0
j = 0
sumsOfColumns = []
while j < matrixShape[1]:
sumOfElems = 0
i = 0
while i < matrixShape[0]:
sumOfElems += matrix[i,j]
i += 1
sumsOfColumns.append(sumOfElems)
j += 1
print(sumsOfColumns)
maxValue = 0
for value in sumsOfColumns:
if value > maxValue:
maxValue = value
print(maxValue)
repl: https://repl.it/#ShroomCode/FrequentFunnyDisplaymanager
If you're looking to get a max sum of columns, here is a super simple approach using a pandas.DataFrame:
import numpy as np
import pandas as pd
vals = np.array([[0.94369777, 0.34434054, 0.80366952, 0.665736],
[0.82367659, 0.13791176, 0.6993436, 0.44473609],
[0.82337673, 0.56936686, 0.46648214, 0.50403736]])
# Store values to a DataFrame.
df = pd.DataFrame(vals)
# Get the max of column sums.
max_sum = df.sum(axis=0).max()
As a Function:
def max_col_sum(vals):
max_sum = pd.DataFrame(vals).sum(axis=0).max()
return max_sum
Output:
2.59075109
With numpy you can get each column as an array by using my_np_array[:,column_number]
So using this you can do a for loop:
sums = []
for i in range(0, np.shape(my_np_array)[0] + 1):
sums.append(sum(my_np_array[:,i]))
max_sum = max(sums)
To solve without numpy, we can go through each row adding each value to its corresponding column tally:
import numpy as np
answer = np.array([[0.94369777, 0.34434054, 0.80366952, 0.665736],
[0.82367659, 0.13791176, 0.6993436, 0.44473609],
[0.82337673, 0.56936686, 0.46648214, 0.50403736]])
# Convert our numpy array to a normal array
a = answer.tolist()
# list comprehension to initialise list
sums = [0 for x in range(len(a) + 1)]
for i in range(0, len(a)):
for j in range(0, len(a[i])):
sums[j] += a[i][j]
# Get the max sum
max_sum = max(sums)
print(max_sum)
Simple answer using zip, np.sum
Code
def L1Norm(M):
return max([np.sum(column) for column in zip(*M)])for column in zip(*M)]
Result
2.59075109
Explanation
List comprehension to loop over data in each column with:
[... for column in zip(*M)]
Sum column values with
np.sum(column)
Compute Max of list comprehension with:
max([...])
Please try the following?-
A.sum(0).max()
or
max(sum(A))
Both should give you the desired answer!

random flip m values from an array

I have an array with length n, I want to randomly choose m elements from it and flip their value. What is the most efficient way?
there are two cases, m=1 case is a special case. It can be discussed separately, and m=/=1.
My attempt is:
import numpy as np
n = 20
m = 5
#generate an array a
a = np.random.randint(0,2,n)*2-1
#random choose `m` element and flip it.
for i in np.random.randint(0,n,m):
a[m]=-a[m]
Suppose m are tens and n are hundreds.
To make sure we are not flipping the same element twice or even more times, we can create unique indices in that length range with np.random.choice using its optional replace argument set as False. Then, simply indexing into the input array and flipping in one go should give us the desired output. Thus, we would have an implementation like so -
idx = np.random.choice(n,m,replace=False)
a[idx] = -a[idx]
Faster version : For a faster version of np.random_choice, I would suggest reading up on this post that explores using np.argpartition to simulate identical behavior.
You can make a random permutation of the array indices, take the first m of them and flip their values:
a[np.random.permutation(range(len(a)))[:m]]*=-1
Using permutation validate you don't choose the same index twice.
You need to change the index of the array from m to i to actually change the value.
Result:
import numpy as np
n = 20
m = 5
#generate an array a
a = np.random.randint(0,2,n)*2-1
print(a)
#random choose `i` element and flip it.
for i in np.random.randint(0,n,m):
a[i] = -a[i]
print(a)
My output:
[ 1 1 -1 -1 1 -1 -1 1 1 -1 -1 1 -1 1 1 1 1 -1 1 -1]
[ 1 1 -1 -1 -1 -1 1 1 1 -1 -1 1 -1 -1 1 -1 1 -1 -1 -1]

conditional sum over a range python

I have created X as folowing
num_locations = 2
X= [ ]
for n in range(num_locations):
X.append([0 for j in range(num_locations)])
Now I want to sum these X[n][m] values for the case n != m . Such that the result should be like
X[0][1]+X[1][0]
Is there a way to do that with the sum formulation ?
X[n][m] for n in range(num_locations)for m in range(num_locations))
This is effectively taking the sum of the non-diagonal elements of your 2D array. One option using Numpy could simply be to subtract the sum of the main diagonal (np.trace) from the sum of the entire array.
num_locations = 2
X= [[1,2],[2,1]]
import numpy as np
s = np.sum(X) - np.trace(X)
print(s)
Outputs:
4
You can simply use enumerate
>>> sum(o for i, a in enumerate(X) for j, o in enumerate(a) if i!=j)
0
Where i and j are row (1st dim) and column (2nd dim) indices respectively
This should work
sum([sum(row) - (row[i] if len(row) < i else 0) for i,row in enumerate(X)])
It runs over every row in the 2d array, and sums it, then take out the i cell (if exists) so it won't get into sum

Categories