Finding index where one sequence is greater than another - python

I have two numpy arrays and I'd like to find the index at which the data in one array becomes greater than another. The following code seems to do the trick but I'm wondering if there is a better way:
# For example
import numpy as np
x=np.arange(-10,10,0.01)
f1 = x+3.0
f2 = 2*x
cross_over_index = np.nonzero(f2 > f1)[0][0]

Because your question is only meaningful if the arrays are ordered, you can find the crossover point with a binary search that will be much faster for large arrays:
# Find first index of a2 > a1
def crossover(a1, a2):
bottom = 0
top = min(len(a1) - 1, len(a2) - 1)
if a2[top] <= a1[top]:
return -1
while top > bottom:
mid = (top + bottom) >> 1
if a2[mid] > a1[mid]:
top = mid
else:
bottom = mid + 1
return top
f1 = [ (x + 20) for x in range(80) ]
f2 = [ (2 * x) for x in range(100) ]
print( crossover( f1, f2 ) )
This should (and does) print "21".

If you're looking for the solution of the equation f1(x) = f2(x), you could also do this:
np.argmin(abs(f2-f1))
# 1300
and to get x there, of course
x[np.argmin(abs(f2-f1))]
# 3.0
But note that this will only sometimes give the same answer as what you technically asked for (which in this example returns i0 --> 1301 and x0 --> 3.01 ( which is the solution plus stepsize of x).

Related

minimal absolute value of the difference between A[i] and B[i] (array A is strictly increasing, array B is strictly decreasing)

Given two sequences A and B of the same length: one is strictly increasing, the other is strictly decreasing.
It is required to find an index i such that the absolute value of the difference between A[i] and B[i] is minimal. If there are several such indices, the answer is the smallest of them. The input sequences are standard Python arrays. It is guaranteed that they are of the same length. Efficiency requirements: Asymptotic complexity: no more than the power of the logarithm of the length of the input sequences.
I have implemented index lookup using the golden section method, but I am confused by the use of floating point arithmetic. Is it possible to somehow improve this algorithm so as not to use it, or can you come up with a more concise solution?
import random
import math
def peak(A,B):
def f(x):
return abs(A[x]-B[x])
phi_inv = 1 / ((math.sqrt(5) + 1) / 2)
def cal_x1(left,right):
return right - (round((right-left) * phi_inv))
def cal_x2(left,right):
return left + (round((right-left) * phi_inv))
left, right = 0, len(A)-1
x1, x2 = cal_x1(left, right), cal_x2(left,right)
while x1 < x2:
if f(x1) > f(x2):
left = x1
x1 = x2
x2 = cal_x1(x1,right)
else:
right = x2
x2 = x1
x1 = cal_x2(left,x2)
if x1 > 1 and f(x1-2) <= f(x1-1): return x1-2
if x1+2 < len(A) and f(x1+2) < f(x1+1): return x1+2
if x1 > 0 and f(x1-1) <= f(x1): return x1-1
if x1+1 < len(A) and f(x1+1) < f(x1): return x1+1
return x1
#value check
def make_arr(inv):
x = set()
while len(x) != 1000:
x.add(random.randint(-10000,10000))
x = sorted(list(x),reverse = inv)
return x
x = make_arr(0)
y = make_arr(1)
needle = 1000000
c = 0
for i in range(1000):
if abs(x[i]-y[i]) < needle:
c = i
needle = abs(x[i]-y[i])
print(c)
print(peak(x,y))
Approach
The poster asks about alternative, simpler solutions to posted code.
The problem is a variant of Leetcode Problem 852, where the goal is to find the peak index in a moutain array. We convert to a peak, rather than min, by computing the negative of the abolute difference. Our aproach is to modify this Python solution to the Leetcode problem.
Code
def binary_search(x, y):
''' Mod of https://walkccc.me/LeetCode/problems/0852/ to use function'''
def f(m):
' Absoute value of difference at index m of two arrays '
return -abs(x[m] - y[m]) # Make negative so we are looking for a peak
# peak using binary search
l = 0
r = len(arr) - 1
while l < r:
m = (l + r) // 2
if f(m) < f(m + 1): # check if increasing
l = m + 1
else:
r = m # was decreasing
return l
Test
def linear_search(A, B):
' Linear Search Method '
values = [abs(ai-bi) for ai, bi in zip(A, B)]
return values.index(min(values)) # linear search
def make_arr(inv):
random.seed(10) # added so we can repeat with the same data
x = set()
while len(x) != 1000:
x.add(random.randint(-10000,10000))
x = sorted(list(x),reverse = inv)
return x
# Create data
x = make_arr(0)
y = make_arr(1)
# Run search methods
print(f'Linear Search Solution {linear_search(x, y)}')
print(f'Golden Section Search Solution {peak(x, y)}') # posted code
print(f'Binary Search Solution {binary_search(x, y)}')
Output
Linear Search Solution 499
Golden Section Search Solution 499
Binary Search Solution 499

How can I calculate conditional counting for each entries of a tuple?

def Trigger(V1, P_T, N1, N2): # N1 = N_W # N2 = N_A
V = np.transpose(V1[:N1])
c = 0
for l in range(N2): # over number of antennas
if ( sum( (np.array(V[l]) >= P_T ) ) >= 2 ):
c = c + 1
if(c >= 4):
Trigger = 1
else:
Trigger = 0
return Trigger
N_W = 50
N_A = 90
P_Th = 2.0 * 5.0
for m in range(N_W):
Q = [ np.float32( np.random.normal(0, 5.0, N_A) ) ] # working
Q = [number**2 for number in Q]
V_G.append(np.array(Q))
Q.clear()
T = Trigger(V_G, P_Th, N_W, N_A)
So, basically, I have a tupple V1. After taking transpose (i.e. V), I want to calculate for each entry of V, i.e. V[1], V[2]...and so on, (each of these are 1D-arrays), how many numbers are there with value greater or equal to "P_T". However, I have been facing the following problem on compilation.
if ( sum( (np.array(V[l]) >= P_T ) ) >= 2 ):
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
where am I committing the mistake?
We can diagnose the issue by first splitting up the line that is giving you the error to work out which bit is causing errors
if ( sum( (np.array(V[l]) >= P_T ) ) >= 2 ):
Which can be split up to be:
test = np.array(V[l]) >= P_T
if (sum(t) >= 2):
If we then inspect test we can see it is a numpy array of booleans. The error occurs because we are calling the built-in version of sum which does not accept this as the input.
In this case it is a simple fix, just use the numpy version of sum np.sum() to count how many elements are true in your boolean array:
if (np.sum(np.array(V[l] >= P_T)) >= 2):

Is there another way to find item n in this recursive sequence?

The sequence is:
an = an-1 + (2 * an-2)
a0 = 1, a1= 1. Find a100
The way I did it is making a list.
#List 'a' with a0 = 1 , a1 = 1.
a = [1,1]
#To get the a100, implement 'i' as the index value of the list.
for i in range (2,101):
x = a[i-1] + (2 * a[i-2])
print( str(len(a)) + (": ") + str(x))
#Save new value to list
a.append(x)
Is there another way to do this where you can just directly get the value of a100? Or the value of a10000.. it will take up so much memory.
For this specific case, the sequence appears to be known as the Jacobsthal sequence. Wikipedia gives a closed form expression for a_n that can be expressed as follows:
def J(n):
return (2**(n+1) - (1 if n % 2 else -1))//3
Slightly more generally, you can use fast matrix exponentiation to find a specific value of a_n in O(log n) matrix operations. The approach here is a slight modification of this.
import numpy as np
def a(n):
mat = np.array([[1, 2], [1, 0]], dtype=object) # object for large integers
return np.linalg.matrix_power(mat, n)[0,0]
Here is the value for a_1000:
7143390714575115472989500327066678737076032078036890716291669255802340340832907483287989192104639054183964486117020978834580968571282093623989718383132383202623045183216153990280716403374914094585302788102030983322387960844932511706110362630718041943047464318457694778440286554435082924558137112046251
This recurrence relation has a closed form solution:
a = lambda n: (2**(n+1) + (-1)**n)//3
Then
a(0) == 1
a(1) == 1
a(2) == 3
...
Use Wolfram Alpha solve for the closed form solution.
For a more general solution, sympy's rsolve can generate a formula for linear recurrences. And then use substitution to find particular values.
from sympy import rsolve, Function, symbols
f = Function('f')
n = symbols('n', integer=True)
T = f(n) - f(n - 1) - 2 * f(n - 2)
sol = rsolve(T, f(n), {f(0): 1, f(1): 1})
print(sol.factor())
for k in range(6):
print(f'a[{10**k}] = {sol.subs({n:10**k})}')
This finds the formula: ((-1)**n + 2*2**n)/3 and substituting various values gives:
a[1] = 1
a[10] = 683
a[100] = 845100400152152934331135470251
a[1000] = 7143390714575115472989500327066678737076032078036890716291669255802340340832907483287989192104639054183964486117020978834580968571282093623989718383132383202623045183216153990280716403374914094585302788102030983322387960844932511706110362630718041943047464318457694778440286554435082924558137112046251
a[10000] = 13300420779205055899224947751223900558823312212574616365680059665686292553481297754613307789357463065266220752948806082847704327566275854078395857288064215971903820031195863017843497700844039930347033391278795541028339072307078736457006049910726416592060326596558672835961088838567081045539649268371274925376816731095916294031173247751323635481912358774462877183753093841891253840488152356727760984122637587639312975932940560640357511880709747618222262691017043766353735428453489979600223956211100972865182186443850404115054687605329465453071585497122508186691535256991501267222976387636433705286400943222614410489725426171396919846079518533884638490449629415374679171890883668485549192847140249201910928687618755494267749463781127049374279769561549759200832570764870138287994839741197500087328573494472227205070621546774178994858997503894208562707691159300991409504210074059830342802209213468621093971730976504006937230561044048029975244677676707947087336124281517272447267049737611904634607637370045500833604005013228174598706158078702963192048604263495032226147988471602982108251173897742022519137359868942131422329103081800375446624970338827853981873988860876269047918349845673238184625284288814399599917924440538912558558685095521850114849105048496522741529593155873907738282168861316542080131736118854643798317265443020838956090639908522753418790270855651099392460347365053921743882641323846748271362887055383912692879736402269982104388805781403942200602501882277026496929598476838303527006808207298214407168983217160516849324232198998893837958637097759081249712999519344381402467576288757211476207860932148655897231556293513976121900670048618498909700385756334067235325208259649285799693889564105871362639412657210097186118095746465818754306322522134720983321447905340926047485500603884544957480384983947611769143791817076603055269994974019086721023722205420067991783904156229025970272783748933896591684108429045765889012975813584862160062970831282169566933785351515891836917604484599090827358327607311145704700506065400164526586785514617302254188281302685535172938965970009784445593131997924161090875584262602248970534271757827918474036922817159666073457645479797721100990086996148246631809842046103645478455250800241851505149187576887740797874187195112987924800865762440512367759907023068198581038345298256830912964615391929510632144672034080214910330858779357159414245558929061170945822567007313514409276959727327732103102944890874437957354081499958646666151187821572015407908429716866090505450005466559490856410166587392640154829574782514412057571343645656039081553195235917082324370960357975081345975714019208241045008362225535513352731779100379038105003677818345932796086474225126766610787543447696005152433715459704967280220123536564742545543604882702212692308056024281175802607700426526000495235781464187268985316355546978912530579053491968145752746720495213034211965438416298865678974339803258684849814383125421063166939821410053665460303868944551299858094210708807124261007787849536528397806251

More information on output array with equation and indicies

I have a math function whose output is defined by two variables, x and y.
The function is e^(x^3 + y^2).
I want to calculate every possible integer combination between 1 and some defined integer for x and y, and place them in an array so that each output is aligned with the cooresponding x value and y value index. So something like:
given:
x = 3
y = 5
output would be an array like this:
f(1,1) f(1,2) f(1,3)
f(2,1) f(2,2) f(2,3)
f(3,1) f(3,2) f(3,3)
f(4,1) f(4,2) f(4,3)
f(5,1) f(5,2) f(5,3)
I feel like this is an easy problem to tackle but I have limited knowledge. The code that follows is the best description.
import math
import numpy as np
equation = math.exp(x**3 + y**2)
#start at 1, not zero
i = 1
j = 1
#i want an array output
output = []
#function
def shape_f (i,j):
shape = []
output.append(shape)
while i < x + 1:
while j < y +1:
return math.exp(i**3 + j**2)
#increase counter
i = i +1
j = j +1
print output
I've gotten a blank array recently but I have also gotten one value (int instead of an array)
I am not sure if you have an indentation error, but it looks like you never do anything with the output of the function shape_f. You should define your equation as a function, rather than expression assignment. Then you can make a function that populates a list of lists as you describes.
import math
def equation(x, y):
return math.exp(x**3 + y**2)
def make_matrix(x_max, y_max, x_min=1, y_min=1):
out = []
for i in range(x_min, x_max+1):
row = []
for j in range(y_min, y_max+1):
row.append(equation(i, j))
out.append(row)
return out
matrix = make_matrix(3, 3)
matrix
# returns:
[[7.38905609893065, 148.4131591025766, 22026.465794806718],
[8103.083927575384, 162754.79141900392, 24154952.7535753],
[1446257064291.475, 29048849665247.426, 4311231547115195.0]]
We can do this very simply with numpy.
First, we use np.arange to generate a range of values from 0 (to simplify indexing) to a maximum value for both x and y. We can perform exponentiation, in a vectorised manner, to get the values of x^3 and y^2.
Next, we can apply np.add on the outer product of x^3 and y^3 to get every possible combination thereof. The final step is taking the natural exponential of the result:
x_max = 3
y_max = 5
x = np.arange(x_max + 1) ** 3
y = np.arange(y_max + 1) ** 2
result = np.e ** np.add.outer(x, y)
print(result[2, 3]) # e^(2 ** 3 + 3 ** 2)
Output:
24154952.753575277
A trivial solution would be to use the broadcasting feature of numpy with the exp function:
x = 3
y = 5
i = np.arange(y).reshape(-1, 1) + 1
j = np.arange(x).reshape(1, -1) + 1
result = np.exp(j**3 + y**2)
The reshape operations make i into a column with y elements and j into a row with x elements. Exponentiation does not change those shapes. Broadcasting happens when you add the two arrays together. The unit dimensions in one array get expanded to the corresponding dimension in the other. The result is a y-by-x matrix.

Overlap fraction between two numeric ranges

I want to compute the overlap fraction of two numeric ranges. Let me illustrate my question with an example since I believe that it will be easier to understand.
Lets say that I have two numeric ranges:
A = [1,100]
B = [25,100]
What I want to know (and code) is how much is B overlapping A and viceversa (how much is A overlapping B)
In this case, A overlaps B (as a fraction of B) by 100% and B overlaps A (as a fraction of A) by 75% percent.
I have try been trying to code this in python, but I am struggling and I can't find the proper solution for computing both fractions
What I have been able to achieve so far is the following:
Given the start and end of both numeric ranges, I have been able to figure out if the two numerical ranges overlap (from other stackoverflow post)
I have done this with the following code
def is_overlapping(x1,x2,y1,y2):
return max(x1,y1) <= min(x2,y2)
thanks!
Here's a fast solution without for loops:
def overlapping(x1,x2,y1,y2):
#A = [x1,x2]
#B = [y1,y1]
# Compute the B over A
if(x1 <= y1 and x2 >= y2): # Total overlapping
return 1
elif(x2 < y1 or y2 < x1):
return 0
elif(x2 == y1 or x1 == y2):
return 1/float(y2 - y1 + 1)
return (min(x2,y2) - max(x1,y1))/float(y2 - y1)
One (less efficient) way to do this is by using sets.
If you set up ranges
A = range(1,101)
B = range(25, 101)
then you can find your fractions as follows:
len(set(A)&set(B))/float(len(set(B)))
and
len(set(A)&set(B))/float(len(set(A)))
giving 1.0 and 0.76.
There are 76 points in B that are also in A (since your ranges appear to be inclusive).
There are more efficient ways to do this using some mathematics as the other answers show, but this is general purpose.
I believe there are countless ways of solving this problem. The first one that came into my mind is making best use of the sum function which can also sum up over an iterable:
a = range(1,100)
b = range(25,100)
sum_a = sum(1 for i in b if i in a)
sum_b = sum(1 for i in a if i in b)
share_a = sum_a*100 / len(b)
share_b = sum_b*100 / len(a)
print(share_a, share_b)
>>> 100 75
This might be a bit more robus, e.g. when you are not working with ranges but with unsorted lists.
Here's my solution using numpy & python3
import numpy as np
def my_example(A,B):
# Convert to numpy arrays
A = np.array(A)
B = np.array(B)
# determine which elements are overlapping
overlapping_elements=np.intersect1d(A, B)
# determine how many there are
coe=overlapping_elements.size
#return the ratios
return coe/A.size , coe/B.size
# Generate two test lists
a=[*range(1,101)]
b=[*range(25,101)]
# Call the example & print the results
x,y = my_example(a,b) # returns ratios, multiply by 100 for percentage
print(x,y)
I have assumed both lower and upper bounds are included in the range. Here is my way of calculating overlapping distance with respect to other:
def is_valid(x):
try:
valid = (len(x) == 2) and (x[0] <= x[1])
except:
valid = False
finally:
return valid
def is_overlapping(x,y):
return max(x[0],y[0]) <= min(x[1],y[1])
def overlapping_percent(x,y):
if(is_valid(x) and is_valid(y)) == False:
raise ValueError("Invalid range")
if is_overlapping(x,y):
overlapping_distance = min(x[1],y[1]) - max(x[0],y[0]) + 1
width_x = x[1] - x[0] + 1
width_y = y[1] - y[0] + 1
overlap_x = overlapping_distance * 100.0/width_y
overlap_y = overlapping_distance *100.0/width_x
return (overlap_x, overlap_y)
return (0,0);
if __name__ == '__main__':
try:
print(overlapping_percent((1,100),(26,100)))
print(overlapping_percent((26,100),(1,100)))
print(overlapping_percent((26,50),(1,100)))
print(overlapping_percent((1,100),(26,50)))
print(overlapping_percent((1,100),(200,300)))
print(overlapping_percent((26,150),(1,100)))
print(overlapping_percent((126,50),(1,100)))
except Exception as e:
print(e)
Output:
(100.0, 75.0)
(75.0, 100.0)
(25.0, 100.0)
(100.0, 25.0)
(0, 0)
(60.0, 75.0)
Invalid range
I hope it helps.

Categories