Python 3: Multiply a vector by a matrix without NumPy - python

I'm fairly new to Python and trying to create a function to multiply a vector by a matrix (of any column size).
e.g.:
multiply([1,0,0,1,0,0], [[0,1],[1,1],[1,0],[1,0],[1,1],[0,1]])
[1, 1]
Here is my code:
def multiply(v, G):
result = []
total = 0
for i in range(len(G)):
r = G[i]
for j in range(len(v)):
total += r[j] * v[j]
result.append(total)
return result
The problem is that when I try to select the first row of each column in the matrix (r[j]) the error 'list index out of range' is shown. Is there any other way of completing the multiplication without using NumPy?

The Numpythonic approach: (using numpy.dot in order to get the dot product of two matrices)
In [1]: import numpy as np
In [3]: np.dot([1,0,0,1,0,0], [[0,1],[1,1],[1,0],[1,0],[1,1],[0,1]])
Out[3]: array([1, 1])
The Pythonic approach:
The length of your second for loop is len(v) and you attempt to indexing v based on that so you got index Error . As a more pythonic way you can use zip function to get the columns of a list then use starmap and mul within a list comprehension:
In [13]: first,second=[1,0,0,1,0,0], [[0,1],[1,1],[1,0],[1,0],[1,1],[0,1]]
In [14]: from itertools import starmap
In [15]: from operator import mul
In [16]: [sum(starmap(mul, zip(first, col))) for col in zip(*second)]
Out[16]: [1, 1]

I think the problem with your code was that you loop through the rows of the matrix rather than by the columns. Also you don't reset your 'total' variable after each vector*matrix column calculation. This is what you want:
def multiply(v, G):
result = []
for i in range(len(G[0])): #this loops through columns of the matrix
total = 0
for j in range(len(v)): #this loops through vector coordinates & rows of matrix
total += v[j] * G[j][i]
result.append(total)
return result

i have attached a code for matrix multiplication do follow the example format for one dimensional multiplication (lists of list)
def MM(a,b):
c = []
for i in range(0,len(a)):
temp=[]
for j in range(0,len(b[0])):
s = 0
for k in range(0,len(a[0])):
s += a[i][k]*b[k][j]
temp.append(s)
c.append(temp)
return c
a=[[1,2]]
b=[[1],[2]]
print(MM(a,b))
result is [[5]]

r is an element from G so it's a row which only has two elements. That means you can't use index j to get a value from r because j goes from 0 till the length of v, which is 6 in your example.

I needed solution where the first matrix could be 2-dimensional. Extending the solution from #Kasramvd to accept a two dimensional first matrix. Posted here for reference:
>>> first,second=[[1,0,0,1,0,0],[0,1,1,1,0,0]], [[0,1],[1,1],[1,0],[1,0],[1,1],[0,1]]
>>> from itertools import starmap
>>> from operator import mul
>>> [[sum(starmap(mul, zip(row, col))) for col in zip(*second)] for row in first]
[[1, 1], [3, 1]]

# check matrices
A = [[1,2],[3,4]]
B = [[1,4],[5,6],[7,8],[9,6]]
def custom_mm(A,B):
if len(A[0]) == len(B): -- condition to check if matrix multiplication is valid or not. Making sure matrix is nXm and mXy
result = [] -- final matrix
for i in range(0,len(A)): -- loop through each row of first matrix
temp = [] -- temporary list to hold output of each row of the output matrix where number of elements will be column of second matrix
for j in range(0,len(B[0])): -- loop through each column of second matrix
total = 0
l = 0 -- dummy index to switch row of second matrix
for k in range(0,len(A[0])):
total += A[i][k]*B[l][j]
l = l+1
temp.append(total)
result.append(temp)
return result
else:
return (print("not possible"))
print(custom_mm(A,B))

