How to define index based on sequence with starting and ending values - python

I've got a set of indices that defines the starts:
Int64Index([0, 3, 5, 6, 7, 8, 10, 15, 20, 22], dtype='int64')
and ends:
Int64Index([2, 5, 7, 8, 9, 10, 12, 17, 22, 24], dtype='int64')
of the ranges that should be used as desirable index. In other words, I'd like to obtain an index that would include all integers from 0 to 2 (inclusive), then from 3 to 5 (inclusive), ..., from 10 to 12 (inclusive), from 15 to 17 (inclusive) and so on. The resulting index would be:
Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, **15**, 16, 17, **20**, 21, 22, 23, 24], dtype='int64')
(please note the break before 15 and 20). So the pairs of subsequent values would define the ranges and then those ranges would be joined together.
How can I obtain that?
My attempt is:
np.unique(np.concatenate([np.arange(start, end + 1) for start, end in zip(indices_starts, indices_ends)]))
But it feels like there must be more straighforward and potentially faster solution.

start = [0, 3, 5, 6, 7, 8, 10, 15, 20, 22]
end = [2, 5, 7, 8, 9, 10, 12, 17, 22, 24]
# Create an empty list for your indexes
new_idx = []
# Add the new indexes
for s, e in zip(start, end):
new_idx.extend(list(range(s,e+1)))
# Drop duplicated values
list(set(new_idx))
Hope it helps!

Your result index list is not accurate according to your description. With the condition of the index ranges being INCLUSIVE, the resulting index list would be:
starts = [0, 3, 5, 6, 7, 8, 10, 15, 20, 22]
ends = [2, 5, 7, 8, 9, 10, 12, 17, 22, 24]
indexes = []
for i in range(len(starts)):
indexes.extend(list(range(starts[i], ends[i] + 1)))
print(indexes)
# [0, 1, 2, 3, 4, 5, 5, 6, 7, 6, 7, 8, 7, 8, ... 20, 21, 22, 22, 23, 24]
With the condition of the index ranges being EXCLUSIVE:
...
for i in range(len(starts)):
indexes.extend(list(range(starts[i], ends[i])))
print(indexes)
# [0, 1, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 15, 16, 20, 21, 22, 23]

Related

Python - How to add n zeros randomly in an existing matrix?

i have this array that i generated using the default_rng:
import numpy as np
from numpy.random import default_rng
rng = default_rng(seed=10)
rng = rng.integers(1,20,(5,10))
rng
>>>array([[15, 19, 6, 4, 16, 16, 10, 3, 16, 10],
[ 3, 3, 8, 14, 8, 16, 1, 9, 10, 19],
[ 5, 16, 2, 7, 15, 11, 18, 15, 18, 16],
[ 3, 18, 17, 3, 19, 15, 6, 3, 8, 18],
[15, 5, 10, 17, 13, 6, 3, 19, 5, 10]], dtype=int64)
I want to add 10 zeros in this matrix using the generator with seed=5.
I thought to create a new array with dimessions [5,10] and to put 10 zeros inside and the rest to be one and then mutliply the two arrays but i have to use the generator so i can't do this.
Try with np.random.choice to choose the index, then set the values at those indexes to 0:
np.random.seed(10)
idx = np.random.choice(np.arange(5*10), size=5, replace=False)
rng.ravel()[idx] = 0
Output:
array([[15, 19, 6, 4, 16, 16, 10, 3, 16, 10],
[ 3, 3, 8, 14, 8, 16, 1, 9, 10, 19],
[ 5, 16, 2, 0, 15, 11, 18, 15, 18, 16],
[ 3, 18, 17, 3, 19, 15, 6, 0, 8, 18],
[15, 5, 0, 17, 0, 6, 3, 0, 5, 10]])
Of course
idx = np.random.choice(rng.ravel(), 10, replace= False)
print(idx)
rng.ravel()[idx] = 0
rng
Output
[10 17 3 6 15 15 15 16 15 15]
array([[15, 19, 6, 0, 16, 16, 0, 3, 16, 10],
[ 0, 3, 8, 14, 8, 0, 0, 0, 10, 19],
[ 5, 16, 2, 7, 15, 11, 18, 15, 18, 16],
[ 3, 18, 17, 3, 19, 15, 6, 3, 8, 18],
[15, 5, 10, 17, 13, 6, 3, 19, 5, 10]], dtype=int64)
So instead of take 10 zeros i take only 6 becaus of 15 appears five times in my idx.

