Quiver vector from high value toward low value - python

What I would like to plot is to make vector from high values to low values.
If code would start from:
a = [[1, 8, 9, 10],[2, 15, 3, -1],[3,1,6,11],[13,15,5,-2]]
X,Y = np.meshgrid(np.arange(4), np.arange(4))
U = ?
V = ?
From this point, I should set U and V components of the vector.
The magnitude of each point would be a[x][y]. I don't have much idea of how I can set U and V to make arrow from high to low value at each grid point.

Here's a solution (doesn't require numpy):
import itertools as it
a = [[1, 8, 9, 10],[2, 15, 3, -1],[3,1,6,11],[13,15,5,-2]]
rowSize = len(a[0])
maxVal = a[0][0]
maxIndex = 0
minVal = a[0][0]
minIndex = 0
for k, v in enumerate(it.chain(*a)): # Loop through a flattened list of the values in the array, and locate the indices of the max and min values.
if v > maxVal:
maxVal = v
maxIndex = k
if v < minVal:
minVal = v
minIndex = k
U = (minIndex % rowSize) - (maxIndex % rowSize)
V = (minIndex / rowSize) - (maxIndex / rowSize)
print U, ",", V
OUTPUT
2 , 2
Note that you haven't defined what behavior you want when there are two equal maximum values, as there are in your example. The code above uses the "first" (upper-leftmost) one as the true maximum, and ignores all others.
Explanation:
I flattened the list (which means I read the values like you would the words on a book - first the first row, then the second row, then the third row). Each value got a single index, like so:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
For example, a value in the second row and the third column would get an index of 6, since it's the 7th value if you read the array like a book.
At the end, when we've found the index of the max or min value, we need to get 2D coordinates from the 1D index. So, we can use the mod operator (%) to get the x-value.
For example, 6 % 4 = 2, so X = 2 (the 3rd column)
To get the Y value, we use the integer division operator (/).
For example, 6 / 4 = 1, so Y = 1 (the second row)
The formulas for U and V are simply taking the X and Y values for the max and min and subtracting them to get the vector coordinates, like so:
U = xMin - xMax
V = yMin - yMax
If you're wondering, "why the heck didn't he just use the meshgrid solution I started with", there are two reasons: One, using a non-standard library like numpy is generally undesirable if there is an easy way to solve the problem without non-standard libraries, and two, if you ever need to deal with large arrays, generating a large meshgrid could become time/memory expensive.
Solution that picks shortest vector:
import itertools as it
a = [[1, 8, 9, 10],[2, 15, 3, -1],[3,1,6,11],[13,15,5,-2]]
rowSize = len(a[0])
values = sorted(enumerate(it.chain(*a)), key=lambda x:x[1]) # Pair each value with its 1D index, then sort the list.
minVal = values[0][1]
maxVal = values[-1][1]
maxIndices = map(lambda x:x[0], filter(lambda x:x[1]==maxVal, values)) # Get a list of all the indices that match the maximum value
minIndices = map(lambda x:x[0], filter(lambda x:x[1]==minVal, values)) # Get a list of all the indices that match the minimum value
def getVector(index1, index2, rowSize): # A function that translates a pair of 1D index values to a "quiver vector"
return ((index1 % rowSize) - (index2 % rowSize), (index1 / rowSize) - (index2 / rowSize))
vectors = [getVector(k2, k1, rowSize) for k1, k2 in it.product(maxIndices, minIndices)] # produce a list of the vectors formed by all possible combinations of the 1D indices for maximum and minimum values
U, V = sorted(vectors, key=lambda x:(x[0]*x[0] + x[1]*x[1])**0.5)[0]
print U, ",", V
OUTPUT
2 , 0

Related

Find maximum value and indices of a maximum without using max built in functions

