Generating overlapping sequences - python

I have a dataset with the following information. The timebin variable is an identifier for the time period of the data. It can be assumed that timebin is unique and without any gaps (i.e. the data will always contain 2 if it contains 1 and 3).
timebin,lat,lon
0,9.0,2.0
1,12.0,4.0
2,15.0,6.0
3,18.0,8.0
4,21.0,10.0
5,24.0,12.0
6,27.0,14.0
7,30.0,16.0
I want to generate all the sequences of a fixed-length l with an amount of overlap o. For instance, for l=4 and o=2 the following groups of indices would be output:
[[0,1,2,3], [2,3,4,5], [4,5,6,7]]
This could be done using a loop, but I wonder if there is a more elegant and efficient way of doing it in python?

Use list comprehension:
l = 4
o = 2
e = 7
print([[x for x in range(s, s + l)] for s in range(0, e, o) if s + l <= e + 1])
Result:
[[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7]]

overlap = 2
data = [0, 1, 2 ,3 ,4, 5 ,6 ,7]
groups = [data[i: i + overlap * 2] for i in range(len(data) - overlap * 2 + 1)]

Is the rest of the provided data involved in any way?
Just from your question you could generate those sequences with list comprehensions:
>>> l = 4
>>> o = 2
>>> [[x for x in range(s, s+l)] for s in range(20)[::(l-o)]]
[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7], [6, 7, 8, 9], [8, 9, 10, 11],
[10, 11, 12, 13], [12, 13, 14, 15], [14, 15, 16, 17], [16, 17, 18, 19],
[18, 19, 20, 21]]

Related

Loop through list elements to get cumulative sums

I'm very new to python. I'm trying to create a loop so that I can get cumulative sums of the elements in a list. For example, given a list [3, 2, 1] I'm hoping to get [3 (first number), 5 (3+2), 6 (3+2+1)], [2 (second number), 3 (2+1)] and [1].
What I have currently is:
data = [5, 4, 3, 2, 1]
for i in data:
perf = [sum(data[:i+1]) for i in range(len(data))]
print(perf)
And I'm getting the following as output, which is the sum from the first element. How do I modify to get the cumulative sums starting with 4, 3, ... ?
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
My desired output
[5, 9, 12, 14, 15]
[4, 7, 9, 10]
[3, 5, 6]
[2, 3]
[1]
Thank you!
If I understand you correctly, in the 1. iteration you want to get sums from first element, in the 2. iteration sums from second element and so on:
data = [5, 4, 3, 2, 1]
for i in range(len(data)):
s = 0
l = [s := s + d for d in data[i:]]
print(l)
Prints:
[5, 9, 12, 14, 15]
[4, 7, 9, 10]
[3, 5, 6]
[2, 3]
[1]
Or: using itertools.accumulate
from itertools import accumulate
data = [5, 4, 3, 2, 1]
for i in range(len(data)):
print(list(accumulate(data[i:])))
You're not far from the answer. You just need to begin your range from the next num in the list. Try this:
data = [5, 4, 3, 2, 1]
for ind, num in enumerate(data):
perf = [sum(data[ind:i+1]) for i in range(ind, len(data))]
print(perf)
Output:
[5, 9, 12, 14, 15]
[4, 7, 9, 10]
[3, 5, 6]
[2, 3]
[1]
Your statement to compute a commulative sum within the loop is correct.
You had just used i incorrectly in the outer loop statement.
All you need to do is slice your original data and generate sums for each slice.
test_data = [5, 4, 3, 2, 1]
def commulative_sum(a_list: list[int]):
# The same thing you wrote
return [sum(a_list[:i+1]) for i in range(len(a_list))]
def commulative_sums(data: list[int]):
# Slice the input data and generate commulative sums
return [commulative_sum(data[j:]) for j in range(len(data))]
result = commulative_sums(test_data)
print(result)
[[5, 9, 12, 14, 15], [4, 7, 9, 10], [3, 5, 6], [2, 3], [1]]
Here are 2 ways you can solve this problem.
data = [5, 4, 3, 2, 1]
k = 0;
for i in data:
k = k + i
print(k)
And this is the second method
data = [5, 4, 3, 2, 1]
k = 0;
for i in range(len(data)):
k = k + data[i]
print(k)

Slice a submatrix with center element indices

