what is "1 in array[]" mean in Julia? - python

I'm in a situation where I have to rewrite some Julia code into Python code and I cannot reproduce this line.
if 1 in array1[array2] || 1 in array1[array3]
In my understanding, this line comparing arrays array1 to array2 and array1 to array3, to see if the index array2 of array1 is 1 or the index array3 of array1 is 1.
So, I reproduced this code into python code with my understand,
for i, j in zip(array2, array3):
if array1[i] == 1 or array1[j] == 1:
But this code didn't work like an above code and I got a ValueError like below:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I'm not sure if this is my misunderstanding of the Julia's line or my Python code is wrong.
Could someone tell me what is wrong?
[edit]:
Here is Julia code of this problem. here I am using karate club network as an input matrix
dir = "to/your/path"
ln = "soc-karate.mtx"
mtx = MatrixMarketRead(string(dir,strip(ln)));
A = mtx - spdiagm(diag(mtx))
n = size(A,1);
A = speye(n) - A * spdiagm(1./vec(sum(A,1)));
println(A)
function findDegrees(Ac::SparseMatrixCSC)
degrees = zeros(Int,length(Ac.colptr)-1)
for i = 1:length(degrees)
degrees[i] = Ac.colptr[i+1]-Ac.colptr[i]-1
end
return degrees
end
function lowDegreeNodes(A::SparseMatrixCSC,At::SparseMatrixCSC,d::Int64,dout::Vector,din::Vector)
# 1: find low degree nodes
n = size(A,1)
U = collect(dout.==1)
println(U)
V = collect(din.==1)
Z = min((dout+din) .>= 1 , (dout+din) .<= 8 )
# 2: visited = 0 ==> NotVisited
# = 1 ==> FNode
# = 2 ==> NotEliminated
visited = zeros(length(U))
for u = 1:n
if Z[u]
if visited[u] == 0
Au = A.rowval[ A.colptr[u]:A.colptr[u+1]-1 ]
Av = At.rowval[ At.colptr[u]:At.colptr[u+1]-1 ]
if 1 in visited[Au] || 1 in visited[Av]
visited[u] = 2
else
visited[Au] = 2
visited[u] = 1
end
end
end
if V[u]
if visited[u] == 0
Au = A.rowval[ A.colptr[u]:A.colptr[u+1]-1 ]
Av = At.rowval[ At.colptr[u]:At.colptr[u+1]-1 ]
if 1 in visited[Au] || 1 in visited[Av]
visited[u] = 2
else
visited[Av] = 2
visited[u] = 1
end
end
end
if U[u]
if visited[u] == 0
Au = A.rowval[ A.colptr[u]:A.colptr[u+1]-1 ]
Av = At.rowval[ At.colptr[u]:At.colptr[u+1]-1 ]
if 1 in visited[Au] || 1 in visited[Av]
visited[u] = 2
else
visited[Av] = 2
visited[u] = 1
end
end
end
end
return visited .== 1
end
dout = findDegrees(A)
din = findDegrees(A')
z = lowDegreeNodes(A, A', 3, dout, din)

if 1 in array1[array2] || 1 in array1[array3]
In my understanding, this line comparing arrays array1 to array2 and array1 to array3, to see if the index array2 of array1 is 1 or the index array3 of array1 is 1.
I don't think that's correct. I think this line tests if 1 is in the values of array1 at indices array2 or indices array3. Let me make a MWE:
julia> array2 = [2, 3]
2-element Array{Int64,1}:
2
3
julia> array3 = [4, 5]
2-element Array{Int64,1}:
4
5
julia> array1 = [1, 9, 1, 2, 3]
5-element Array{Int64,1}:
1
9
1
2
3
julia> 1 in array1[array2] || 1 in array1[array3]
true
julia> array1 = [1, 9, 4, 2, 3] # now only at the 1st position is there a 1
5-element Array{Int64,1}:
1
9
4
2
3
julia> 1 in array1[array2] || 1 in array1[array3]
false

Your understanding of this line is correct:
Edit: Ok, after reading your description again, I am not sure the understanding is correct, but hopefully this explanation will clarify it.
if 1 in array1[array2] || 1 in array1[array3]
You choose the elements in array1 at indexes given by array2 and array3 and check if any of these elements is a 1
So if your array1 is [0, 1, 2, 3, 4, 5, 6] and array2 is [1, 3, 4], array1[array2] would be [0, 2, 3] (remember, arrays are indexed by 1 in Julia!) and thus 1 in array1[array2] would evlauate to false
You can achieve something similar with numpy but remember that since python indexes by 0, you have to subtract 1 from the indexes if you want the code stay equivalent for same input data:
array1 = np.array([...]) # Fill your arrays with the data
array2 = np.array([...])
array3 = np.array([...])
if 1 in array1[array2 - 1] or 1 in array1[array3 - 1]:
# Rest of code
The syntax 1 in <array> is same as in Julia, it evaluates to True if the value 1 is contained in <array>

If these are regular python lists (and built assuming 0 indexed arrays) you could do
array1 = [1,1,2,2,3,3]
array2 = [0,2]
array3 = [3,5]
print(any(array1[i]==1 for i in array2), any(array1[i]==1 for i in array3))
if any(array1[i]==1 for i in array2) or any(array1[i]==1 for i in array3):
print("Yes")
This would fail if indicies in the second two arrays overflow the first. In that case you could scrub them first.
array2 = [i for i in array2 if i < len(array1)]
array3 = [i for i in array3 if i < len(array1)]

Related

How does adding two axis get calculated?

Update: Apologies. I have updated the code to match the output now.
import numpy as np
x = np.arange(0,4,1)
matrix = x[:6,np.newaxis] + x[np.newaxis,:]
That produces this table that looks like this in rows and columns:
0 1 2 3
1 2 3 4
2 3 4 5
3 4 5 6
which is this array:
array([[0, 1, 2, 3],[1, 2, 3, 4],[2, 3, 4, 5],[3, 4, 5, 6]])
My question is how does numpy add up each cell to produce this result?
In my environment your code doesn't give that result. The matrix I get using your code is this:
[[0, 2],
[2, 4]]
To understand the way this result is calculated lets split up the process:
#--- 1
x = np.arange(0,4,2)
The first line gets an array of numbers between 0 and 4 with a step of 2 (not including the 4). The output of this line is the following array:
[0, 2]
Next the two parts of the equation:
#--- 2
part1 = x[:4,np.newaxis]
part2 = x[np.newaxis,:]
The first part takes the first 4 elements of array x and expands it in axis index 1 (so now the elements of our original array are in the axis index 0 (rows)). The output of this part is the following:
[[0],
[2]]
The second part takes the array x and expands the dimensions in the axis index 0 (the elements of the original array are now axis index 1 (columns)). The output of this part is:
[[0, 2]]
Finally adding the two parts:
matrix = part1 + part2
The result of this is the following matrix:
[[0, 2],
[2, 4]]
At each index combination for example [0, 1] the result is the element of part1 at index [0] plus the array of the element of part2 at index [1], thus the result is 0 + 2 = 2.
Similarly:
matrix[0, 0] = part1[0] + part2[0] = 0 + 0 = 0
matrix[0, 1] = part1[0] + part2[1] = 0 + 2 = 2
matrix[1, 0] = part1[1] + part2[0] = 2 + 0 = 2
matrix[1, 1] = part1[1] + part2[1] = 2 + 2 = 4
Edit: Yes the updated code gives the result you mention. Anyway, the same logic applies.

Unable to assign in numpy array

I want to square even index values in numpy array and assign same in that array. I followed 2 approaches.
1 -
for i in range(len(arr)):
if i %2 == 0:
arr[i] = arr[i]**2
That is working.
2 -
arr[i] = arr[i]**2 for i in range(len(arr)) if i % 2 == 0
File "<ipython-input-149-30fc7ed25f1f>", line 1
arr[i] = arr[i]**2 for i in range(len(arr)) if i % 2 == 0
^
SyntaxError: invalid syntax
not working.
Is some syntax error?
This works with list compreension:
arr = [arr[i]**2 if i % 2 == 0 else arr[i] for i in range(len(arr))]
But you could also use the shorter:
arr[::2] = arr[::2]**2
I assume you are trying to do list comprehension, for which your syntax is slightly off, read up on the syntax of list comprehension.
It's syntax is similar to [exp1(item) if condition1 else exp2(item) for item in arr] .
The correct way to do it is as follows.
arr = [1,2,3,4,5,6]
arr = [arr[i]**2 if i % 2 == 0 else arr[i] for i in range(len(arr))]
print(arr)
#[1, 2, 9, 4, 25, 6]
What this is doing is running the for loop, checking the condition, and then picking either arr[i] or arr[i]**2, and then assigning the result to the list
Dont loop over numpy arrays you lose all the power of numpy.
Use these numpy functions to achieve the required result instead:
import numpy as np
arr = np.random.randint(0,10, size=(10,))
print(arr)
ans = np.where(np.arange(10) % 2 == 0, arr, arr**2)
print(ans)
output:
[ 1 9 1 1 0 6 5 2 1 5 ]
[ 1 81 1 1 0 36 5 4 1 25]
np.where selects the elements where the condition is true. Then outputs either the original array or the squared array.
Docs for np.where.

How to find numpy array shape in a larger array?

big_array = np.array((
[0,1,0,0,1,0,0,1],
[0,1,0,0,0,0,0,0],
[0,1,0,0,1,0,0,0],
[0,0,0,0,1,0,0,0],
[1,0,0,0,1,0,0,0]))
print(big_array)
[[0 1 0 0 1 0 0 1]
[0 1 0 0 0 0 0 0]
[0 1 0 0 1 0 0 0]
[0 0 0 0 1 0 0 0]
[1 0 0 0 1 0 0 0]]
Is there a way to iterate over this numpy array and for each 2x2 cluster of 0s, set all values within that cluster = 5? This is what the output would look like.
[[0 1 5 5 1 5 5 1]
[0 1 5 5 0 5 5 0]
[0 1 5 5 1 5 5 0]
[0 0 5 5 1 5 5 0]
[1 0 5 5 1 5 5 0]]
My thoughts are to use advanced indexing to set the 2x2 shape = to 5, but I think it would be really slow to simply iterate like:
1) check if array[x][y] is 0
2) check if adjacent array elements are 0
3) if all elements are 0, set all those values to 5.
big_array = [1, 7, 0, 0, 3]
i = 0
p = 0
while i <= len(big_array) - 1 and p <= len(big_array) - 2:
if big_array[i] == big_array[p + 1]:
big_array[i] = 5
big_array[p + 1] = 5
print(big_array)
i = i + 1
p = p + 1
Output:
[1, 7, 5, 5, 3]
It is a example, not whole correct code.
Here's a solution by viewing the array as blocks.
First you need to define this function rolling_window from here https://gist.github.com/seberg/3866040/revisions
Then break the array big, your starting array, into 2x2 blocks using this function.
Also generate an array which has indices of every element in big and break it similarly into 2x2 blocks.
Then generate a boolean mask where the 2x2 blocks of big are all zero, and use the index array to get those elements.
blks = rolling_window(big,window=(2,2)) # 2x2 blocks of original array
inds = np.indices(big.shape).transpose(1,2,0) # array of indices into big
blkinds = rolling_window(inds,window=(2,2,0)).transpose(0,1,4,3,2) # 2x2 blocks of indices into big
mask = blks == np.zeros((2,2)) # generate a mask of every 2x2 block which is all zero
mask = mask.reshape(*mask.shape[:-2],-1).all(-1) # still generating the mask
# now blks[mask] is every block which is zero..
# but you actually want the original indices in the array 'big' instead
inds = blkinds[mask].reshape(-1,2).T # indices into big where elements need replacing
big[inds[0],inds[1]] = 5 #reassign
You need to test this: I did not. But the idea is to break the array into blocks, and an array of indices into blocks, then develop a boolean condition on the blocks, use those to get the indices, and then reassign.
An alternative would be to iterate through indblks as defined here, then test the 2x2 obtained from big at each indblk element and reassign if necessary.
This is my attempt to help you solve your problem. My solution may be subject to fair criticism.
import numpy as np
from itertools import product
m = np.array((
[0,1,0,0,1,0,0,1],
[0,1,0,0,0,0,0,0],
[0,1,0,0,1,0,0,0],
[0,0,0,0,1,0,0,0],
[1,0,0,0,1,0,0,0]))
h = 2
w = 2
rr, cc = tuple(d + 1 - q for d, q in zip(m.shape, (h, w)))
slices = [(slice(r, r + h), slice(c, c + w))
for r, c in product(range(rr), range(cc))
if not m[r:r + h, c:c + w].any()]
for s in slices:
m[s] = 5
print(m)
[[0 1 5 5 1 5 5 1]
[0 1 5 5 0 5 5 5]
[0 1 5 5 1 5 5 5]
[0 5 5 5 1 5 5 5]
[1 5 5 5 1 5 5 5]]