Like the title says, I'm trying to find the max value and location of the argument(s) without using any variation of the built in max functions.
I was able to piece this together for a basic np.array, but I'm having difficulty translating it into a matrix ... I think because of how it is indexed.
Here's what I have for the np.array:
a = np.array((1,2,2,3,4,3,2,1,4,3))
def argmax(x):
maximum = 0
for i in range(len(x)):
if x[i] > maximum: maximum = x[i]
pos = np.argwhere(x == maximum)[0][0]
return(print('The maximum value of the array is', maximum, 'and is located at index', pos))
argmax(a)
The maximum value of the array is 4 and is located at index 4.
I'm trying to create something similar for any size matrix without using built in max functions. Can someone help me with the function and help me understand the difference in indexing between a basic array and a matrix?
This works for 1d arrays and 2d arrays:
import numpy as np
import math
matrix = np.arange(20).reshape(4, 5)
print(matrix)
# Important
matrix = np.atleast_2d(matrix)
# set maximum to -inf
maximum = -math.inf
# Search maximum
for j in range(matrix.shape[1]):
for i in range(matrix.shape[0]):
maximum = matrix[i][j] if matrix[i][j] > maximum else maximum
# More than 1 maximum, take the first one?
pos = np.argwhere(matrix == maximum)[0]
print(
f"The maximum value of the array is: {maximum}, located at: row {pos[0]}, column {pos[1]}"
)
Outputs:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
The maximum value of the array is: 19, located at: row 3, column 4
I'm assuming that you want to find the maxima along a given axis. Otherwise, do np.unravel_index(argmax(a.ravel()), a.shape).
First let's define a function that steps along the given dimension and keeps track of both the maxima and the indices at which they occur:
def argmax(a, axis):
# index
cur = [slice(None) for _ in range(a.ndim)]
cur[axis] = 0
# trackers
val = a[tuple(index)]
ind = np.zeros(val.shape, dtype=int)
# loop
for i in range(1, a.shape[axis]):
index[axis] = i
v = a[tuple(index)]
mask = v > val
val[mask] = v[mask]
ind[mask] = i
return ind
This returns the index along axis. If you want to get the other indices, do something like
all_indices = list(np.indices(a.shape))
all_indices[axis] = ind
all_indices = tuple(all indices)
Or alternatively,
all_indices = [slice(None) for _ range(a.ndim)]
all_indices[axis] = ind
all_indices = tuple(all indices)
This function skips a couple of corner cases, like when a.shape[axis] == 0 and a.ndim == 0, but you can easily handle them with a simple preliminary test.
You can also special-case axis=None with a recursive call as shown in the beginning of the answer.
If you want to allow multiple axes simultaneously, swap them all to the end, and reshape them into a single axis. So a hybrid of the axis=None and normal processing.
Here is a way to do it for ANY shape and dimensions array (it assumes values are non-negative since you initialize maximum with 0 and returns the first incidence of maximum only as you did in your original answer. Of course you can easily change them):
def argmax(x):
maximum = 0
for i, v in enumerate(x.reshape(-1)):
if v > maximum:
maximum = v
pos = i
print('The maximum value of the array is', maximum, 'and is located at index', np.unravel_index(pos, x.shape))
argmax(a)
Example:
a = np.random.randint(0,10,(3,4))
#[[7 6 2 6]
# [7 2 0 5]
# [4 0 8 7]]
output:
The maximum value of the array is 8 and is located at index (2, 2)

Compare if every element of a list is larger then every other elements

