我正在使用基于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()
答案 0 :(得分:1)
Run-length encoding(Wikipedia):
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)]
True / False是多余的,如果存储初始值,则可以进一步缩短。如果要使用时间戳,只需将戳记存储在值更改的地方。
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])