Reputation: 1616
I have a python dict
{'kValues': [2, 3, 4, 5, 6, 7, 8, 9, 10],
'WSS': [21455, 5432, 4897, 4675, 4257, 3954, 3852, 3756, 3487],
'SS': [0.75, 0.85, 0.7, 0.52, 0.33, 0.38, 0.42, 0.46, 0.47]}
When I plot kValues against WSS and SS, I get following line
The optimum value of 1st plot is at k value = 3 and on 2nd plot is at k value = 3
How to extract that k value from the dictionary without visualizing the plots
Criteria - First plot always have a elbow, elbow point to be extracted, second plot always have a raise followed by a dip, that raise value to be extracted
Upvotes: 1
Views: 314
Reputation: 1616
Found this wonderful python library for finding the optimum value
https://pypi.org/project/kneed/
from kneed import KneeLocator
kneedle = KneeLocator(kValues, WSS, S=1.0, curve="convex", direction="decreasing")
print(kneedle.knee) # 3
print(kneedle.elbow) # 3
curve and direction can be configured based on pattern
Upvotes: 1
Reputation: 1160
You can use the derivative to find the peak in the SS:
import numpy as np
k_ss = kValues[np.where(np.sign(np.diff(SS, append=SS[-1])) == -1)[0][0]]
diff
calculates the difference between the elements (the derivative) and then we find the first place where the derivative changes sign
(goes over the peak).
For WSS it's a bit more complicated because you have to define a threshold, that would define an elbow, you could take a few examples from your data and use that. Here is a code where the threshold is set to 1/10 of the max derivative:
d = np.diff(WSS, append=WSS[-1])
th = max(abs(d)) / 10
k_wss = kValues[np.where(abs(d) < th)[0][0]]
Other than that you can try to fit the data to an asymptotic curve and extract the constants
Upvotes: 0
Reputation: 424
You can use the angle between 3 points p1,p2, and p3 which will be only helpful, and a point that is near 90 degrees for the elbow and 0 for deep. I am sharing my code the normalization is the tricky.
import math
kValues= [1 , 2 , 3, 4, 5, 6, 7, 8, 9, 10]
WSS= [81000,21455, 5432, 4897, 4675, 4257, 3954, 3852, 3756, 3487]
SS=[0.75, 0.85, 0.7, 0.52, 0.33, 0.38, 0.42, 0.46, 0.47]
#get all the angles between k values as x and WSS as y
angles=[]
#each WSS slab values
normalize_wss=2000
for i in range(1,len(WSS)-1,1):
p1=(kValues[i-1]*normalize_wss,WSS[i-1])
p2=(kValues[i]*normalize_wss,WSS[i])
p3=(kValues[i+1]*normalize_wss,WSS[i+1])
#find angle between 3 points p1,p2,p3
angle1=math.degrees(math.atan2(p3[1]-p2[1],p3[0]-p2[0]))
angle2=math.degrees(math.atan2(p1[1]-p2[1],p1[0]-p2[0]))
angles.append([angle1-angle2])
print(angles)
Upvotes: 1