Checking if n elements in an array are increasing - python

I have written a code for SPC and I am attempting to highlight certain out of control runs.
So I was wondering if there was a way to pull out n(in my case 7) amount of increasing elements in an array so I can index with with the color red when I go to plot them.
This is what I attempted but I obviously get an indexing error.
import numpy as np
import matplotlib.pyplot as plt
y = np.linspace(0,10,15)
x = np.array([1,2,3,4,5,6,7,8,9,1,4,6,4,6,8])
col =[]
for i in range(len(x)):
if x[i]<x[i+1] and x[i+1]<x[i+2] and x[i+2]<x[i+3] and x[i+3]<x[i+4] and x[i+4]<x[i+5] and x[i+5]<x[i+6] and x[i+6]<x[i+7]:
col.append('red')
elif x[i]>x[i+1] and x[i+1]>x[i+2] and x[i+2]>x[i+3] and x[i+3]>x[i+4] and x[i+4]>x[i+5] and x[i+5]>x[i+6] and x[i+6]>x[i+7]:
col.append('red')
else:
col.append('blue')
for i in range(len(x)):
# plotting the corresponding x with y
# and respective color
plt.scatter(y[i], x[i], c = col[i], s = 10,
linewidth = 0)
Any help would be greatly appreciated!

As Andy said in his comment you get the index error because at i=8 you get to 15 which is the length of x.
Either you only loop over len(x)-7 and just repeat the last entry in col 7 times or you could do something like this:
import numpy as np
import matplotlib.pyplot as plt
y = np.linspace(0,10,20)
x = np.array([1,2,3,4,5,6,1,2,3,1,0,-1,-2,-3,-4,-5,-6,4,5])
col =[]
diff = np.diff(x) # get diff to see if x inc + or dec - // len(x)-1
diff_sign = np.diff(np.sign(diff)) # get difference of the signs to get either 1 (true) or 0 (false) // len(x)-2
zero_crossings = np.where(diff_sign)[0] + 2 # get indices (-2 from len(x)-2) where a zero crossing occures
diff_zero_crossings = np.diff(np.concatenate([[0],zero_crossings,[len(x)]])) # get how long the periods are till next zero crossing
for i in diff_zero_crossings:
if i >= 6:
for _ in range(i):
col.append("r")
else:
for _ in range(i):
col.append("b")
for i in range(len(x)):
# plotting the corresponding x with y
# and respective color
plt.scatter(y[i], x[i], c = col[i], s = 10,
linewidth = 0)
plt.show()

To determine if all integer elements of a list are ascending, you could do this:-
def ascending(arr):
_rv = True
for i in range(len(arr) - 1):
if arr[i + 1] <= arr[i]:
_rv = False
break
return _rv
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 16]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16]
print(ascending(a1))
print(ascending(a2))
If you want to limit the sequence of ascending values then you could just use nested loops. It may look inelegant but it's surprisingly efficient and much simpler than bringing dataframes into the mix:-
def ascending(arr, seq):
for i in range(len(arr) - seq + 1):
state = True
for j in range(i, i + seq - 1):
if arr[j] >= arr[j + 1]:
state = False
break
if state:
return True
return False
a1 = [100, 99, 98, 6, 7, 8, 10, 11, 12, 13, 14, 13]
a2 = [9, 8, 7, 6, 5, 4, 3, 2, 1]
print(ascending(a1, 7))
print(ascending(a2, 7))

Related

Add padding based on partial sum