There is a code that help u to multiply two matrix:
A=[[1,2,3],[4,5,6],[7,8,9]]
B=[[1,2,3],[4,5,6],[7,8,9]]
matrix=[]
def multiplicationLineColumn(line,column):
try:
sizeLine=len(line)
sizeColumn=len(column)
if(sizeLine!=sizeColumn):
raise ValueError("Exception")
res = sum([line[i] * column[i] for i in range(sizeLine)])
return res
except ValueError:
print("sould have the same len line & column")
def getColumn(matrix,numColumn):
size=len(matrix)
column= [matrix[i][numColumn] for i in range(size)]
return column
def getLine(matrix,numLine):
line = matrix[numLine]
return line
for i in range(len(A)):
matrix.append([])
for j in range(len(B)):
matrix[i].append(multiplicationLineColumn(getLine(A,i),getColumn(B,j)))
print(matrix)

Related

find top_k element of numpy ndarray and ignore zero

Given a numpy ndarray like the following
x = [[4.,0.,2.,0.,8.],
[1.,3.,0.,9.,5.],
[0.,0.,4.,0.,1.]]
I want to find the indices of the top k (e.g. k=3) elements of each row, excluding 0, if possible. If there are less than k positive elements, then just return their indices (in a sorted way).
The result should look like (a list of array)
res = [[4, 0, 2],
[3, 4, 1],
[2, 4]]
or just one flatten array
res = [4,0,2,3,4,2,2,4]
I know argsort can find the indices of top k elements in a sorted order. But I am not sure how to filter out the 0.
You can use numpy.argsort with (-num) for getting index as descending. then use numpy.take_along_axis for getting values base index of 2D sorted.
Because you want to ignore zero you can insert zero for other columns after three (as you mention in the question). At the end return value from the sorted values that is not zero.
x = np.array([[4.,0.,2.,0.,8.],[1.,3.,0.,9.,5.],[0.,0.,4.,0.,1.]])
idx_srt = np.argsort(-x)
val_srt = np.take_along_axis(x, idx_srt, axis=-1)
val_srt[:, 3:] = 0
res = idx_srt[val_srt!=0]
print(res)
[4 0 2 3 4 1 2 4]
Try one of these two:
k = 3
res = [sorted(range(len(r)), key=(lambda i: r[i]), reverse=True)[:min(k, len([n for n in r if n > 0]))] for r in x]
or
res1 = [np.argsort(r)[::-1][:min(k, len([n for n in r if n > 0]))] for r in x]
I came up with the following solution:
top_index = score.argsort(axis=1) # score here is my x
positive = (score > 0).sum(axis=1)
positive = np.minimum(positive, k) # top k
# broadcasting trick to get mask matrix that selects top k (k = min(2000, num of positive scores))
r = np.arange(score.shape[1])
mask = (positive[:,None] > r)
top_index_flatten = top_index[:, ::-1][mask]
I compare my result with the one suggested by #I'mahdi and they are consistent.

Matrix multiplication explanation

When we multiply two matrices A of size m x k and B of size k x n we use the following code:
#for resultant matrix rows
for i in range(m):
#for resultant matrix column
for j in range(n):
for l in range(k):
#A's row x B's columns
c[i][j]=c[i][j]+a[i][l]*b[l][j]
are my comments in the code right explanation of the loops? Is there a better explanation of the loops or is there a better thought process to code matrix multiplication?
EDIT1: I am not looking for a better code. My question is about the thought process that goes in when we transform the math of matrix multiplicate into code.
Your code is correct but if you want to add detail comment/explanation like you ask for you can do so:
#for resultant matrix rows
for i in range(m):
#for resultant matrix column
for j in range(n):
#for each entry in resultant matrix we have k entries to sum
for l in range(k):
#where each i, j entry in the result matrix is given by multiplying the
#entries A[i][l] (across row i of A) by the entries B[l][j] (down
#column j of B), for l = 1, 2, ..., k, and summing the results over l:
c[i][j]=c[i][j]+a[i][l]*b[l][j]
EDIT: if you want a better explanation of the loop or thought process than take out #A's row x B's columns comments. and replace it with "where each i, j entry in the result matrix is given by multiplying the entries A[i][l] (across row i of A) by the entries B[l][j] (down column j of B), for l = 1, 2, ..., k, and summing the results over " also don't use l as an iterator it looks like a 1
You can use numpy.dot function. Here's the documentation. Example (extracted from the documentatio):
> a = [[1, 0], [0, 1]]
> b = [[4, 1], [2, 2]]
> np.dot(a, b)
> array([[4, 1],
[2, 2]])
The condition that should always stand in order to do 2 matrices multiplication is that first matrix must have the same amount of rows that the other matrix has columns.
so if matrix_1 is m x n than second matrix_2 should be n x p. The result of the two will have a dimension of m x p
the Pseudocode will be:
multiplyMatrix(matrix1, matrix2)
-- Multiplies rows and columns and sums them
multiplyRowAndColumn(row, column) returns number
var
total: number
begin
for each rval in row and cval in column
begin
total += rval*cval
end
return total
end
begin
-- If the rows don't match up then the function fails
if matrix1:n != matrix2:m return failure;
dim = matrix1:n -- Could also be matrix2:m
newmat = new squarematrix(dim) -- Create a new dim x dim matrix
for each r in matrix1:rows and c in matrix2:columns
begin
end
end
In python either you can do what you did, or you can use ijk-algo, ikj-algo, psyco ikj-algo, Numpy, or SciPy to accomplish this. It appears that Numpy is the fastest and most efficient.
YOUR CODE LOOKS RIGHT AND YOUR COMMENTS ALSO DO LOOK CORRECT