List comprehension function for odd-even numbers

I am trying to print a list containing 2 lists at index 0 and 1. One list contains even numbers and the other one odd numbers.
Also, I want to do it with list comprehension and use only one list variable.
even_odd = [[],[]]
even_odd = [even_odd[0].append(a) if a%2 == 0 else even_odd[1].append(a) for a in range(20)]
Expected Output:
[[0, 2, 4, 6, 8, 10, 12, 14, 16, 18], [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]]
Using list comprehension
You can do it with two range by iterating in 2 interval
even_odd = [list(range(0, 19, 2)), list(range(1, 20, 2))]
# [[0, 2, 4, 6, 8, 10, 12, 14, 16, 18], [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]]

How to remove numbers in a NumPy array?

I want to know how I can remove the numbers resulted by the code from the original list, based on How to find larger numbers of any selected number in a series in an ascending order in NumPy?
EXAMPLE:
Series of random numbers:
4, 8, 5, 9, 3, 11, 17, 19, 9, 15, 16
X=4, Then:
4, 8, 9, 11, 17, 19 (We call this ROUND 1)
The numbers resulted in ROUND 1 are removed and the operation goes for the new list as follows:
5, 3, 9, 15, 16
So if we apply the code to the new list, it will generate new results:
X=5, Then:
5, 9, 15, 16
Edit:
a = np.array([4, 8, 5, 9, 3, 11, 17, 19, 9, 15, 16])
X = 4
withreps = np.maximum.accumulate(a[np.argmax(a==X):])
result = withreps[np.where(np.diff(withreps, prepend=withreps[0]-1))]
result
# array([ 4, 8, 9, 11, 17, 19])
Check out the following code
import numpy as np
rand_nums = np.array([4, 8, 5, 9, 3, 11, 17, 19, 9, 15, 16])
round_one = np.array([4, 8, 9, 11, 17, 19])
res = np.setdiff1d(rand_nums, round_one)
print(res)
# output
>>> array([ 3, 5, 15, 16])

Creating an overlap array with conditions - Python