I have four given variables:
group size
total of groups
partial sum
1-D tensor
and I want to add zeros when the sum within a group reached the partial sum. For example:
groupsize = 4
totalgroups = 3
partialsum = 15
d1tensor = torch.tensor([ 3, 12, 5, 5, 5, 4, 11])
The expected result is:
[ 3, 12, 0, 0, 5, 5, 5, 0, 4, 11, 0, 0]
I have no clue how can I achieve that in pure pytorch. In python it would be something like this:
target = [0]*(groupsize*totalgroups)
cursor = 0
current_count = 0
d1tensor = [ 3, 12, 5, 5, 5, 4, 11]
for idx, ele in enumerate(target):
subgroup_start = (idx//groupsize) *groupsize
subgroup_end = subgroup_start + groupsize
if sum(target[subgroup_start:subgroup_end]) < partialsum:
target[idx] = d1tensor[cursor]
cursor +=1
Can anyone help me with that? I have already googled it but couldn't find anything.
Some logic, Numpy and list comprehensions are sufficient here.
I will break it down step by step, you can make it slimmer and prettier afterwards:
import numpy as np
my_val = 15
block_size = 4
total_groups = 3
d1 = [3, 12, 5, 5, 5, 4, 11]
d2 = np.cumsum(d1)
d3 = d2 % my_val == 0 #find where sum of elements is 15 or multiple
split_points= [i+1 for i, x in enumerate(d3) if x] # find index where cumsum == my_val
#### Option 1
split_array = np.split(d1, split_points, axis=0)
padded_arrays = [np.pad(array, (0, block_size - len(array)), mode='constant') for array in split_array] #pad arrays
padded_d1 = np.concatenate(padded_arrays[:total_groups]) #put them together, discard extra group if present
#### Option 2
split_points = [el for el in split_points if el <len(d1)] #make sure we are not splitting on the last element of d1
split_array = np.split(d1, split_points, axis=0)
padded_arrays = [np.pad(array, (0, block_size - len(array)), mode='constant') for array in split_array] #pad arrays
padded_d1 = np.concatenate(padded_arrays)

Summing up arrays without doubles

I would like to know if I have generated the 3 arrays in the manner below, how can I sum all the numbers up from all 3 arrys without summing up the ones that appear in each array.
(I would like to only som upt 10 once but I cant add array X_1 andX_2 because they both have 10 and 20, I only want to som up those numbers once.)
Maybe this can be done by creating a new array out of the X_1, X_2 and X_3 what leave out doubles?
def get_divisible_by_n(arr, n):
return arr[arr%n == 0]
x = np.arange(1,21)
X_1=get_divisible_by_n(x, 2)
#we get array([ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20])
X_2=get_divisible_by_n(x, 5)
#we get array([ 5, 10, 15, 20])
X_3=get_divisible_by_n(x, 3)
#we get array([3, 6, 9, 12, 15, 18])
it is me again!
here is my solution using numpy, cuz i had more time this time:
import numpy as np
arr = np.arange(1,21)
divisable_by = lambda x: arr[np.where(arr % x == 0)]
n_2 = divisable_by(2)
n_3 = divisable_by(3)
n_5 = divisable_by(5)
what_u_want = np.unique( np.concatenate((n_2, n_3, n_5)) )
# [ 2, 3, 4, 5, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20]
Not really efficient and not using numpy but here is one solution:
def get_divisible_by_n(arr, n):
return [i for i in arr if i % n == 0]
x = [i for i in range(21)]
X_1 = get_divisible_by_n(x, 2)
X_2 = get_divisible_by_n(x, 5)
X_3 = get_divisible_by_n(x, 3)
X_all = X_1+X_2+X_3
y = set(X_all)
print(sum(y)) # 142

How to get postion range of a list when give any number?

I have list [1, 2, 5, 6, 9, 10, 14, 19], how can i get any number range index.
For example:
l = [1, 2, 5, 6, 9, 10, 14, 19]
value = 11
range_index = get_range_index(l)
range_index = (5, 6) # need like this
# give a value = 11, need to get value index like (5, 6), because 10 < value < 14.
# the list size may be very very long,can there have good method?
This i try to get left value and calculate index by returned left value.
It's not very good and not high performance.
def get_left_point(self, data, value):
if len(data) == 1:
return data[0]
mid_index, mid_value = len(data) // 2, data[len(data) // 2]
if value >= float(mid_value):
ret = self.get_left_point(data[mid_index:], value)
else:
ret = self.get_left_point(data[:mid_index], value)
return ret
my_range = (100, 101)
[x for x in l if (my_range[0] <= x) and (x <= my_range[1])]

i need help getting stDev without using importmath, python

### import math
def mean(values):
return sum(values)*1.0/len(values)
def std():
pass
print(std())
def std(values):
length = len(values)
if length < 2:
return("Standard deviation requires at least two data points")
m = mean(values)
total_sum = 0
for i in range(length):
total_sum += (values[i]-m)**2
under_root = total_sum*1.0/length
return math.sqrt(under_root)
vals = [5]
stan_dev = std(vals)
print(stan_dev)
values = [1, 2, 3, 4, 5]
stan_dev = std(values)
print(stan_dev)
__________________________________________________________________________
lst = [3, 19, 21, 1435, 653342]
sum = reduce((lambda x, y: x +y), lst)
print (sum)
# list = [3, 19, 21, 1435, 653342]
i need to be able to get the stDev without using sum or len
i need to 'unpack' the stDev ???
You can do it with two loops (there are shorter ways but this is simple):
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Calculate the mean first
N, X = 0, 0
for xi in arr:
N += 1
X += xi
mean = X/N
# Calculate the standard deviation
DSS = 0
for xi in arr:
DSS += (xi - mean)**2
std = (DSS/N)**(1/2)
Outputs 4.5 for mean and 2.872 for std.

Peak finder in Python in O(log n) complexity

I'm completely new to Python, thus the question. I'm trying to solve a standard interview question, which is finding a peak in an array. A peak is defined as a number which is greater than it's left and right neighbor. I'm trying to find the largest such peak.
This is my code:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peak(arr))
def find_peak(arr):
return _find_peak(arr, 0, len(arr))
def _find_peak(arr, start, stop):
mid = (start + stop) // 2
if arr[mid] > arr[mid - 1] and arr[mid] > arr[mid + 1]:
return arr[mid]
elif arr[mid] < arr[mid - 1]:
_find_peak(arr, 0, mid - 1)
elif arr[mid] < arr[mid + 1]:
_find_peak(arr, mid + 1, stop)
if __name__ == '__main__':
main()
The output of this program is None, where as the expected output is 24. Any help appreciated.
Data
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
A one-liner:
One line should be enough:
max_peak = max(x2 for x1, x2, x3 in zip(arr, arr[1:], arr[2:]) if x1 < x2 > x3)
In a loop
Maybe easier to understand when you are new to Python:
peak = float('-inf')
for x1, x2, x3 in zip(arr, arr[1:], arr[2:]):
if x1 < x2 > x3:
peak = max(peak, x2)
print(peak)
Output:
24
All peaks
You can also use a one-liner to get all peaks:
>>> [x2 for x1, x2, x3 in zip(arr, arr[1:], arr[2:]) if x1 < x2 > x3]
[13, 24]
and get the greatest one with max() on the result.
Explanation
Let's have a look at some of the components of the solution. I am working with Python 3 here, as everybody should. ;)
You can slice lists.
>>> arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
This gives you all of the list but the first element:
>>> arr[1:]
[12, 13, 8, 2, 16, 24, 11, 5, 1]
Here its starts with element three:
>>> arr[2:]
[13, 8, 2, 16, 24, 11, 5, 1]
The zip() function zips multiple sequences together. To visualize what happens, you can convert the zip object into a list:
>>> list(zip(arr, arr[1:], arr[2:]))
[(7, 12, 13),
(12, 13, 8),
(13, 8, 2),
(8, 2, 16),
(2, 16, 24),
(16, 24, 11),
(24, 11, 5),
(11, 5, 1)]
Python supports tuple unpacking. This allows to assign individual names to all members of a tuple:
>>> x1, x2, x3 = (7, 12, 13)
>>> x1
7
>>> x2
12
>>> x3
13
Another nice feature is the comparison of more than two objects:
>>> 10 < 12 > 8
True
This is equivalent to:
>>> (10 < 12) and (12 > 8)
True
Python offers list comprehensions:
>>> [x * 2 for x in range(2, 6)]
[4, 6, 8, 10]
Generator expression work in a similar way but don't produce a list but an iterator and can be consumed without using lots of memory:
>>> sum(x * 2 for x in range(2, 6))
28
you are missing a return statement for your two elif cases
I think the 13 also is a peak (greater than 12 and 8).
Try this approach:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peaks(arr))
def find_peaks(arr):
return list(_search(arr))
def _search(arr):
last = len(arr) - 1
for i, e in enumerate(arr):
if not any((i > 0 and arr[i-1] > e, i < last and arr[i+1] > e)):
yield e
if __name__ == '__main__':
main()
If you don’t understand anything, ask!
Another approach – using only one function:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peaks(arr))
def find_peaks(arr):
last = len(arr) - 1
return [
e for i, e in enumerate(arr)
if not any((i > 0 and arr[i-1] > e, i < last and arr[i+1] > e))
]
if __name__ == '__main__':
main()
I don't think you can find a peak in O(log N) time, because by definition the items cannot be in order, and there is no way to predict the peaky-ness of any item in a list given other items, except that comparing item N with item N+1 is presumably reflexive - it tells you that either N or N+1 might be a peak. That gets you to N/2 compares, which must then be followed by N/2 more compares to check the other side of the peak.
Here's a local_maxima(iterable) function that you can use with max() to find peaks. It treats start/end elements as peaks if they are greater than their one neighbor.
data = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1, None, 2, None, 3, 4, None, 5, 1, None]
firstpeak = [12, 7, 9, 8]
lastpeak = [1, 2, 3, 4]
def local_maxima(it):
"""Find local maxima in iterable _it_. Compares with None using
`is (not) None`, and using operator `<`."""
peaking = False
last = None
for item in it:
# Deal with last item peaking
if peaking and (item is None or item < last):
yield last
peaking = False
elif item is None:
peaking = False
elif last is None or last < item:
peaking = True
else:
peaking = False
last = item
if peaking:
yield last
print([x for x in local_maxima(data)])
print("Highest:", max(local_maxima(data)))
print([x for x in local_maxima(firstpeak)])
print("Highest:", max(local_maxima(firstpeak)))
print([x for x in local_maxima(lastpeak)])
print("Highest:", max(local_maxima(lastpeak)))

Categories

Resources