Editting python 2-dimensional array without for-loop? - python

So, I have a given 2 dimensional matrix which is randomly generated:
a = np.random.randn(4,4)
which gives output:
array([[-0.11449491, -2.7777728 , -0.19784241, 1.8277976 ],
[-0.68511473, 0.40855461, 0.06003551, -0.8779363 ],
[-0.55650378, -0.16377137, 0.10348714, -0.53449633],
[ 0.48248298, -1.12199767, 0.3541335 , 0.48729845]])
I want to change all the negative values to 0 and all the positive values to 1.
How can I do this without a for loop?

You can use np.where()
import numpy as np
a = np.random.randn(4,4)
a = np.where(a<0, 0, 1)
print(a)
[[1 1 0 1]
[1 0 1 0]
[1 1 0 0]
[0 1 1 0]]

(a<0).astype(int)
This is one possibly solution - converting the array to boolean array according to your condition and then converting it from boolean to integer.
array([[ 0.63694991, -0.02785534, 0.07505496, 1.04719295],
[-0.63054947, -0.26718763, 0.34228736, 0.16134474],
[ 1.02107383, -0.49594998, -0.11044738, 0.64459594],
[ 0.41280766, 0.668819 , -1.0636972 , -0.14684328]])
And the result -
(a<0).astype(int)
>>> array([[0, 1, 0, 0],
[1, 1, 0, 0],
[0, 1, 1, 0],
[0, 0, 1, 1]])

Related

Replace specific element in ndarray per condition

I have the following example array:
[[ 2 4 -1]
[ 1 -1 -1]
[ 2 4 -1]
[ 0 -1 -1]
[ 0 0 2]
[ 2 4 -1]]
In each of the rows, if I have 0 twice, I need to replace the second one with -1 and move it to the end of the row, like this:
[[ 2 4 -1]
[ 1 -1 -1]
[ 2 4 -1]
[ 0 -1 -1]
[ 0 2 -1]
[ 2 4 -1]]
I tried the following cycle:
for i in np.nditer(f_vars_r, op_flags = ['readwrite']):
if i == 0 and i==0:
i[...] == -1
I realize it cannot be complete, but at least I expected to receive some kind of error. Strangely, it passes without error but does nothing with the array. Any suggestions how the cycle can be re-worked to do the job will be greatly appreciated.
Here's an approach that works on any size of sub-arrays.
The basic idea is to convert the numpy array to a list of lists; then loop over the list, for each sub-list get the indices of all the zeros; if there are two zeros in the sub-list, remove the zero with pop() and then append a -1 at the end
import numpy as np
x = np.array([[2, 0, 4, -1],
[1, 0, -1, -1],
[2, 0, 4, -1],
[0, 0, -1, 2],
[0, 0, 1, 2],
[2, 0, 0, -1]])
# convert your numpy array to a list
x = x.tolist()
# iterate over the list (sub will contain the sublists)
for sub in x:
# get the indices of zeros from sub
zero_indices = [i for i, n in enumerate(sub) if n == 0]
if len(zero_indices) == 2:
sub.pop(zero_indices[1]) # remove the second zero
sub.append(-1) # add a -1 to the end
# convert the list back to a numpy array
x = np.array(x)

Boundaries when printing list of lists

I have the following code:
matrix = [[0, 0, 1, 0], [1, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 1]]
I am able to print every line as follows using this:
for i in matrix:
print(*i)
outputting:
0 0 1 0
1 1 0 0
0 0 0 1
1 0 0 1
I want to create custom boundaries for each line and I am able to do so with by manually adding the boundaries to the list of list as shown below:
for k in range(0,columns):
matrix[k].insert(0,'[')
matrix[k].insert(columns+1,']')
giving me the output as desired:
[ 0 0 1 0 ]
[ 1 1 0 0 ]
[ 0 0 0 1 ]
[ 1 0 0 1 ]
Is there a better way to do this, particularly without having to add the boundaries into my list?
Yes you can do it with two for loop like that
for i in matrix:
s = "["
for j in i:
s = s + str(j) + " "
s = s + "]"
print(s)
Or you can still do it with 1 for loop like that
for i in matrix:
print("[", *i, "]")
for row in matrhx:
print( '[ ' + ' '.join(str(j)) + ' ]' )
for row in matrix:
print(row)
almost does what you want, but it has commas. Replace those commas by nothing:
for row in matrix:
print(str(row).replace(',',''))
[0 0 1 0]
[1 1 0 0]
[0 0 0 1]
[1 0 0 1]
Even this isn't quite what your target is, but in mathematical type-setting it is not customary to pad the boundaries of a matrix with white space.
Another way with simple list to str casting and replacing all the commas with nothing like below-
matrix = [[0, 0, 1, 0], [1, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 1]]
for i in matrix:
print(str(i).replace(',',''))
DEMO: https://rextester.com/QESAJC13339

Tensorflow: tensor binarization

