Creating a matrix in Python with a range of numbers - python

I would like to create a matrix with cells that increment by 10. For example, the output of a 3x3 matrix should be:
[[10, 20, 30], [40, 50, 60], [70, 80, 90]]
The code I currently have creates a 3x3 matrix filled with 0s:
print([[0 for x in range(3)] for y in range(3)])
output: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

Try this on for size
print([[30*y + 10*x for x in range(3)] for y in range(3)])
What this does is swaps out the 0 you were using with 30*y + 10*x which is exactly what you need to generate your array. For a more general solution that lets you scale to n by n matrices you can use
n = k
print([[10*k*y + 10*x for x in range(k)] for y in range(k)])
For different rows and columns you can use
rows = k
cols = j
print([[10*cols*y + 10*x for x in range(cols)] for y in range(rows)])

numpy package is quite flexible for things you want:
import numpy as np
m = np.arange(10, 100, 10) #array [10, 20, 30, 40, 50, 60, 70, 80, 90]
m = m.reshape(3,3) # array [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
print(m.tolist()) # array converted to list if you need
Output:
[[10, 20, 30], [40, 50, 60], [70, 80, 90]]

import numpy as np
x = np.array(range(10,100,10)).reshape(3,3)
print(x)
[[10 20 30]
[40 50 60]
[70 80 90]]

The code is not very compact but it gets the job done:
matrix = []
bar = []
foo = 10
for i in range(3):
for i in range(3):
bar.append(foo)
foo = foo + 10
matrix.append(bar)
bar = []
print(matrix)

Related

Numpy: Apply function pairwise on two arrays of different length

I am trying to make use of numpy vectorized operations. But I struggle on the following task: The setting is two arrays of different length (X1, X2). I want to apply a method to each pair (e.g. X1[0] with X2[0], X2[1], etc). I wrote the following working code using loops, but I'd like to get rid of the loops.
result = []
for i in range(len(X1)):
result.append([])
for j in range(len(X2)):
tmp = my_method(X1[i] - X2[j])
result[i].append(tmp)
result = np.asarray(result)
You can reshape one of your vectors to be (N, 1) and then use vectorize which will broadcast the operation as normal:
import numpy as np
X1 = np.arange(5)
X2 = np.arange(3)
print(X1, X2)
# [0 1 2 3 4] [0 1 2]
def my_op(x, y):
return x + y
np.vectorize(my_op)(X1[:, np.newaxis], X2)
# array([[0, 1, 2],
# [1, 2, 3],
# [2, 3, 4],
# [3, 4, 5],
# [4, 5, 6]])
Note that my_op is just defined as an example; if your function is actually anything included in numpy's vectorized operations, it'd be much faster to just use that directly, e.g.:
X1[:, np.newaxis] + X2
itertools.product might be what you're looking for:
from itertools import product
import numpy as np
x1 = np.array(...)
x2 = np.array(...)
result = np.array([my_method(x_1 - x_2) for x_1, x_2 in product(x1,x2)])
Alternatively you could also use a double list comprehension:
result = np.array([my_method(x_1 - x_2) for x_1 in x1 for x_2 in x2])
This obviously depends on what my_method is doing and operating on and what you have stored in x1 and x2.
Assuming a simple function my_method(a, b), which adds the two numbers.
And this input:
X1 = np.arange(10)
X2 = np.arange(10,60,10)
You code is:
result = []
for i in range(len(X1)):
result.append([])
for j in range(len(X2)):
tmp = my_method(X1[i], X2[j])
result[i].append(tmp)
result = np.asarray(result)
You can replace it with broadcasting:
X1[:,None]+X2
output:
array([[10, 20, 30, 40, 50],
[11, 21, 31, 41, 51],
[12, 22, 32, 42, 52],
[13, 23, 33, 43, 53],
[14, 24, 34, 44, 54],
[15, 25, 35, 45, 55],
[16, 26, 36, 46, 56],
[17, 27, 37, 47, 57],
[18, 28, 38, 48, 58],
[19, 29, 39, 49, 59]])
Now you need to see if your operation can be vectorized… please share details on what you want to achieve. Functions can be vectorized using numpy.vectorize, but this is not a magic tool as it will loop on the elements, which can be slow. The best is to have a true vector operation.

How to perform operations on certain rows of one np array based on conditions of another np array using numpy methods?