I want to compare if element one of a list is larger then every other element(same for every other element).
If one element is larger than an other it gets a 1. The sum of 1s (depending on the number of comparison "won") should be store in a way that let me know how many comparison are wow for each specif element of the list.
To clarify every element to a list would be an individual with an ID
Python
#Here I create 10 random values which I call individual with the random
#funcion plus mean and standard deviation
a, b = 3, 10
mu, sigma = 5.6, 2
dist = stats.truncnorm((a - mu) / sigma, (b - mu) / sigma, loc=mu, scale=sigma)
individuals = dist.rvs(10)
#Initialize the list where I want to store the 1s
outcome = num.zeros(n)
#Trying to loop through all the elements
for k in range(0, n):
for j in range(0, n):
if individuals[k] == individuals[j]:
continue
elif individuals[k] < individuals[j]:
continue
elif individuals[k] > individuals[j]:
outcome[i] += 1
return outcome[i]
I end up having an outcome with one single value.
Probably it summed up every 1s in the first element
Here is a more efficient way, by sorting the list first, which makes the process O(n*log(n)) instead of O(n**2).
We sort the list, keeping the original index of each value (this is O(n*log(n)).
Then, we go once over the list to set the output counts, which are the indices of the values in the sorted list, except for the duplicates - in this case, we just keep track of the number of identical values to adjust the result.
def larger_than(values):
ordered_values = sorted((value, index) for index, value in enumerate(values))
out = [None] * len(values)
# take care of equal values
equals = 0
prev = None
for rank, (value, index) in enumerate(ordered_values):
if value == prev:
equals += 1
else:
equals = 0
prev = value
out[index] = rank - equals
return out
Some test:
values = [1, 4, 3, 3, 10, 1, 5, 2, 7, 6]
print(larger_than(values))
# [0, 5, 3, 3, 9, 0, 6, 2, 8, 7]

Calculating Distance Between Two Items in a List

I am trying to Calculate the Distance or Length between two items in a list
Question: Find the length of the longest subsequence in which the value 6 does not occur. (This number can be zero, if only 6 were in the list.)
For example, in the trial 66423612345654 the longest subsequence which the value 6 does not occur is 12345. and such the distance or length we can say is 5
Note: i have tried using trackers and for loops but i guess i am having trouble with the break positioning maybe
Throws=[6,6,2,5,3,6,6,3,6,6,3,6,6,6]
Max=0
Min=0
for i in range (0,len(Throws)):
Tracker1 = Throws[i]
if Tracker1==6:
for k in range (i+1,len(Throws)):
Tracker2 = Throws[k]
if Tracker2 ==6 and Throws[k-1]!=6:
Min = k-i
if Min>Max:
Max=Min
break
print(Max)
The Max value for the given code should be 3
,Thanks in advance
Easy to understand:
THROWS = [6, 6, 2, 5, 3, 6, 6, 3, 6, 6, 3, 6, 6, 6]
CONTROL_NUM = 6
max = 0
count = 0
for current in THROWS:
if current != CONTROL_NUM:
count += 1
if count > max:
max = count
else:
count = 0
print(max)
You can use use join() and split() to convert sequence to string and find the longest distance using the following:
throws = [6,6,4,2,3,6,1,2,3,4,5,6,5,4]
max_seq_length = max([len(sub_list) for sub_list in "".join([str(i) for i in throws]).split("6")])
One-line, recursive solution:
f = lambda s, v: v in s and max(s.index(v), f(s[s.index(v) + 1:], v)) or len(s)
So, in your case:
f([6,6,2,5,3,6,6,3,6,6,3,6,6,6], 6))
gives 3 as output.
The main idea is that the length of a subsequence not containing a value is the length of the subsequnce between two consecutive occurences of that value. The base case is when the value is not present at all in the sequence, so that the longest subsequence not containing it is the subsequence itself.
The method index provides you with the position of the first occurrence of a value, so the length of the prefix of the sequence not containing the value is the value given by the index method. Recursively, you can search for the other prefixes, looking at subsequences starting at the immediate position after the occurrence you have just found, til you reach the end of the input sequence.
Use itertools.groupby:
max(len(list(g)) for k, g in groupby(Throws, lambda x: x != 6) if k)
Code:
from itertools import groupby
Throws = [6,6,2,5,3,6,6,3,6,6,3,6,6,6]
print(max(len(list(g)) for k, g in groupby(Throws, lambda x: x != 6) if k))
# 3

How to generate and filter efficiently all combinations of a list of list product

