Let's say I have a 3D array representing tic-tac-toe games (and their respective historical states):
[
[[0,0,0,1,1,0,0,0,1]], #<<--game 1
[[1,0,0,1,0,0,1,0,1]], #<<--game 2
[[1,0,0,1,0,0,1,0,1]] #<<--game 3
]
I would like to pre-pend a clone of these states, but then keep the historical records growing out to the right where they will act as an unadultered historical record
So the next iteration would look like this:
[
[[0,0,0,1,1,0,0,0,1], [0,0,0,1,1,0,0,0,1]], #<<--game 1
[[1,0,0,1,0,0,1,0,1], [1,0,0,1,0,0,1,0,1]], #<<--game 2
[[1,0,0,1,0,0,1,0,1], [1,0,0,1,0,0,1,0,1]] #<<--game 3
]
I will then edit these new columns. At a later time, I will copy it again.
So, I always want to copy this leftmost column (pass by value) - but I don't know how to perform this operation.
You can use concatenate:
# initial array
a = np.array([
[[0,0,0,1,1,0,0,0,1], [0,1,0,1,1,0,0,0,1]], #<<--game 1
[[1,0,0,1,0,0,1,0,1], [1,1,0,1,0,0,1,0,1]], #<<--game 2
[[1,0,0,1,0,0,1,0,1], [1,1,0,1,0,0,1,0,1]] #<<--game 3
])
#subset of this array (column 0)
b = a[:,0,:]
# reshape to add dimension
b = b.reshape ([-1,1,9])
print(a.shape, b.shape) # ((3, 2, 9), (3, 1, 9))
# concatenate:
c = np.concatenate ((a,b), axis = 1)
print (c)
array([[[0, 0, 0, 1, 1, 0, 0, 0, 1],
[0, 1, 0, 1, 1, 0, 0, 0, 1],
[0, 0, 0, 1, 1, 0, 0, 0, 1]], # leftmost column copied
[[1, 0, 0, 1, 0, 0, 1, 0, 1],
[1, 1, 0, 1, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 0, 1, 0, 1]], # leftmost column copied
[[1, 0, 0, 1, 0, 0, 1, 0, 1],
[1, 1, 0, 1, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 0, 1, 0, 1]]]) # leftmost column copied
You can do this using hstack and slicing:
import numpy as np
start= np.asarray([[[0,0,0,1,1,0,0,0,1]],[[1,0,0,1,0,0,1,0,1]],[[1,0,0,1,0,0,1,0,1]]])
print(start)
print("duplicating...")
finish = np.hstack((start,start[:,:1,:]))
print(finish)
print("modifying...")
finish[0,1,2]=2
print(finish)
[[[0 0 0 1 1 0 0 0 1]]
[[1 0 0 1 0 0 1 0 1]]
[[1 0 0 1 0 0 1 0 1]]]
duplicating...
[[[0 0 0 1 1 0 0 0 1]
[0 0 0 1 1 0 0 0 1]]
[[1 0 0 1 0 0 1 0 1]
[1 0 0 1 0 0 1 0 1]]
[[1 0 0 1 0 0 1 0 1]
[1 0 0 1 0 0 1 0 1]]]
modifying...
[[[0 0 0 1 1 0 0 0 1]
[0 0 2 1 1 0 0 0 1]]
[[1 0 0 1 0 0 1 0 1]
[1 0 0 1 0 0 1 0 1]]
[[1 0 0 1 0 0 1 0 1]
[1 0 0 1 0 0 1 0 1]]]
I have a matrix and it's currently populated with just 1's. How do I make it so it populates with random 1's and 0's?
matrix5x5 = [[1 for row in range (5)] for col in range (5)]
for row in matrix5x5:
for item in row:
print(item,end=" ")
print()
print("")
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
I want something like:
1 0 0 1 0
0 1 1 1 1
1 0 1 0 1
1 1 0 0 1
0 1 1 1 1
I found something regarding using random.randint(0,1) but I don't know how to change my current code to include the above.
Modifying your code, using the random package (and not the numpy equivalent):
matrix5x5 = [[random.randint(0,1) for _ in range(5)] for _ in range(5)]
for row in matrix5x5:
for item in row:
print(item,end=" ")
print()
print("")
0 1 0 0 1
0 1 0 1 0
0 0 1 1 0
0 0 0 1 0
1 0 0 1 1
But honestly, numpy makes it a lot faster and easier!
If you don't mind using numpy:
>>> import numpy as np
>>> np.random.randint(2, size=(5, 5))
array([[1, 0, 1, 0, 1],
[1, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[1, 0, 0, 0, 1],
[0, 1, 0, 0, 1]])
Numpy arrays support most list operations that involve indexing and iteration, and if you really care, you can turn it back into a list:
>>> np.random.randint(2, size=(5, 5)).tolist()
[[1, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 1, 0, 0], [1, 0, 1, 1, 1], [1, 0, 1, 0, 0]]
And, if for some strange reason, you are 100% adamant on using vanilla Python, just use the random module and a list comprehension:
>>> import random
>>> [[random.randint(0,1) for j in range (5)] for i in range (5)]
[[0, 1, 0, 1, 1], [0, 1, 1, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]]
You probably want to use numpy. Do the following:
import numpy as np
my_matrix = np.random.randint(2,size=(5,5))
This will create a random 5 by 5 matrix with 0s and 1s.
I have a matrix 'A' whose values are shown below. After creating a matrix 'B' of ones using numpy.ones and assigning the values from 'A' to 'B' by indexing 'i' rows and 'j' columns, the resulting 'B' matrix is retaining the first row of ones from the original 'B' matrix. I'm not sure why this is happening with the code provided below.
The resulting 'B' matrix from command line is shown below:
import numpy
import numpy as np
A = np.matrix([[8,8,8,7,7,6,8,2],
[8,8,7,7,7,6,6,7],
[1,8,8,7,7,6,6,6],
[1,1,8,7,7,6,7,7],
[1,1,1,1,8,7,7,6],
[1,1,2,1,8,7,7,6],
[2,2,2,1,1,8,7,7],
[2,1,2,1,1,8,8,7]])
B = np.ones((8,8),dtype=np.int)
for i in np.arange(1,9):
for j in np.arange(1,9):
B[i:j] = A[i:j]
C = np.zeros((6,6),dtype=np.int)
print C
D = np.matrix([[1,1,2,3,3,2,2,1],
[1,2,1,2,3,3,3,2],
[1,1,2,1,1,2,2,3],
[2,2,3,2,2,2,1,3],
[1,2,2,3,2,3,1,3],
[1,2,3,3,2,3,2,3],
[1,2,2,3,2,3,1,2],
[2,2,3,2,2,3,2,2]])
print D
for k in np.arange(2,8):
for l in np.arange(2,8):
B[k,l] # point in middle
b = B[(k-1),(l-1)]
if b == 8:
# Matrix C is smaller than Matrix B
C[(k-1),(l-1)] = C[(k-1),(l-1)] + 1*D[(k-1),(l-1)]
#Output for Matrix B
B=
[1,1,1,1,1,1,1,1],
[8,8,7,7,7,6,6,7],
[1,8,8,7,7,6,6,6],
[1,1,8,7,7,6,7,7],
[1,1,1,1,8,7,7,6],
[1,1,2,1,8,7,7,6],
[2,2,2,1,1,8,7,7],
[2,1,2,1,1,8,8,7]
Python starts counting at 0, so your code should work find if you replace np.arange(1,9) with np.arange(9)
In [11]: np.arange(1,9)
Out[11]: array([1, 2, 3, 4, 5, 6, 7, 8])
In [12]: np.arange(9)
Out[12]: array([0, 1, 2, 3, 4, 5, 6, 7, 8])
As stated above: python indices start at 0.
In order to iterate over some (say matrix) indices, you should use the builtin function 'range' and not 'numpy.arange'. The arange returns an ndarray, while range returns a generator in a recent python version.
The syntax 'B[i:j]' does not refer to the element at row i and column j in an array B. It rather means: all rows of B starting at row i and going up to (but not including) row j (if B has so many rows, otherwise it returns until includingly the last row). The element at position i, j is in fact 'B[i,j]'.
The indexing syntax of python / numpy is quite powerful and performant.
For one thing, as others have mentioned, NumPy uses 0-based indexing. But even once you fix that, this is not what you want to use:
for i in np.arange(9):
for j in np.arange(9):
B[i:j] = A[i:j]
The : indicates slicing, so i:j means "all items from the i-th, up to the j-th, excluding the last one." So your code is copying every row over several times, which is not a very efficient way of doing things.
You probable wanted to use ,:
for i in np.arange(8): # Notice the range only goes up to 8
for j in np.arange(8): # ditto
B[i, j] = A[i, j]
This will work, but is also pretty wasteful performancewise when using NumPy. A much faster approach is to simply ask for:
B[:] = A
Here first what I think you are trying to do, with minimal corrections, comments to your code:
import numpy as np
A = np.matrix([[8,8,8,7,7,6,8,2],
[8,8,7,7,7,6,6,7],
[1,8,8,7,7,6,6,6],
[1,1,8,7,7,6,7,7],
[1,1,1,1,8,7,7,6],
[1,1,2,1,8,7,7,6],
[2,2,2,1,1,8,7,7],
[2,1,2,1,1,8,8,7]])
B = np.ones((8,8),dtype=np.int)
for i in np.arange(1,9): # i= 1...8
for j in np.arange(1,9): # j= 1..8, but A[8,j] and A[j,8] do not exist,
# if you insist on 1-based indeces, numpy still expects 0... n-1,
# so you'll have to subtract 1 from each index to use them
B[i-1,j-1] = A[i-1,j-1]
C = np.zeros((6,6),dtype=np.int)
D = np.matrix([[1,1,2,3,3,2,2,1],
[1,2,1,2,3,3,3,2],
[1,1,2,1,1,2,2,3],
[2,2,3,2,2,2,1,3],
[1,2,2,3,2,3,1,3],
[1,2,3,3,2,3,2,3],
[1,2,2,3,2,3,1,2],
[2,2,3,2,2,3,2,2]])
for k in np.arange(2,8): # k = 2..7
for l in np.arange(2,8): # l = 2..7 ; matrix B has indeces 0..7, so if you want inner points, you'll need 1..6
b = B[k-1,l-1] # so this is correct, gives you the inner matrix
if b == 8: # here b is a value in the matrix , not the index, careful not to mix those
# Matrix C is smaller than Matrix B ; yes C has indeces from 0..5 for k and l
# so to address C you'll need to subtract 2 from the k,l that you defined in the for loop
C[k-2,l-2] = C[k-2,l-2] + 1*D[k-1,l-1]
print C
output:
[[2 0 0 0 0 0]
[1 2 0 0 0 0]
[0 3 0 0 0 0]
[0 0 0 2 0 0]
[0 0 0 2 0 0]
[0 0 0 0 3 0]]
But there are more elegant ways to do it. In particular look up slicing, ( numpy conditional array arithmetic, possibly scipy threshold.All of the below should be much faster than Python loops too (numpy loops are written in C).
B=np.copy(A) #if you need a copy of A, this is the way
# one quick way to make a matrix that's 1 whereever A==8, and is smaller
from scipy import stats
B1=stats.threshold(A, threshmin=8, threshmax=8, newval=0)/8 # make a matrix with ones where there is an 8
B1=B1[1:-1,1:-1]
print B1
#another quick way to make a matrix that's 1 whereever A==8
B2 = np.zeros((8,8),dtype=np.int)
B2[A==8]=1
B2=B2[1:-1,1:-1]
print B2
# the following would obviously work with either B1 or B2 (which are the same)
print np.multiply(B2,D[1:-1,1:-1])
Output:
[[1 0 0 0 0 0]
[1 1 0 0 0 0]
[0 1 0 0 0 0]
[0 0 0 1 0 0]
[0 0 0 1 0 0]
[0 0 0 0 1 0]]
[[1 0 0 0 0 0]
[1 1 0 0 0 0]
[0 1 0 0 0 0]
[0 0 0 1 0 0]
[0 0 0 1 0 0]
[0 0 0 0 1 0]]
[[2 0 0 0 0 0]
[1 2 0 0 0 0]
[0 3 0 0 0 0]
[0 0 0 2 0 0]
[0 0 0 2 0 0]
[0 0 0 0 3 0]]
A cleaner way, in my opinion, of writing the C loop is:
for k in range(1,7):
for l in range(1,7):
if B[k,l]==8:
C[k-1, l-1] += D[k,l]
That inner block of B (and D) can be selected with slices, B[1:7, 1:7] or B[1:-1, 1:-1].
A and D are defined as np.matrix. Since we aren't doing matrix multiplications here (no dot products), that can create problems. For example I was puzzled why
In [27]: (B[1:-1,1:-1]==8)*D[1:-1,1:-1]
Out[27]:
matrix([[2, 1, 2, 3, 3, 3],
[3, 3, 3, 4, 5, 5],
[1, 2, 1, 1, 2, 2],
[2, 2, 3, 2, 3, 1],
[2, 2, 3, 2, 3, 1],
[2, 3, 3, 2, 3, 2]])
What I expected (and matches the loop C) is:
In [28]: (B[1:-1,1:-1]==8)*D.A[1:-1,1:-1]
Out[28]:
array([[2, 0, 0, 0, 0, 0],
[1, 2, 0, 0, 0, 0],
[0, 3, 0, 0, 0, 0],
[0, 0, 0, 2, 0, 0],
[0, 0, 0, 2, 0, 0],
[0, 0, 0, 0, 3, 0]])
B = A.copy() still leaves B as matrix. B=A.A returns an np.ndarray. (as does np.copy(A))
D.A is the array equivalent of D. B[1:-1,1:-1]==8 is boolean, but when used in the multiplication context it is effectively 0s and 1s.
But if we want to stick with np.matrix then I'd suggest using the element by element multiply function:
In [46]: np.multiply((A[1:-1,1:-1]==8), D[1:-1,1:-1])
Out[46]:
matrix([[2, 0, 0, 0, 0, 0],
[1, 2, 0, 0, 0, 0],
[0, 3, 0, 0, 0, 0],
[0, 0, 0, 2, 0, 0],
[0, 0, 0, 2, 0, 0],
[0, 0, 0, 0, 3, 0]])
or just multiply the full matrixes, and select the inner block after:
In [47]: np.multiply((A==8), D)[1:-1, 1:-1]
Out[47]:
matrix([[2, 0, 0, 0, 0, 0],
[1, 2, 0, 0, 0, 0],
[0, 3, 0, 0, 0, 0],
[0, 0, 0, 2, 0, 0],
[0, 0, 0, 2, 0, 0],
[0, 0, 0, 0, 3, 0]])