For example, I have one np array A = [[30, 60, 50...], [ 15, 20, 18...], [21, 81, 50...]...] of size (N, 10).
And I have another np array B = [1, 1, 0...] of size (N, ).
I want to do operations E.g. I want all the sums of each column in A but only for rows where B==1. How would I do that without using any loops and just numpy methods?
So if I want sum of columns in A for indices where B == 1:
result = 30 + 15 because the first two indices in B are 1 but the third index is 0 so I wouldn't include it in the sum.
Use np.compress and sum along axis=0
>>> A = [[30, 60, 50], [ 15, 20, 18], [21, 81, 50]]
>>> B = [1, 1, 0]
>>> np.compress(B, A, axis=0).sum(0)
array([45, 80, 68])
If array, use np.nonzero on B:
>>> A = np.array([[30, 60, 50], [ 15, 20, 18], [21, 81, 50]])
>>> A[np.nonzero(B)].sum(0)
array([45, 80, 68])
Another way:
>>> A[B.astype(bool)].sum(0)
array([45, 80, 68])
If you want 0s:
>>> np.compress(B==0, A, axis=0).sum(0)
# Or,
>>> A[np.nonzero(B==0)].sum(0)
# Or,
>>> A[~B.astype(bool)].sum(0)
If you want both 1s and 0s, obviously:
>>> A.sum(0)
You can convert B to bool type and mask A. Then you can get the sum along columns.
A = np.array([[30, 60, 50], [ 15, 20, 18], [21, 81, 50]])
B = np.array([1, 1, 0])
A[B.astype(np.bool)].sum(axis=0)
array([45, 80, 68])

How do you get all the combinations of n numbers divisible by 10 and whose sum is 100?

The objective is to obtain distribution lists that allow, for example, to test scenarios by weighting variables with different familiar weights whose sum is equal to 100 (and therefore assimilable to percentages).
The method I propose below works but may not be the best. Feel free to suggest any improvement.
Function for integer compositions into n parts:
def comppercents(n):
y = [0] * n
y[0] = 100
while True:
yield(y)
v = y[-1]
if (100 ==v ):
break
y[-1] = 0
j = -2
while (0==y[j]):
j -= 1
y[j] -= 10
y[j+1] = 10 + v
for x in comppercents(3):
print(x)
[100, 0, 0]
[90, 10, 0]
[90, 0, 10]
[80, 20, 0]
...
[0, 20, 80]
[0, 10, 90]
[0, 0, 100]
(66 variants)
from itertools import groupby
def comb_100(n):
global L_combination_100
L_combination_100= []
# adds in L_combination_100 all the possible lists (without the order mattering) whose sum of the elements is 10
find_raw_combination([i+1 for i in list(range(10))]*10,10)
# we remove all duplicate lists
for i in range(len(L_combination_100)):
L_combination_100[i].sort()
L_combination_100.sort()
L_combination_100 = list(k for k,_ in groupby(L_combination_100)) # groupby from itertools
# We remove all lists that have too many elements (> n)
L_combination_100 = [i if len(i)<=n else [] for i in L_combination_100]
L_combination_100 = [x for x in L_combination_100 if x != []]
# We add 0's to lists that don't have n items
# All items within each list are multiplied by 10 to obtain a sum equal to 100
for i,l in enumerate(L_combination_100) :
if len(l) != n:
L_combination_100[i].extend([0]*(n-len(l)))
L_combination_100[i] = [ii*10 for ii in L_combination_100[i]]
#That's how we got our final list of lists/combinations. We have to be careful that the order doesn't matter in these lists.
return L_combination_100
#Strongly inspired from https://stackoverflow.com/questions/4632322/finding-all-possible-combinations-of-numbers-to-reach-a-given-sum
def find_raw_combination(numbers, target, partial=[]): # need global variable L_combination_100
s = sum(partial)
# check if the partial sum is equals to target
if s == target:
L_combination_100.append(partial) if partial not in L_combination_100 else L_combination_100
if s >= target:
return # reach if we get the number
for i in range(len(numbers)):
n = numbers[i]
remaining = numbers[i+1:]
find_raw_combination(remaining, target, partial + [n])
Example :
comb_100(3)
Output :
[[10, 10, 80],
[10, 20, 70],
[10, 30, 60],
[10, 40, 50],
[10, 90, 0],
[20, 20, 60],
[20, 30, 50],
[20, 40, 40],
[20, 80, 0],
[30, 30, 40],
[30, 70, 0],
[40, 60, 0],
[50, 50, 0],
[100, 0, 0]]

