I have a function createPattern, that, given an array, it returns a list of size 8 containing 7 symbols, say (1,2,3,4,5,6,7). Each symbol can either not appear at all in the list, or appear one or more times.
What i want to do is to create random arrays and, whenever a new pattern is found, append it to circ_pattern_Collection. The difficulty im having is with the following:
I want the code to recognize the pattern independent of the starting "symbol", i.e. recognize only the new circular patterns, for example:
(1,2,3,4,5,6,7,7) = (7,1,2,3,4,5,6,7) = (3,4,5,6,7,7,1,2)… and so on.
(1,1,1,2,3,3,3,3) = (1,1,2,3,3,3,3,1) = (3,3,3,3,1,1,1,2).. and so on.
Something like this :
circ_pattern_Collection=[]
for j in range(10000):
array = np.random.randint(-1000, 1000, (3, 3))
patternList = createPattern(array)
…
"if new circular pattern found, append to circ_pattern_Collection"
…
return circ_pattern_Collection
I could ofc do it by lots of if statements but there must be a more elegant/efficient way of doing this? Any tips?
you can use np.roll to roll the array on all possible patterns,
try this:
import numpy as np
def is_same_circ(a1, a2):
if len(a1) != len(a2):
return False
return any(np.array_equal(a1,np.roll(a2, offset)) for offset in range(len(a1)))
a1 = np.array((1, 2, 3, 4, 5, 6, 7, 7))
print(is_same_circ(a1, np.array((7, 1, 2, 3, 4, 5, 6, 7))))
print(is_same_circ(a1, np.array((7, 7, 7, 3, 4, 5, 6, 7))))
Output:
True
False
Related
I currently have some code where I've created a mask which checks to see if a variable matches the first position in a sequence, called index_pos_overload. If it matches, the variable is chosen, and the check ends. However, I want to be able to use this mask to not only check if the number satisfies the condition of the mask, but if it doesn't move along to the next value in the sequence which does. It's essentially to pick out a row in my pandas data column, hyst. My code currently looks like this:
import pandas as pd
from itertools import chain
hyst = pd.DataFrame({"test":[12, 4, 5, 4, 1, 3, 2, 5, 10, 9, 7, 5, 3, 6, 3, 2 ,1, 5, 2]})
possible_overload_cycle = 1
index_pos_overload = chain.from_iterable((hyst.index[i])
for i in range(0, len(hyst)-1, 5))
if (possible_overload_cycle == index_pos_overload):
hyst_overload_cycle = possible_overload_cycle
else:
hyst_overload_cycle = 5 #next value in iterable where index_pos_overload is true
The expected output of hyst_overload_cycle should be this:
print(hyst_overload_cycle)
5
I've included my logic as to how I think this should work - possible_overload_cycle = 1 does not point to the first position in the dataframe, so hyst_overload_cycle should return as 5, the first position in the mask. I hope I've made sense, as I can't quite seem to work out how I would go about this programatically.
If I understood you correctly, it may be simpler than you think:
index_pos_overload can be an array / list, there is no need to use complex constructs to store a sequence of values
to find the first non-zero value from index_pos_overload, one can simply use np.nonzero()[0][0] (the first [0] is to select the dimension, the second is to select the index within that axis) and use array indexing of that on the original index_pos_overload array
The code would look like:
import numpy as np
import pandas as pd
hyst = pd.DataFrame({"test":[12, 4, 5, 4, 1, 3, 2, 5, 10, 9, 7, 5, 3, 6, 3, 2 ,1, 5, 2]})
possible_overload_cycle = 1
index_pos_overload = np.array([hyst.index[i] for i in range(0, len(hyst)-1, 5)])
if possible_overload_cycle in index_pos_overload:
hyst_overload_cycle = possible_overload_cycle
else:
hyst_overload_cycle = index_pos_overload[np.nonzero(index_pos_overload)[0][0]]
print(hyst_overload_cycle)
# 5
Numpy has а repeat function, that repeats each element of the array a given (per element) number of times.
I want to implement a function that does similar thing but repeats not individual elements, but variably sized blocks of consecutive elements. Essentially I want the following function:
import numpy as np
def repeat_blocks(a, sizes, repeats):
b = []
start = 0
for i, size in enumerate(sizes):
end = start + size
b.extend([a[start:end]] * repeats[i])
start = end
return np.concatenate(b)
For example, given
a = np.arange(20)
sizes = np.array([3, 5, 2, 6, 4])
repeats = np.array([2, 3, 2, 1, 3])
then
repeat_blocks(a, sizes, repeats)
returns
array([ 0, 1, 2,
0, 1, 2,
3, 4, 5, 6, 7,
3, 4, 5, 6, 7,
3, 4, 5, 6, 7,
8, 9,
8, 9,
10, 11, 12, 13, 14, 15,
16, 17, 18, 19,
16, 17, 18, 19,
16, 17, 18, 19 ])
I want to push these loops into numpy in the name of performance. Is this possible? If so, how?
Here's one vectorized approach using cumsum -
# Get repeats for each group using group lengths/sizes
r1 = np.repeat(np.arange(len(sizes)), repeats)
# Get total size of output array, as needed to initialize output indexing array
N = (sizes*repeats).sum() # or np.dot(sizes, repeats)
# Initialize indexing array with ones as we need to setup incremental indexing
# within each group when cumulatively summed at the final stage.
# Two steps here:
# 1. Within each group, we have multiple sequences, so setup the offsetting
# at each sequence lengths by the seq. lengths preceeeding those.
id_ar = np.ones(N, dtype=int)
id_ar[0] = 0
insert_index = sizes[r1[:-1]].cumsum()
insert_val = (1-sizes)[r1[:-1]]
# 2. For each group, make sure the indexing starts from the next group's
# first element. So, simply assign 1s there.
insert_val[r1[1:] != r1[:-1]] = 1
# Assign index-offseting values
id_ar[insert_index] = insert_val
# Finally index into input array for the group repeated o/p
out = a[id_ar.cumsum()]
This function is a great candidate to speed up using Numba:
#numba.njit
def repeat_blocks_jit(a, sizes, repeats):
out = np.empty((sizes * repeats).sum(), a.dtype)
start = 0
oi = 0
for i, size in enumerate(sizes):
end = start + size
for rep in range(repeats[i]):
oe = oi + size
out[oi:oe] = a[start:end]
oi = oe
start = end
return out
This is significantly faster than Divakar's pure NumPy solution, and a lot closer to your original code. I made no effort at all to optimize it. Note that np.dot() and np.repeat() can't be used here, but that doesn't matter when all the code gets compiled.
Plus, since it is njit meaning "nopython" mode, you can even use #numba.njit(nogil=True) and get multicore speedup if you have many of these calls to make.
I want to write a search function that takes in a value x and a sorted sequence and returns the position that the value should go to by iterating through the elements of the sequence starting from the first element. The position that x should go to in the list should be the first position such that it will be less than or equal to the next element in the list.
Example:>>> search(-5, (1, 5, 10))——0
>>> search(3, (1, 5, 10))——1
Building a list of every item would be a bit of a waste of resources if there were big gaps in the list, instead you can just iterate through each list item until the input is bigger than the value.
In terms of your code -
def search(input,inputList):
for i in range( len( inputList ) ):
if inputList[i]>input:
return i
return len( inputList )
print search(-5, (1, 5, 10))
#Result: 0
print search(3, (1, 5, 10))
#Result: 1
To insert it into the list, this would work, I split the list in 2 based on the index and add the value in the middle.
def insert(input,inputList):
index = search(input,inputList) #Get where the value should be inserted
newInput = [input]+list(inputList[index:]) #Add the end of the list to the input
if index:
newInput = list(inputList[:index])+newInput #Add the start of the list if the index isn't 0
return newInput
print insert(-5, (1, 5, 10))
#Result: (-5, 1, 5, 10)
print insert(3, (1, 5, 10))
#Result: (1, 3, 5, 10)
since someone has answered a similar question, I will just draw a rough skeleton of what u may want to do.
declare a list and populate it with your stuff;
mylist = [1, 2, 3, 5, 5, 6, 7]
then just make a function and iterate the list;
def my_func( x, mylist):
for i in mylist:
if((mylist[i] == x)|| (mylist[i] > x)):
return i
Given 3 in list (1, 2, 3, 4, 5), the function should return index 2.
Given 3 in list (1, 2, 4, 5, 6), it should still return 2
You may want to check my python code, because I have not checked this for errors, I am assuming you know some python and if you have the skeleton, you should crack it. And Oh, python cares about the tabbibg I did.
In Python, I have several lists that look like variations of:
[X,1,2,3,4,5,6,7,8,9,X,11,12,13,14,15,16,17,18,19,20]
[X,1,2,3,4,5,6,7,8,9,10,X,12,13,14,15,16,17,18,19,20]
[0,X,2,3,4,5,6,7,8,9,10,11,X,13,14,15,16,17,18,19,20]
The X can fall anywhere. There are criteria where I put an X, but it's not important for this example. The numbers are always contiguous around/through the X.
I need to renumber these lists to meet a certain criteria - once there is an X, the numbers need to reset to zero. Each X == a reset. Each X needs to become a zero, and counting resumes from there to the next X. Results I'd want:
[0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,10]
[0,1,2,3,4,5,6,7,8,9,10,0,1,2,3,4,5,6,7,8,9]
Seems like a list comprehension of some type or a generator could help me here, but I can't get it right.
I'm new and learning - your patience and kindness are appreciated. :-)
EDIT: I'm getting pummeled with downvotes, like I've reposted on reddit or something. I want to be a good citizen - what is getting me down arrows? I didn't show code? Unclear question? Help me be better. Thanks!
Assuming the existing values don't matter this would work
def fixList(inputList, splitChar='X'):
outputList = inputList[:]
x = None
for i in xrange(len(outputList)):
if outputList[i] == splitChar:
outputList[i] = x = 0
elif x is None:
continue
else:
outputList[i] = x
x += 1
return outputList
eg
>>> a = ['X',1,2,3,4,5,6,7,8,9,'X',11,12,13,14,15,16,17,18,19,20]
>>> fixList(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> b = ['y',1,2,3,4,5,6,7,8,9,10,'y',12,13,14,15,16,17,18,19,20]
>>> fixList(b, splitChar='y')
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
EDIT: fixed to account for the instances where list does not start with either X or 0,1,2,...
Using the string 'X' as X and the_list as list:
[0 if i == 'X' else i for i in the_list]
This will return the filtered list.
I am tryng to make a dict that could hold some array sniplets
like [127:130, 122:124] but dict = {1:[127:130, 122:124], 2:[127:129, 122:123]} doesn't work.
Is there a way to do this? It doesn't need to be dicts, but I want a bunch of these areas to be callable.
So I have 256x256 arrays and I want to select small areas in them for some calculations:
fft[127:130, 122:124]
Would be great if the whole part between brackets could be in a dict
You could use the slice function. It returns a slice object that can be stored in a dictionary. eg:
slice_1 = slice(127, 130)
slice_2 = slice(122, 124)
slice_a = slice(127, 129)
slice_b = slice(122, 123)
d = {1:[slice_1, slice_2],
2:[slice_a, slice_b]
}
x = fft[d[1]] # Same as fft[127:130, 122:124]
y = fft[d[2]] # Same as fft[127:129, 122:123]
Slicing numpy arrays returns a view, and not a copy, maybe this is what you are looking for?
import numpy
a = numpy.arange(10)
b = a[3:6] # array([3, 4, 5])
a[4] = 0
#b is now array([ 3, 0, 5])
b[1] = 1
#a is now array([0, 1, 2, 3, 1, 5, 6, 7, 8, 9])