Assign 0 and 1 based on values greater than in one line

Say I have an array with integers 1 through 10 and have to replace all integers less than 6 with 0 and all integers equal to or greater than 6 with 1. Currently, I am doing this:
arry[arry < 6] = 0
arry[arry >= 6] = 1
I was wondering what would be a way to combine these two statements into one line of code, or any other solution for that matter.
I assume that arry is a numpy array (the smart indexing that you are using seems to indicate this). In that case you can simply do:
arry = (arry >= 6).astype(int)
where astype(int) will convert the array of booleans arry >= 6 to an array of integers.
You can use a simple list comprehension:
array = [0 if num < 6 else 1 for num in arry]
Which is equivalent to the following loops:
temp = []
for num in arry:
if num < 6:
temp.append(0)
else:
temp.append(1)
arry = temp
[1 if e >= 6 else 0 for e in arry]
for numpy array, (arry >= 6) gives an array of True/False which you can multiply by 1
(arry >= 6) * 1
or add 0
(arry >= 6) + 0
or cast to int
(a >= 6).astype(int)
[int(e >= 6) for e in arry]
This works because True is defined to be the same value as 1 and False is defined to be the same value as 0.
list(map(lambda i: 0 if i<6 else 1, a))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(function (n) {return n >= 6 ? 1 : 0})

