Vesper
Vesper

Reputation: 845

How to split a list using two nested conditions

Basically I have list of 0s and 1s. Each value in the list represents a data sample from an hour. Thus, if there are 24 0s and 1s in the list that means there are 24 hours, or a single day. I want to capture the first time the data cycles from 0s to 1s back to 0s in a span of 24 hours (or vice versa from 1s to 0s back to 1s).

signal = [1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1]

expected output:

#                                                     D   
signal = [1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0]
output = [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0]
#                           ^ cycle.1:day.1           |dayline        ^cycle.1:day.2

In the output list, when there is 1 that means 1 cycle is completed at that position of the signal list and at rest of the position there are 0. There should only 1 cycle in a days that's why only 1 is there.

I don't how to split this list according to that so can someone please help?

Upvotes: 0

Views: 96

Answers (1)

Andrew Micallef
Andrew Micallef

Reputation: 360

It seams to me like what you are trying to do is split your data first into blocks of 24, and then to find either the first rising edge, or the first falling edge depending on the first hour in that block.

Below I have tried to distill my understanding of what you are trying to accomplish into the following function. It takes in a numpy.array containing zeros and ones, as in your example. It checks to see what the first hour in the day is, and decides what type of edge to look for. it detects an edge by using np.diff. This gives us an array containing -1's, 0's, and 1's. We then look for the first index of either a -1 falling edge, or 1 rising edge. The function returns that index, or if no edges were found it returns the index of the last element, or nothing.

For more info see the docs for descriptions on numpy features used here np.diff, np.array.nonzero, np.array_split

import numpy as np

def get_cycle_index(day):
    '''
    returns the first index of a cycle defined by nipun vats
    if no cycle is found returns nothing
    '''

    first_hour = day[0]
    if first_hour == 0:
        edgetype = -1
    else:
        edgetype = 1

    edges = np.diff(np.r_[day, day[-1]])

    if (edges == edgetype).any():
        return (edges == edgetype).nonzero()[0][0]
    elif (day.sum() == day.size) or day.sum() == 0:
        return
    else:
        return day.size - 1

Below is an example of how you might use this function in your case.

import numpy as np

_data = [1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
#_data = np.random.randint(0,2,280, dtype='int')
data = np.array(_data, 'int')

#split the data into a set of 'day' blocks
blocks = np.array_split(data, np.arange(24,data.size, 24))


_output = []

for i, day in enumerate(blocks):
    print(f'day {i}')
    buffer = np.zeros(day.size, dtype='int')
    print('\tsignal:', *day, sep = ' ')
    cycle_index = get_cycle_index(day)
    if cycle_index:
        buffer[cycle_index] = 1
    print('\toutput:', *buffer, sep=' ')

    _output.append(buffer)

output = np.concatenate(_output)
print('\nfinal output:\n', *output, sep=' ')

this yeilds the following output:

day 0
    signal: 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0
    output: 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
day 1
    signal: 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    output: 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
day 2
    signal: 0 0 0 0 0 0
    output: 0 0 0 0 0 0

final output:
 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Upvotes: 1

Related Questions