Given a matrix A, and a list of row indices, and a list of column indices, how to efficiently extract the squared submatrices with size k centered by the row and column indices?
For example:
A = array([[12, 6, 14, 8, 4, 1],
[18, 13, 8, 10, 9, 19],
[ 8, 15, 6, 5, 6, 18],
[ 3, 0, 2, 14, 13, 12],
[ 4, 4, 5, 19, 0, 14],
[16, 8, 7, 7, 11, 0],
[ 3, 11, 2, 19, 11, 5],
[ 4, 2, 1, 9, 12, 12]])
r = np.array([2, 5])
c = np.array([3, 2])
k = 3
The output should be A[1:4, 2:5] and A[4:7, 1:4]. So basically, the outputs are squared submatrices in size kxk and centered on the [r,c] elements (A[2,3] and A[5,2] in this case)
How to do this efficiently and elegantly? Thanks
For the case when the submatrices be of the same shape, we can get sliding windows and then index those with the start indices along the rows and cols for our desired output. To get those windows, we can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows. More info on use of as_strided based view_as_windows -
from skimage.util.shape import view_as_windows
# Get all sliding windows
w = view_as_windows(A,(k,k))
# Select relevant ones for final o/p
out = w[r-k//2,c-k//2]
You mean something like this?
for x,y in zip(r,c):
s = k // 2
print("position:",[x - s,x + s + 1], [y - s,y + s + 1])
print(A[x - s:x + s + 1,y - s:y + s + 1])
print()
Output:
position: [1, 4] [2, 5]
[[ 8 10 9]
[ 6 5 6]
[ 2 14 13]]
position: [4, 7] [1, 4]
[[ 4 5 19]
[ 8 7 7]
[11 2 19]]
Note that k should be odd here

How to generate a 2D list which will contain numbers from 1..n without using numpy?

The 2D list should be like this:
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
I am unable to find the logic for this. I have done this using numpy's reshape function. But unable to do without numpy.
Here is one simple way:
res = [list(range(i, i+4)) for i in range(1, 14, 4)]
print(res)
[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]
You can also wrap in a generic function:
def square(n):
return [list(range(i, i+n)) for i in range(1, n**2, n)]
res = square(4)
Explanation
The syntax for range construction is range(start, end, [step]). step is optional; if it is not specified, it is assumed to be 1.
The first part range(i, i+n) creates a range object from i to i+n-1, inclusive.
The second part range(1, n**2, n) iterates in steps of n to n*n, not including the final term. Since end is non-inclusive, squaring n provides the desired cap.
This is one approach
l = range(1, 17) #Create a list using range
print([l[i:i+4] for i in range(0, len(l), 4)]) #Divide the list into 4 equal chunks
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
I like this one too:
>> [[i+4*j for i in range(1,5)] for j in range(4)]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
Use a list-comprehension like this with tuple unpacking:
>>> [[*range(i, i+4)] for i in range(1, 14, 4)]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
or you could use the grouper from the itertools recipes to split a given list (or iterable) into an 2d matrix. this is something along those lines:
def to2d(items, width):
return list(list(i) for i in zip(*(iter(items_1d),) * width))
items_1d = list(range(1, 17)) # or just items_1d = range(1, 17)
print(to2d(items=items_1d, width=4))

Python: Sum part of a list

Given a list, how can I find sums of part of the list? For example:
a = [2,5,4,6,8]
sum(a) = 25
I want to find out if a part of the list sums up to a certain number.
The list part should have a certain length. This is my goal:
ex_list = [2,5,4,6,8]
dif_list = partsum(ex_list, 3)
print(dif_list) ==> [11, 13, 15, 12, 14, 16, 15, 17, 19, 18]
Each element in 'dif_list' is given by taking 3 numbers out of 'ex_list' and summing them up, i.e. 2+5+4 = 11, 2+5+6 = 13, 2+5+8 = 15, 2+4+6 = 12, etc.
Also for reference:
ex_list = [2,5,4,6,8]
another_list = partsum(ex_list, 4)
print(another_list) ==> [17, 19, 21, 20, 23]
Because 2+5+4+6 = 17, 2+5+4+8 = 19, etc.
Basically, partsum(thing, num) will take 'num' items of 'thing', sum them up, and append it to a new list. All help is appreciated, thanks!
You want itertools.combinations.
import itertools
lst = [2,5,4,6,8]
combos = itertools.combinations(lst, 3)
# combos is equivalent to
# [ [2, 5, 4], [2, 5, 6], [2, 5, 8],
# [2, 4, 6], [2, 4, 8], [2, 6, 8],
# [5, 4, 6], [5, 4, 8], [5, 6, 8],
# [4, 6, 8] ]
result = [sum(combo) for combo in combos]

python oneline to create matrix of given order

I am looking for python oneliner that will create matrix with the given order and fill values from 1 to n. n = r X c
I achieved till this,
Matrix1 = [[x+1 for x in range(rowCount)] for x in range(columnCount)]
print Matrix1
But the output is
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> matrix1 = [[1+x+y*rowCount for x in range(rowCount)] for y in range(columnCount)]
>>> matrix1
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
No, the correct way is without loop (and in one line):
import numpy as np
rowCount = 2
colCount = 5
np.array(range(1, 1+rowCount*colCount)).reshape(rowCount,colCount)
#array([[ 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10]])
You use the same variable for your two loops. Try this :
matrix1 = [[y*rowCount + x + 1 for x in range(rowCount)] for y in range(columnCount)]
print matrix1
Given c (column count), n, here's what I came up with:
[range(0, n)[cx:cx+c] for cx in range(0, n, c)]
Result:
In [16]: n = 9
In [17]: c = 3
In [18]: [range(0, n)[cx:cx+c] for cx in range(0, n, c)]
Out[18]: [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
EDIT: More examples for non square matrices:
(mod is a function i created to quickly change r and c values, and calculate n from them)
In [23]: mod(8, 2) # 8 rows, 2 columns
In [24]: [range(0, n)[cx:cx+c] for cx in range(0, n, c)]
Out[24]: [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13], [14, 15]]
In [25]: mod(3, 6) # 3 rows, 6 columns
In [26]: [range(0, n)[cx:cx+c] for cx in range(0, n, c)]
Out[26]: [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17]]
In [27]: mod(10, 3) # 10 rows, 3 columns
In [28]: [range(0, n)[cx:cx+c] for cx in range(0, n, c)]
Out[28]:
[[0, 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, 26],
[27, 28, 29]]
It works for them too.

Categories

Resources