восстановление сжатой информации о кадре - PullRequest
0 голосов
/ 13 октября 2018

Я собираю двоичные данные, используя систему мониторинга на основе pygame, которая собирает данные о состоянии с разрешением, близким, но не точно, 0,2 секунды.Объект будет либо включен (1), либо выключен (0) и будет отслеживаться один час, в конце которого будет собрано 18 000 точек данных.

Моя проблема в том, что студенты будут читать этонабор данных использует Excel, поэтому, хотя его можно рассматривать как небольшой набор данных, если смотреть в Excel, это просто ошеломляет.Мне нужно, чтобы этот набор данных оставался легко видимым и понятным (т. Е. В форме csv), поэтому, когда я говорю, что хочу сжать размер фрейма данных, я не имею в виду уменьшение его размера с помощью общего алгоритма сжатия файлов.

Большую часть времени состояние объекта будет выключено.Это означает, что, возможно, 95% моих данных будут неизменными от одного момента времени к другому.Когда происходит изменение состояния на «включено», состояние «включено» обычно сохраняется гораздо дольше, чем всего на 0,2 секунды.

Вот краткий пример типичного кадра данных, который вы можете увидеть изПо столбцу действий я легко могу вычислить общее время, в течение которого что-то остается во включенном (или выключенном) состоянии, и matlotlib хорошо визуализирует эти данные с помощью гистограммы.Но моя проблема в том, что реальный информационный фрейм имеет огромное количество строк на каждую 0,2-секундную временную точку (приблизительно).

Я думал, что мог бы значительно уменьшить размер информационного фрейма, просто записав действия, которые отличаются отпоследний момент времени.Это уменьшает размер фрейма данных, но теперь усложняет интерпретацию данных.Например, при построении нового набора данных matplotlib не знает, как долго длится состояние «включено», так же как и моя функция getOnStatePeriods, которая не может правильно измерить промежуток времени для состояния «включено».Пожалуйста, запустите приведенный ниже код и посмотрите на исходные данные «df», а затем посмотрите на мою попытку уменьшить размер набора данных с помощью «dfSmall».

Этот набор данных не тот, который я бы назвал временной серией,поскольку pygame заставляет делать образцы примерно за 0,2 секунды, а не ТОЧНО через 0,2 секунды.

Меня устраивают методы, которые я использую для измерения состояний включения / выключения с использованием полного набора данных, просто кажется неэффективным хранить все события времени, когда ничего не меняется.Может быть, есть лучшая техника сжатия, которую я должен использовать?Кроме того, кажется, что я вынужден использовать гистограмму, а не простой «график», потому что простой график дает мне диагональные переходы ...

Любая помощь приветствуется.

import pandas as pd
import numpy as np
import io
import matplotlib.pyplot as plt

try:
    # for Python2
    from cStringIO import StringIO 
except ImportError:
    # for Python3
    from io import StringIO

def getOnStatePeriods(df):
    mask = df['action']==0 #mask is True for specified event
    mask[0] = True # maybe worth setting 1st element in event to zero, or: mask[0] = True
    df.loc[mask,'step1'] = df.loc[mask,'time']
    df['step2'] = df['step1'].fillna(method='ffill')
    df['step3'] = df['time']-df['step2']
    df['step4'] = df['step3'].shift(1)
    df.loc[mask,'step5'] = df.loc[mask,'step4']
    df['step6'] = df['step5'].replace(0, np.nan)
    df['step7'] = df['step6'].shift(-1)
    df.rename(columns={'step7': 'actionTime'}, inplace=True)
    longDf = df # Make one detailed longDf and one concise df:
    df = df[['time','action','actionTime']]
    return df


df = pd.read_csv(StringIO('''
time,action
.203,0
.401,0
.605,1
.802,1
1.001,0
1.201,0
1.403,1
1.606,1
1.803,1
2.004,0
2.201,0
2.407,0
'''.strip()))

dfSmall = pd.read_csv(StringIO('''
time,action
.203,0
.605,1
1.001,0
1.403,1
2.004,0
'''.strip()))