I want to transform this dataset in such a way that each tensor has a given size n and that a feature at index i of this new tensor is set to 1 if and only if there is a i in the original feature (modulo n).
I hope the following example will make things clearer
Let's suppose I have a dataset like:
t = tf.constant([
[0, 3, 4],
[12, 2 ,4]])
ds = tf.data.Dataset.from_tensors(t)
I want to get (if n = 9)
t = tf.constant([
[1, 0, 0, 1, 1, 0, 0, 0, 0], # index set to 1 are 0, 3 and 4
[0, 0, 1, 1, 1, 0, 0, 0, 0]]) # index set to 1 are 2, 4, and 12%9 = 3
I know how to apply the modulo to a tensor, but I don't find how to do the rest of the transformation
thanks
That is similar to tf.one_hot, only for multiple values at the same time. Here is a way to do that:
import tensorflow as tf
def binarization(t, n):
# One-hot encoding of each value
t_1h = tf.one_hot(t % n, n, dtype=tf.bool, on_value=True, off_value=False)
# Reduce across last dimension of the original tensor
return tf.cast(tf.reduce_any(t_1h, axis=-2), t.dtype)
# Test
with tf.Graph().as_default(), tf.Session() as sess:
t = tf.constant([
[ 0, 3, 4],
[12, 2, 4]
])
t_m1h = binarization(t, 9)
print(sess.run(t_m1h))
Output:
[[1 0 0 1 1 0 0 0 0]
[0 0 1 1 1 0 0 0 0]]

Convert a tree to a matrix Python 3

I'm trying to convert a Tree: (list Nat (listof Tree)) to a graph matrix but I do not know where to start. I'm not looking for code but more so ideas on how to approach this problem.
For example, a tree is
aTree = [3 , [
[1 , []] ,
[0 , [
[2 , []] ,
[5 , []]
]
] ,
[4 , []]
]
]
Which would look like:
3
/ | \
1 0 4
/ \
2 5
And the matrix would be
aM =
[[0 , 0 , 1 , 1 , 0 , 1] ,
[0 , 0 , 0 , 1 , 0 , 0] ,
[1 , 0 , 0 , 0 , 0 , 0] ,
[1 , 1 , 0 , 0 , 1 , 0] ,
[0 , 0 , 0 , 1 , 0 , 0] ,
[1 , 0 , 0 , 0 , 0 , 0]]
the function would be treetomatrix(Tree, N) where N is the number of vertices in the tree. So treetomatrix(aTree, 6) => aM.
Any suggestions would be much appreciated.
The really hard part of this question is how to change the weird list structure you're using into a dictionary. (If you don't know about dictionaries, read up on them. They do what you're trying to make your list do, but much more naturally.) I've skipped that for the moment, and will do that next.
aTree = {3 : {
1: {},
0:{ 2: {},
5: {}
}
4:{}
}
}
def tree_to_matrix(tree, n):
return tree_to_mat(tree, [[0 for i in range(n)] for j in range(n)])
def tree_to_mat(tree, mat):
for k, v in tree.items():
for i in v.keys():
mat[i][k] = mat[k][i] = 1
mat = tree_to_mat(v, mat)
return mat
print(tree_to_matrix(aTree, 6))
prints
[[0, 0, 1, 1, 0, 1], [0, 0, 0, 1, 0, 0], [1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0], [1, 0, 0, 0, 0, 0]]
Which is our desired output. You may find it easier to read your input into a custom Tree class and then write a method for that class to generate the matrices. The trick is to use recursion and realize that you have to set both mat[i][k] and mat[k][i] at the same time.
EDIT: Here's my hacky way of turning your list into a dict.
def dictify(l):
return {l[0]: d_helper(l[1])}
def d_helper(l):
d={}
for i in l:
d.update(dictify(i))
return d
dictify(aTree)
There's a better way, but this works.

In order to generate all combinations of 1's and 0's we use a simple binary table. How can I easily create this binary table in an array?

For example the binary table for 3 bit:
0 0 0
0 0 1
0 1 0
1 1 1
1 0 0
1 0 1
And I want to store this into an n*n*2 array so it would be:
0 0 0
0 0 1
0 1 0
1 1 1
1 0 0
1 0 1
For generating the combinations automatically, you can use itertools.product standard library, which generates all possible combinations of the different sequences which are supplied, i. e. the cartesian product across the input iterables. The repeat argument comes in handy as all of our sequences here are identical ranges.
from itertools import product
x = [i for i in product(range(2), repeat=3)]
Now if we want an array instead a list of tuples from that, we can just pass this to numpy.array.
import numpy as np
x = np.array(x)
# [[0 0 0]
# [0 0 1]
# [0 1 0]
# [0 1 1]
# [1 0 0]
# [1 0 1]
# [1 1 0]
# [1 1 1]]
If you want all elements in a single list, so you could index them with a single index, you could chain the iterable:
from itertools import chain, product
x = list(chain.from_iterable(product(range(2), repeat=3)))
result: [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1]
Most people would expect 2^n x n as in
np.c_[tuple(i.ravel() for i in np.mgrid[:2,:2,:2])]
# array([[0, 0, 0],
# [0, 0, 1],
# [0, 1, 0],
# [0, 1, 1],
# [1, 0, 0],
# [1, 0, 1],
# [1, 1, 0],
# [1, 1, 1]])
Explanation: np.mgrid as used here creates the coordinates of the corners of a unit cube which happen to be all combinations of 0 and 1. The individual coordinates are then ravelled and joined as columns by np.c_
Here's a recursive, native python (no libraries) version of it:
def allBinaryPossiblities(maxLength, s=""):
if len(s) == maxLength:
return s
else:
temp = allBinaryPossiblities(maxLength, s + "0") + "\n"
temp += allBinaryPossiblities(maxLength, s + "1")
return temp
print (allBinaryPossiblities(3))
It prints all possible:
000
001
010
011
100
101
110
111

Categories