which would be the most time efficient way to perform these nested loops?

for i in range(x):
for j in range(y):
for k in range(z):
if arr[i][j][k] != 0:
arr[i][j][k] = 1
I'm traversing through a 3D array and if any value is not equal to 1, I would like to change it to 1.
If you use numpy, just write:
arr[arr!=0] = 1
or if you only need a boolean array:
result = arr!=0
If you, on the other side, have a list of list of lists:
for plane in arr:
for row in plane:
row[:] = [int(item!=0) for item in row]

broadcast intersection on a numpy array

I am trying to generate a large 2D numpy NxN array (larr) where each cell contains the intersection (c) between lists (a or b) of string elements (director names) belonging both to the unit represented by the row (company i) and the unit represented by the column (company j). The lists (a and b) are taken from another array (marray) where companies are identified by an integer between 1 and N in the column 'nfirm'. I am not interested in the diagonal of the matrix (I substitute NaN).
I came up with the following nested loop but it is very slow and memory consuming. I was wondering whether it is possible to do it in a more efficient way by broadcasting the union operation. Any tip to improve it is very much appreciated. Thanks!
larr = np.empty(shape=(N,N), dtype=object)
for i in range(1,N):
for j in range(1,N):
a= marray['listdir'][marray['nfirm']==i].tolist()
b= marray['listdir'][marray['nfirm']==j].tolist()
c=np.intersect1d(a,b)
if (len(c)>0 and (i!=j)):
larr[i,j]=c
else:
larr[i,j]='NaN'
del a, b, c
Minor improvement: a is recomputed j times but independent of j:
larr = np.empty(shape=(N, N), dtype=object)
for i in range(1, N):
a = marray['listdir'][marray['nfirm']==i].tolist()
for j in range(1, N):
b = marray['listdir'][marray['nfirm']==j].tolist()
c = np.intersect1d(a,b)
if len(c) > 0 and i != j:
larr[i, j] = c
else:
larr[i, j] = 'NaN'
del b
del a
del c
So if I understand correctly,
marray['listdir'] is a list of string representing directors, indexed by movie.
marray['nfirm'] is a list of integers representing companies, also indexed by movie.
You want to create a matrix of directors that have been shared by pairs of companies.
To be more efficient, you can first build a dictionary linking companies to movies, then build the matrix:
firm_movies = [[] for _ in xrange(N)]
for i, m in enumerate(marray['nfirm']):
firm_movies[m].append(i)
larr = np.empty(shape=(N, N), dtype=object)
for i in xrange(N):
larr[i, i] = 'NaN'
for j in xrange(i+1, N):
a = marray['listdir'][firm_movies[i]]
b = marray['listdir'][firm_movies[j]]
c = np.intersect1d(a,b)
larr[i, j] = larr[j, i] = c if len(c)>0 else 'NaN'

How to multiply matrixes using for loops - Python