Hello guys here is the problem. I have something like this in input [[1,2,3],[4,5,6],[7,8,9]]...etc
And i want to generate all possible combination of product of those list and then multiply each elements of the resulting combination beetween them to finally filter the result in a interval.
So first input a n list [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]...etc
Which will then give (1,4,7,10)
(1,4,7,11)
(1,4,7,12)
and so on
Then combination of those result for k in n like (1,4,7)(1,4,10)(1,7,10) for the first row
The multiplication of x as 1*4*7 = 28, 1*4*10 = 40, 1*7*10 = 70
And from this get only the unique combination and the result need in the interval choosed beforehand : if x > 50 and x < 100 i will get (1,7,10) : 70
I did try
def mult(lst): #A function mult i'm using later
r = 1
for element in lst:
r *= element
return round(r)
s = [] #Where i add my list of list
for i in range(int(input1)):
b = input("This is line %s : " % (i+1)).split()
for i in range(len(b)):
b[i] = float(b[i])
s.append(b)
low_result = input("Expected low_result : ")
high_result = input("Expected high_result : ")
combine = []
my_list = []
for element in itertools.product(*s):
l= [float(x) for x in element]
comb = itertools.combinations([*l], int(input2))
for i in list(comb):
combine.append(i)
res = mult(i)
if res >= int(low_result) and res <= int(high_result):
my_list.append(res)
f = open("list_result.txt","a+")
f.write("%s : result is %s\n" % (i, res))
f.close()
And it always result in memory error cause there is too many variation with what i'm seeking.
What i would like is a way to generate from a list of list of 20 elements or more all the product and resulting combination of k in n for the result(interval) that i need.
As suggested above, I think this can be done without exploding your memory by never holding an array in memory at any time. But the main issue is then runtime.
The maths
As written we are:
Producing every combination of m rows of n items n ** m
Then taking a choice of c items from those m values C(m, c)
This is very large. If we have m=25 rows, of n=3 items each and pick c=3 items in them we get:
= n ** m * C(m, c)
= 3 ** 25 * 2300 - n Choose r calculator
= 1.948763802×10¹⁵
If instead we:
Choose c rows from the m rows: C(m, c) as before
Then pick every combination of n items from these c rows: n ** c
With m=25 rows, of n=3 items each and pick c=3 items in them we get:
= n ** c * C(m, c)
= 3 ** 3 * 2300
= 20700
This is now a solvable problem.
The code
from itertools import product, combinations
def mult(values, min_value, max_value):
"""
Multiply together the values, but return None if we get too big or too
small
"""
output = 1
for value in values:
output *= value
# Early return if we go too big
if output > max_value:
return None
# Early return if we goto zero (from which we never return)
if output == 0 and min_value != 0:
return None
if output < min_value:
return None
return output
def yield_valid_combos(values, choose, min_value, max_value):
# No doubt an even fancier list compression would get this too
for rows in combinations(values, choose):
for combos in product(*rows):
value = mult(combos, min_value, max_value)
if value is not None:
yield combos, value
values = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
with open('list_result.txt', 'w') as fh:
for selection, value in yield_valid_combos(
values, choose=3, min_value=50, max_value=100):
fh.write('{}: result is {}\n'.format(selection, value))
This solution also returns no duplicate answers (unless the same value appears in multiple rows).
As an optimisation the multiplication method attempts to return early if we detect the result will be too big or small. We also only open the file once and then keep adding rows to it as they come.
Further optimisation
You can also optimise your set of values ahead of time by screening out values which cannot contribute to a solution. But for smaller values of c, you may find this is not even necessary.
The smallest possible combination of values is c items from the set of the smallest values in each row. If we take the c - 1 smallest items from the set of smallest values, mutliply them together and then divide the maximum by this number, it gives us an upper bound for the largest value which can be in a solution. We can then then screen out all values above this value (cutting down on permutations)

Matrix match in python