stacking numpy arrays?

I am trying to stack arrays horizontally, using numpy hstack, but can't get it to work. Instead, it all comes out in one list, instead of a 'matrix-looking' 2D array.
import numpy as np
y = np.array([0,2,-6,4,1])
y_bool = y > 0
y_bool = [1 if l == True else 0 for l in y_bool] #convert to decimals for classification
y_range = range(0,len(y))
print y
print y_bool
print y_range
print np.hstack((y,y_bool,y_range))
Prints this:
[ 0 2 -6 4 1]
[0, 1, 0, 1, 1]
[0, 1, 2, 3, 4]
[ 0 2 -6 4 1 0 1 0 1 1 0 1 2 3 4]
How do I instead get the last line to look like this:
[0 0 0
2 1 1
-6 0 2
4 1 3]
If you want to create a 2D array, do:
print np.transpose(np.array((y, y_bool, y_range)))
# [[ 0 0 0]
# [ 2 1 1]
# [-6 0 2]
# [ 4 1 3]
# [ 1 1 4]]
Well, close enough h is for horizontal/column wise, if you check its help, you will see under See Also
vstack : Stack arrays in sequence vertically (row wise).
dstack : Stack arrays in sequence depth wise (along third axis).
concatenate : Join a sequence of arrays together.
Edit: First thought vstack does it, but it would be if np.vstack(...).T or np.dstack(...).squeeze(). Other then that the "problem" is that the arrays are 1D and you want them to act like 2D, so you could do:
print np.hstack([np.asarray(a)[:,np.newaxis] for a in (y,y_bool,y_range)])
the np.asarray is there just in case one of the variables is a list. The np.newaxis makes them 2D to make it clearer what happens when concatenating.

Categories