массив numpy (.ma): количество значений с момента последнего изменения значения? - PullRequest
3 голосов
/ 10 ноября 2011

у меня есть сигнал состояния (измеренный тепловым насосом) в массиве numpy.ma вместе с временными метками.То, что я хочу, - это продолжительность периодов, в которые он был включен, и продолжительность периодов, когда он был выключен.(НЕ ежедневное время или что-то в этом роде, это было бы легко ..)

Что у меня есть (примерное, на самом деле у меня значения минут более 16 месяцев ..):

Time    Value
12:00   0
12:01   1
12:02   1
...
12:29   1
12:30   1
12:31   0
...
12:41   0
12:42   1
...
13:01   1
13:02   0
...and so on

И что я хочу получить в качестве вывода:

running_time_was:
time   value (=minutes)
12:31  30
13:10  20

off_time_was:
time   value (=minutes)
12:42  11

(the exact timestamps doesn't matter so much, but there should be some)

Я уже спрашивал людей, которых я знаю, которые знают Python (они тоже понятия не имели), и пытался искать в Интернете, но я просто нене знаю, что искать.Так что, может быть, кто-нибудь хотя бы подскажет, какие слова я могу ввести в Google?:)

ps: Вау, переполнение стека это фантастика!Меня уже поразило удобство использования в качестве пассивного пользователя, но запрашивающий интерфейс еще лучше:)

Ответы [ 4 ]

3 голосов
/ 11 ноября 2011

Ну, наконец-то я получил себя для себя. Но миллионы благодаря ответу Джо Кингтона, который очень вдохновил меня и научил меня всему этому:)

Сценарий

import numpy as np

def main():
    # Generate some data...
    t = np.linspace(0, 10*np.pi, 30)
    x = np.sin(t)
    condition = np.where(x>0,1,0)

    onarray,offarray = on_off_times(condition)

    print "Condition: ",condition
    print "Ontimes:   ",onarray
    print "Offtimes:  ",offarray


def on_off_times(condition):

    changing=np.diff(condition)         #complete array, -1 when tunring off, +1 when turning on
    idx, = changing.nonzero()           #Indices of changepoints
    times=np.diff(idx)              #'Times' between changes
    times=np.r_[0,times]            # The first time can't be calculated ->is set to 0

    ontimes=np.where(changing[idx]<0,times,False)   #When turning off: Was Ontime (times-array with "False" instead of offtimes)
    offtimes=np.where(changing[idx]>0,times,False)  #When turning on:  Was Offtime

    onarray=np.r_[changing.copy(),0]            #copy the array with all the values and add 1(to have an "empty" array of the right size)
    offarray=np.r_[changing.copy(),0]

    np.put(onarray,idx,ontimes)         #Put the times into it (at the changepoints)
    np.put(offarray,idx,offtimes)

    return onarray,offarray

main()

Доходность в:

Condition:  [0 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
Ontimes:    [0 0 2 0 0 0 0 0 3 0 0 0 0 0 3 0 0 0 0 0 3 0 0 0 0 0 3 0 0 0]
Offtimes:   [0 0 0 0 0 3 0 0 0 0 0 3 0 0 0 0 0 3 0 0 0 0 0 3 0 0 0 0 0 0]

Что стоит упомянуть:

  • Да, код дает другой вывод, как я и просил в моем Вопросе .. Извините за неточность, но результат, который дает функция мне наконец нужно
  • Теперь мне просто нужно получить нули в выходах в масках, что будет легко.
  • Если у кого-нибудь есть более хороший способ поместить () данные в новый массив, пожалуйста, отредактируйте:)
  • Как дать ссылку на пользователя Джо? Или как поблагодарить его?
1 голос
/ 10 ноября 2011

По сути, у вас есть логический массив, и вы хотите найти начало и конец смежных областей.

Гораздо лучше избегать зацикливания на каждом элементе массива numpy.

Есть несколько разных способов сделать это, но я обычно делаю что-то похожее на это (что я, вероятно, изначально получилиз здесь ):

import numpy as np
def contiguous_regions(condition):
    """Finds contiguous True regions of the boolean array "condition". Returns
    a 2D array where the first column is the start index of the region and the
    second column is the end index."""

    # Find the indicies of changes in "condition"
    idx, = np.diff(condition).nonzero()

    # Prepend or append the start or end indicies to "idx"
    # if there's a block of "True"'s at the start or end...
    if condition[0]:
        idx = np.r_[0, idx]
    if condition[-1]:
        idx = np.r_[idx, len(condition)-1]

    return idx.reshape((-1,2))