How can I find the best "match" for small matrix in big matrix?
For example:
small=[[1,2,3],
[4,5,6],
[7,8,9]]
big=[[2,4,2,3,5],
[6,0,1,9,0],
[2,8,2,1,0],
[7,7,4,2,1]]
The match is defined as difference of numbers in matrix, so match in position (1,1) is as if number 5 from small would be on number 0 from big matrix (so the central number from small matrix in coordinates (1,1) of big matrix.
The match value in position (1,1) is:
m(1,1)=|2−1|+|4−2|+|2−3|+|6−4|+|0−5|+|1−6|+|2−7|+|8−8|+|2−9|=28
The goal is to find the lowest difference posible in those matrixes.
The small matrix always has odd number of lines and columns, so it's easy to find it's centre.
You can iterate through the viable rows and columns and zip the slices of big with small to calculate the sum of differences, and use min to find the minimum among the differences:
from itertools import islice
min(
(
sum(
sum(abs(x - y) for x, y in zip(a, b))
for a, b in zip(
(
islice(r, col, col + len(small[0]))
for r in islice(big, row, row + len(small))
),
small
)
),
(row, col)
)
for row in range(len(big) - len(small) + 1)
for col in range(len(big[0]) - len(small[0]) + 1)
)
or in one line:
min((sum(sum(abs(x - y) for x, y in zip(a, b)) for a, b in zip((islice(r, col, col + len(small[0])) for r in islice(big, row, row + len(small))), small)), (row, col)) for row in range(len(big) - len(small) + 1) for col in range(len(big[0]) - len(small[0]) + 1))
This returns: (24, (1, 0))
Done by hand:
small=[[1,2,3],
[4,5,6],
[7,8,9]]
big=[[2,4,2,3,5],
[6,0,1,9,0],
[2,8,2,1,0],
[7,7,4,2,1]]
# collect all the sums
summs= []
# k and j are the offset into big
for k in range(len(big)-len(small)+1):
# add inner list for one row
summs.append([])
for j in range(len(big[0])-len(small[0])+1):
s = 0
for row in range(len(small)):
for col in range(len(small[0])):
s += abs(big[k+row][j+col]-small[row][col])
# add to the inner list
summs[-1].append(s)
print(summs)
Output:
[[28, 29, 38], [24, 31, 39]]
If you are just interested in the coords in the bigger one, store tuples of (rowoffset,coloffset,sum) and dont box lists into lists. You can use min() with a key that way:
summs = []
for k in range(len(big)-len(small)+1):
for j in range(len(big[0])-len(small[0])+1):
s = 0
for row in range(len(small)):
for col in range(len(small[0])):
s += abs(big[k+row][j+col]-small[row][col])
summs .append( (k,j,s) ) # row,col, sum
print ("Min value for bigger matrix at ", min(summs , key=lambda x:x[2]) )
Output:
Min value for bigger matrix at (1, 0, 24)
If you had "draws" this would only return the one with minimal row, col offset.
Another possible solution would be this, returning the minimum difference and the coordinates in the big matrix:
small=[[1,2,3],
[4,5,6],
[7,8,9]]
big=[[2,4,2,3,5],
[6,0,1,9,0],
[2,8,2,1,0],
[7,7,4,2,1]]
def difference(small, matrix):
l = len(small)
return sum([abs(small[i][j] - matrix[i][j]) for i in range(l) for j in range(l)])
def getSubmatrices(big, smallLength):
submatrices = []
bigLength = len(big)
step = (bigLength // smallLength) + 1
for i in range(smallLength):
for j in range(step):
tempMatrix = [big[j+k][i:i+smallLength] for k in range(smallLength)]
submatrices.append([i+1,j+1,tempMatrix])
return submatrices
def minDiff(small, big):
submatrices = getSubmatrices(big, len(small))
diffs = [(x,y, difference(small, submatrix)) for x, y, submatrix in submatrices]
minDiff = min(diffs, key=lambda elem: elem[2])
return minDiff
y, x, diff = minDiff(small, big)
print("Minimum difference: ", diff)
print("X = ", x)
print("Y = ", y)
Output:
Minimum difference: 24
X = 1
Y = 2
I would use numpy to help with this.
To start I would convert the arrays to numpy arrays
import numpy as np
small = np.array([[1,2,3], [4,5,6], [7,8,9]])
big = np.array([[2,4,2,3,5], [6,0,1,9,0], [2,8,2,1,0], [7,7,4,2,1]])
then I would initialize an array to store the results of the test (optional: a dictionary as well)
result_shape = np.array(big.shape) - np.array(small.shape) + 1
results = np.zeros((result_shape[0], result_shape[1]))
result_dict = {}
Then iterate over the positions in which the small matrix can be positioned over the large matrix and calculate the difference:
insert = np.zeros(big.shape)
for i in range(results.shape[0]):
for j in range(results.shape):
insert[i:small.shape[0] + i, j:small.shape[1] + j] = small
results[i, j] = np.sum(np.abs(big - insert)[i:3+i, j:3+j])
# Optional dictionary
result_dict['{}{}'.format(i, j)] = np.sum(np.abs(big - insert)[i:3+i, j:3+j])
Then you can print(results) and obtain:
[[ 28. 29. 38.]
[ 24. 31. 39.]]
and/or because the position of the small matrix over the big matrix is stored in the keys of the dictionary, you can get the position of the small matrix over the large matrix where the difference is smallest by key manipulation:
pos_min = [int(i) for i in list(min(result_dict, key=result_dict.get))]
and if you print(pos_min), you obtain:
[1, 0]
then if you need the index for anything you can iterate over it if required. Hope this helps!

Categories