df = getOnStatePeriods(df) #df based on the ORIGINAL large dataframe
dfSmall = getOnStatePeriods(dfSmall) # df containing only times of state changes

fig, axes = plt.subplots(4,1, figsize=(6, 6), sharex=True)
axes[0].set_title("Original df")
axes[0].bar('time','action',data=df, color='red', align='edge', width=0.2)
axes[1].plot('time','action',data=df, color='red', alpha=0.5)
axes[2].set_title("'dfSmall' - where only state changes are recorded.")
axes[2].bar('time','action',data=dfSmall, color='blue', width=0.2)
axes[3].plot('time','action',data=dfSmall, color='blue', alpha=0.5)

plt.tight_layout()
plt.show()

My attempt at compressing a dataframe

1 Ответ

0 голосов
/ 13 октября 2018

Кодировка длин серий (Википедия) :

import random
import sys

random.seed(42) 


def getValue(lastValue): 
    if random.randint(1,100)==100:  # 1% change chance
        return not lastValue
    return lastValue

data = []
lastValue = False
for _ in range(18000):
    lastValue=getValue(lastValue)
    data.append(lastValue)

print(data)

def runLengthEncoded(data):
    rl = []
    last = data[0]
    occ = 1
    for d in data[1:]:
        if d == last:
            occ += 1
        else:
            rl.append( (last,occ))
            occ = 1
            last = d
    rl.append( (last,occ) )
    return rl

rl = runLengthEncoded(data)

print(rl)

Вывод здесь:

[(False, 110), (True, 90), (False, 297), (True, 173), (False, 37), (True, 108), (False, 28), 
(True, 54), (False, 154), (True, 234), (False, 137), (True, 7), (False, 164), (True, 32), 
(False, 167), (True, 107), (False, 9), (True, 100), (False, 114), (True, 73), (False, 73), 
# snipp # 
(False, 156), (True, 23), (False, 373), (True, 86), (False, 122), (True, 82), (False, 250), 
(True, 75), (False, 207), (True, 102), (False, 42), (True, 14), (False, 359), (True, 324), 
(False, 48), (True, 123), (False, 135), (True, 120), (False, 136), (True, 145), (False, 82)]

Истина / Ложь являются избыточными, если вы сохраняете исходный кодзначение вы можете сократить это еще больше.Если вы хотите использовать временные метки, просто сохраните метки там, где значение изменяется.

def runLengthEncoded2(data):
    rl = []
    last = data[0] 
    occ = 1
    for d in data[1:]:
        if d == last:
            occ += 1
        else:
            rl.append(occ)
            occ = 1
            last = d
    rl.append( occ )
    return (data[0],rl)

для:

(False, [110, 90, 297, 173, 37, 108, 28, 54, 154, 234, 137, 7, 164, 32, 167, 107, 9, 100, 114, 
         73, 73, 10, 21, 71, 35, 74, 238, 13, 20, 382, 112, 213, 67, 331, 13, 25, 74, 100, 48, 
         119, 74, 20, 72, 57, 86, 70, 283, 47, 26, 46, 12, 154, 14, 7, 129, 27, 69, 179, 129, 
         14, 33, 86, 9, 171, 36, 203, 81, 50, 28, 54, 58, 39, 108, 7, 34, 196, 139, 9, 205, 
         15, 45, 21, 209, 22, 40, 39, 19, 305, 15, 351, 24, 212, 3, 37, 26, 7, 150, 106, 176, 
         390, 61, 40, 194, 261, 89, 337, 457, 31, 53, 24, 487, 94, 334, 158, 446, 16, 300, 93, 
         5, 189, 62, 200, 136, 84, 75, 1, 179, 52, 19, 123, 54, 42, 130, 97, 77, 101, 11, 166, 
         85, 126, 156, 23, 373, 86, 122, 82, 250, 75, 207, 102, 42, 14, 359, 324, 48, 123, 135, 
         120, 136, 145, 82])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...