В качестве быстрого примера:

import numpy as np

def main():
    # Generate some data...
    t = np.linspace(0, 6*np.pi, 100)
    x = np.sin(t)
    condition = x > 0

    regions = contiguous_regions(condition)
    lengths = regions[:,1] - regions[:,0]

    for reg, length in zip(regions, lengths):
        print 'Condition was True for {0} seconds'.format(length)
        print '    From time {0}s to {1}s'.format(*reg)

def contiguous_regions(condition):
    idx, = np.diff(condition).nonzero()

    if condition[0]:
        idx = np.r_[0, idx]
    if condition[-1]:
        idx = np.r_[idx, len(condition)-1]

    return idx.reshape((-1,2))

main()

Это дает:

Condition was True for 16 seconds
    From time 0s to 16s
Condition was True for 16 seconds
    From time 33s to 49s
Condition was True for 16 seconds
    From time 66s to 82s
0 голосов
/ 10 ноября 2011

(возможно) Ответ

Вы можете попробовать это:

Since = 0
for i in range(1, Data.shape[0]):
    #Switched off
    if Data[i, 1] == 0.0 and Data[i - 1, 1] == 1.0:
        print "{0} for {1}min".format(Data[i, 0], i - Since)
    #Switched on
    elif Data[i, 1] == 1.0 and Data[i - 1, 1] == 0.0:
        Since = i

Вы перебираете массив отверстий (Data), в первом столбце которого есть метки времени, а во втором столбце - 1.0 или 0.0 в зависимости от того, включен или выключен нагреватель.

Вы обнаруживаете изменение состояния, глядя на фактическое значение вкл / выкл и предыдущее. В зависимости от этих двух значений вы видите, был ли нагреватель Switched off или Switched on. Все, что вам нужно сделать, это сохранить значение текущего индекса в Since, и вы получите время включения нагревателя.

Сценарий

С помощью следующего скрипта вы можете настроить массив данных, запустить приведенный выше код и посмотреть, как он работает:

import datetime
import numpy as np

#Setting up OnOff array
OnOff = np.concatenate((np.zeros((7,)), np.ones((20,)), np.zeros((3,)), np.ones((5,)), np.zeros((4,)), np.ones((16,)), np.zeros((2,)), np.ones((2,)), np.zeros((1,))))

#Setting up time array
start = datetime.time(12, 00)
TimeStamps = []

for i in range(OnOff.size):
    TimeStamps.append(datetime.time(12 + i/60, np.mod(i, 60)))

TimeStamps = np.array(TimeStamps)

#Concatenating both arrays to a single array
Data = np.hstack((np.reshape(TimeStamps, (TimeStamps.size, 1)), np.reshape(OnOff, (OnOff.size, 1))))

Since = 0
for i in range(1, Data.shape[0]):
    #Switched off
    if Data[i, 1] == 0.0 and Data[i - 1, 1] == 1.0:
        print "{0} for {1}min".format(Data[i, 0], i - Since)
    #Switched on
    elif Data[i, 1] == 1.0 and Data[i - 1, 1] == 0.0:
        Since = i

Выход

12:27:00 for 20min
12:35:00 for 5min
12:55:00 for 16min
12:59:00 for 2min
0 голосов
/ 10 ноября 2011

Я бы сделал это следующим образом:

# read data from file
dt = {'names' : ('ts', 'state'), 'formats' : ('S5','i4')}
data = np.loadtxt(datafn, dtype = dt)
# minutes counter
mc = 1
# current state, current timestamp
cs = data[0]['state']
ct = data[0]['ts']
# states dictionary
states = {1 : [], 0 : []}

for minute in data[1:]:
    if cs != minute['state']:
        states[cs].append([ct, mc])
        mc = 0
        cs = minute['state']
        ct = minute['ts']
    else:
        mc += 1
# Printing the result
print 'On time'
for [ts, mc] in states[1]:
     print '%s\t%i' % (ts, mc)
print 'Off time'
for [ts, mc] in states[0]:
     print '%s\t%i' % (ts, mc)

Крайне непроверенный, но вы можете понять логику.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...