Numpy array 'for' loop in Python

I'm using a for loop to pull values from 2 arrays and then put them together in a new array. I can get the last row of the array, but not all the rows before it. (I would like to append each row to the same array.) Any ideas?
import numpy as np
# Array inputs
a = np.array([0, 1, 2])
b = np.array([[1, 10, 20, 30], [2, 40, 50, 60], [3, 70, 80, 90]])
Note that the a array will be random depending on what file is loaded. So for one file, it might be:
([1, 1, 2])
And then for another file it might be:
([0, 2, 1])
So, the a array looks up the first value of the b array and then takes its last 3 values while indexing this action.
From these 2 arrays, I want a new array like this:
# ([[0, 10, 20, 30],
# [1, 40, 50, 60],
# [2, 70, 80, 90]])
Here's my loop:
# Loop to put all values in c and d arrays:
for index, value in enumerate(np.nditer(a)):
c = b[value][1:4]
d = index
# Stack c and d array into e
e = np.hstack((c, d))
But returns this:
([2, 70, 80, 90]) # Only last line of loop.
# I wish to get last line and all lines before it.
Without using for loop, you can copy contents of b to e then, replace content of e of all rows first column ( using e[:,0]) by a:
import numpy as np
# Array inputs
a = np.array([0, 1, 2])
b = np.array([[1, 10, 20, 30], [2, 40, 50, 60], [3, 70, 80, 90]])
e = np.copy(b)
e[:,0] = a
print(e)
Result:
[[ 0 10 20 30]
[ 1 40 50 60]
[ 2 70 80 90]]

Incrementing values in 2d array?

I'm attempting to increment the values in a 2d array for a game I'm making, but I'm getting the same value in each array instead. This is the code:
def matrix(grid):
nrows = len(grid)
ncols = len(grid[0])
for i in range(nrows):
for j in range(ncols):
grid[i][j] += 10
for row in grid:
print(row)
rows = 4
cols = 4
grid = [[0 for i in range(cols)] for i in range(rows)]
matrix(grid)
The output is:
[10, 10, 10, 10]
[10, 10, 10, 10]
[10, 10, 10, 10]
[10, 10, 10, 10]
Where as I would like it to be
[10, 20, 30, 40]
[10, 20, 30, 40]
[10, 20, 30, 40]
[10, 20, 30, 40]
Also, is it possible to stagger and use two nested for loops to provide incremented values for each row? Such as:
[10, 20, 30, 40]
[20, 40, 60, 80]
[10, 20, 30, 40]
[20, 40, 60, 80]
The output is as expected: the following line of code adds 10 to each cell, and since each is zero on entry, it becomes 10 in output
for i in range(nrows):
for j in range(ncols):
grid[i][j] += 10
Maybe the following would do, depending on what you are trying to do
for i in range(nrows):
for j in range(ncols):
grid[i][j] += 10*(j+1)
And for the two-loop version (not the output you give, but I didn't find the pattern)
for i in range(nrows):
for j in range(ncols):
grid[i][j] += 10*(i+j+1)
You might try this loop:
for i in range(nrows):
for j in range(ncols):
if (i % 2 != 0):
grid[i][j] += 20*(j+1)
else:
grid[i][j] += 10*(j+1)
for the output:
[10, 20, 30, 40]
[20, 40, 60, 80]
[10, 20, 30, 40]
[20, 40, 60, 80]
Whenever you have to modify the whole list, try to do this with comprehensions. It is efficient. So, your problem can be solved with list comprehensions like this
rows = 4
cols = 4
grid = [[0] * cols for _ in range(rows)]
print [[(i * 10) for i in xrange(1, len(row) + 1)] for row in grid]
Output
[[10, 20, 30, 40], [10, 20, 30, 40], [10, 20, 30, 40], [10, 20, 30, 40]]
You need to change your code to:
for i in range(nrows):
val = 10
for j in range(ncols):
grid[i][j] = val
val += 10
def matrix(grid):
nrows = len(grid)
ncols = len(grid[0])
grid[0][0]=10;
for i in range(nrows):
for j in range(ncols):
if(j!=0)
grid[i][j] = grid[i][j-1]+10;
else
grid[i][j]=10;
for row in grid:
print(row)

Categories