I have no idea how to even begin doing this
It needs to be a for loop to multiply mtrixes
for example
[[1,2],[3,4]] * [[3,4],[5,6]]
[1 , 2] , [3 , 4]
[3 , 4] *[5 , 6]
Need help much appreciated
I know 90% of dont want to code for me so that's ok
It only needs to be two square matrixes
i'm pretty sure the pattern is looking at it in the list thing
a[1][1]*b[1][1]+a[1][2]*b[2][1] a[1][1]b[1][2]+a[1][2]b[2][2]
a[2][1]b[1][1]+a[2][2]b[2][1] a[2][1]b[1][2]+a[2][2]b[2][2]
result = [] # final result
for i in range(len(A)):
row = [] # the new row in new matrix
for j in range(len(B[0])):
product = 0 # the new element in the new row
for v in range(len(A[i])):
product += A[i][v] * B[v][j]
row.append(product) # append sum of product into the new row
result.append(row) # append the new row into the final result
print(result)
Break it down. Before you try to write a function that multiplies matrices, write one that multiplies vectors. If you can do that, multiplying two matrices is just a matter of multiplying row i and column j for every element i,j of the resultant matrix.
If you look at how matrix multiplication works:
[ 1 2 ] x [ 5 6 ] = [ 1*5+2*7 1*6+2*8 ]
[ 3 4 ] [ 7 8 ] [ 3*5+4*7 3*6+4*8 ]
then you can determine a method to calculate this, e.g. if you are multiplying for element i, j of the output matrix, then you need to multiply everything in row i of the LHS matrix by everything in the column j of the RHS matrix, so that is a single for loop (as the number of elements in the row i is equal to column j).
You also need to cover every combination of i and j for the dimensions of the output matrix, which is a for loop for the columns nested inside a for loop for the rows.
The actual code is, of course, an exercise for you to implement.
>>> A=[[1,2],[3,4]]
>>> B=[[3,4],[5,6]]
>>> n=2
>>> ans=[[0]*n for i in range(n)]
>>> ans
[[0, 0], [0, 0]]
>>> for i in range(n):
... for j in range(n):
... ans[i][j]=sum((A[i][v]*B[v][j] for v in range(n)))
...
>>> ans
[[13, 16], [29, 36]]
I think you just need to simplify the formula of matrix multiplication.
We have A*B=C then:
Cij= the value in the ith row and jth column of the answer. For example above we have C12=16 and C11=13.. (note that this is the 0th position in the array so often we start from 0 instead of 1)
Cij= dot_product(row_i_of_A,column_j_of_B)=sum(row_i_of_A(v)*column_j_of_B(v) for v in range(n))
Because we want the whole answer (all of C), we need to work out all possible Cij. This means we need to try all possible pairs ij, so we loop through i in range(n), j in range(n) and do this for each possible pair.
from numpy import *
m1 = array([[1, 2, 3],[4, 5, 6] ])
m2 = array([[7, 8],[9, 10],[11, 12]])
r = array([[0, 0],[0, 0]])
s = 0
for i in range(2):
for j in range(2):
for k in range(3):
s = s + m1[i][k]*m2[k][j]
r[i][j] = s
s = 0
print(r)
I think append function is not working in a two-dimensional array when we are using numpy module, so this is the way I have solved it.
def matmul(matrix1_,matrix2_):
result = [] # final result
for i in range(len(matrix1_)):
row = [] # the new row in new matrix
for j in range(len(matrix2_[0])):
product = 0 # the new element in the new row
for v in range(len(matrix1_[i])):
product += matrix1_[i][v] * matrix2_[v][j]
row.append(product) # append sum of product into the new row
result.append(row) # append the new row into the final result
return result
u and v are constructed for visualization purpose.
from typing import List
A = [[1,0,0],[-1,0,3]]
B = [[7,0,0],[0,0,0],[0,0,1]]
def mult_mat(A:List[List[int]], B:List[List[int]]) -> List[List[int]]:
n = len(A) # Number of rows in matrix A
m = len(B[0]) # Number of columns in matrix B
ret = [[0 for i in range(m)] for j in range(n)]
for row in range(n):
u = A[row]
for col in range(m):
v = [B[i][col] for i in range(len(B))]
# Here you can calculate ret[row][col] directly without v
# But v is constructed for visualization purpose
ret[row][col] = sum([x*y for x,y in zip(u,v)])
return ret
if __name__ == '__main__':
print(mult_mat(A,B))

Categories

Resources