Data = [day(1) day(2)...day(N)...day(2N)..day(K-N)...day(K)]
I am looking to create a numpy array with two arrays, N and K with shapes (120,) and (300,). The array needs to be of the form:
x1 = [day(1) day(2) day (3)...day(N)]
x2 = [day(2) day(3)...day(N) day(N+1)]
xN = [day(N) day(N+1) day(N+2)...day(2N)]
xK-N = [day(K-N) day(K-N+1)...day(K)]
X is basically of shape (K-N)xN, with the above x1,x2,...xK-N as rows. I have tried using iloc for getting two arrays N and K with the same shapes. Good till then. But, when I try to merge the arrays using X = np.array([np.concatenate((N[i:], K[:i] )) for i in range(len(N)]), I am getting an NxN array in the form of an overlap array only, and not in the desired format.
Is this what you are trying to produce (with simpler data)?
In [253]: N,K=10,15
In [254]: data = np.arange(K)+10
In [255]: data
Out[255]: array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])
In [256]: np.array([data[np.arange(N)+i] for i in range(K-N+1)])
Out[256]:
array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21],
[13, 14, 15, 16, 17, 18, 19, 20, 21, 22],
[14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
[15, 16, 17, 18, 19, 20, 21, 22, 23, 24]])
There's another way of generating this, using advanced ideas about strides:
np.lib.stride_tricks.as_strided(data, shape=(K-N+1,N), strides=(4,4))
In the first case, all values in the new array are copies of the original. The strided case is actually a view. So any changes to data appear in the 2d array. And without data copying, the 2nd is also faster. I can try to explain it if you are interested.
Warren suggests using hankel. That's a short function, which in our case does essentially:
a, b = np.ogrid[0:K-N+1, 0:N]
data[a+b]
a+b is an array like:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
[ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]])
In this example case it is just a bit better than the list comprehension solution, but I expect it will be a lot better for much larger cases.
It is probably not worth adding a dependence on scipy for the following, but if you are already using scipy in your code, you could use the function scipy.linalg.hankel:
In [75]: from scipy.linalg import hankel
In [76]: K = 16
In [77]: x = np.arange(K)
In [78]: x
Out[78]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
In [79]: N = 8
In [80]: hankel(x[:K-N+1], x[K-N:])
Out[80]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 1, 2, 3, 4, 5, 6, 7, 8],
[ 2, 3, 4, 5, 6, 7, 8, 9],
[ 3, 4, 5, 6, 7, 8, 9, 10],
[ 4, 5, 6, 7, 8, 9, 10, 11],
[ 5, 6, 7, 8, 9, 10, 11, 12],
[ 6, 7, 8, 9, 10, 11, 12, 13],
[ 7, 8, 9, 10, 11, 12, 13, 14],
[ 8, 9, 10, 11, 12, 13, 14, 15]])

Generate all tuple possible based on three lists

Interesting answers, allow me to modify the question.
After some change on the code I got this:
#coding:utf-8
import itertools
stuff = [1, 2, 3, 4, 5, 8, 10, 13, 16, 17, 18, 20, 21, 22, 25]
for L in range(5, 6):
for subset in itertools.combinations(stuff, L):
subset = list(subset)
subset.extend([7, 9, 11, 15, 19, 23, 6, 12, 14, 24])
print(subset)
the output of it is like this:
[1, 2, 3, 4, 5, 7, 9, 11, 15, 19, 23, 6, 12, 14, 24]
[1, 2, 3, 4, 8, 7, 9, 11, 15, 19, 23, 6, 12, 14, 24]
...
It generates approximately 3000 lines.
It did all possible combination with five numbers of the list stuff and add to every single combination (subset) the another list (subset.extend([7, 9, 11, 15, 19, 23, 6, 12, 14, 24])). It seems to be right, I'm not sure.
But what I really want it to do is:
1 - Input three lists (pair and unpair)
stuff = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
pair = [2 , 6, 12, 20, 16, 10, 22]
unpair = [1, 5, 11, 19, 23, 25, 13, 17]
2 - Than the program will generate all combinations of 4 numbers from the 7 numbers of pair and will do the same with unpair, generating all combinations of 4 numbers from the 8 numbers of unpair, and will bind it together generating a list with 8 number of al possible combinations of 4 numbers from pair combined with 4 number from unpair like:
[2, 12, 20, 10, 1, 5, 19, 23]
[2, 12, 20, 10, 5, 19, 25, 13]
...
3 - Than for each line from the combination of pair and unpair generated it will complete with a 7 numbers combination from the list stuff generating a list with 15 numbers without repeating a number like
[2, 12, 20, 10, 1, 5, 19, 23, 25, 3, 4, 8, 17, 21, 22]
[2, 12, 20, 10, 5, 19, 25, 13, 3, 4, 8, 17, 21, 22, 11]
...
Here is where I got stuck. How to generate a combination for each list and bind them generating a 15 numbers list without repeating a number and a sequence.
you can just manually code that logic in your for loop:
for combo in itertools.combinations(stuff, 15):
if set(combo).issuperset(pair) and set(combo).issuperset(unpair):
print(combo)
Note: This particular code only works when "stuff" has no duplicates

Categories