我有一个约40,000行的DataFrame。 DataFrame看起来大致如下:
Unix Time UTC Val. 1 Val. 2 Val. 3
1 1518544176.927486 2018-02-13 17:49:36.927486 5.00 0.25 2.00
2 1518544176.929897 2018-02-13 17:49:36.929897 4.50 1.00 3.00
3 1518544176.932310 2018-02-13 17:49:36.932310 4.00 0.75 1.75
...
第0列,第2-4列是<class 'numpy.float64'>
类型。第1列是<class 'pandas._libs.tslib.Timestamp'>
类型。当根据时间绘制任何数据列时,我们会看到一个波形。但是,收购中偶尔会出现中断。例如,我们可能有:
Unix Time UTC Val. 1 Val. 2 Val. 3
576 1518544181.755085 2018-02-13 17:49:41.755085 0.10 0.01 0.93
577 1518544182.041129 2018-02-13 17:49:42.041129 0.11 0.02 0.95
...
可以看出,读数576和577之间存在~0.3秒的差距。问题是,在绘制数据时,即使没有数据,matplotlib也会连接点。这个“问题”的解决方案已经在Stack Overflow和在线广告的其他问题中得到解决,虽然我不喜欢......好吧,其中任何一个,最好的选择似乎是将NaN插入到数据差距。由于matplotlib没有绘制NaNs,所以它是一种偷偷摸摸的方法来欺骗它使你的情节变得更加真实。
要做到这一点,我首先找到前两个读数之间的时间差(这是安全的),并使用两倍的值作为我的指标“是否有差距?”然后我遍历DataFrame,检查差距。找到一个后,我在数据列中创建一个临时的NaN行,并在时间列的采集间隙中间创建时间值。然后我修改一个由旧的DataFrame组成的新DataFrame,加上这一行。这可以在这里看到:
df2 = df.copy()
for i, row in df.iterrows():
# The following code checks the delta-t of all timestamp pairs.
# We have i > 0 because it can't activate on the first entry.
if i > 0:
delta_t_unix = row['Unix Time'] - prev_timestamp_unix
delta_t_utc = row['UTC'] - prev_timestamp_utc
# If delta_t_unix > the allowed data gap, add new timestamps and NaNs.
if delta_t_unix > allowed_gap:
time_unix = row['Unix Time'] - (delta_t_unix / 2.0)
time_utc = row['UTC'] - (delta_t_utc / 2.0)
val1 = np.nan
val2 = np.nan
val3 = np.nan
new_row = pd.DataFrame({'Unix Time': time_unix, 'UTC': time_utc,
'Val. 1': val1, 'Val. 2': val2,
'Val. 3': val3}, index = [i])
df2 = pd.concat([df2.ix[:i-1], new_row,
df2.ix[i:]]).reset_index(drop = True)
# Set the previous timestamp for use in the beginning of the loop.
prev_timestamp_unix = row[timestamp_unix]
prev_timestamp_utc = row[timestamp_utc]
# Make the final DataFrame with the completed lists.
df2 = df2[['Unix Time', 'UTC', 'Val. 1', 'Val. 2', 'Val. 3']]
目前这需要大约4.5秒,这要感谢this question(过去需要大约6.5,因为我愚蠢地迭代并创建每个列的新列表,然后创建一个新的DataFrame)。然而,这仍然比我预期或更喜欢的要慢得多。有没有人对如何提高速度有任何想法?我对Pandas和DataFrames还是一个新手,所以我相信这可能会更好。谢谢!
编辑:值得一提的是,如果我删除datetime
列,则会将时间分成两半(不幸的是,我无法在实践中将其删除)。
答案 0 :(得分:2)
您可以使用以下内容重新采样到2.4ms:
df['utc_time'] = pd.to_datetime(df['utc_time'])
df.set_index(df['utc_time'])[['val1','val2','val3']].resample('2.4ms', loffset='1.2ms').mean().reset_index()
答案 1 :(得分:1)
可以加快速度的事情:
df.itertuples()
代替df.iterrows()
,这可能会稍微改善执行时间。如果您可以发布改进,我会很感激,但根据我的经验,我测试的情况有很大差异(循环内更简单的指令提高了10倍)。
不是使用pd.concat
将行放在一起,而是创建一个元组列表,然后仅在此列表中的循环之后生成一个DataFrame。
for i, unix_time, utc_time, val1, val2, val3 in df.itertuples():
list_of_values = []
if i > 0:
delta_t_unix = unix_time - prev_timestamp_unix
delta_t_utc = utc_time - prev_timestamp_utc
if delta_t_unix > allowed_gap:
new_time_unix = unix_time - (delta_t_unix / 2.0)
new_time_utc = utc_time - (delta_t_utc / 2.0)
list_of_values.append((new_time_unix, new_time_utc, np.nan, np.nan, np.nan))
# Set the previous timestamp for use in the beginning of the loop.
prev_timestamp_unix = unix_time
prev_timestamp_utc = utc_time
list_of_values.append(((unix_time , utc_time, val1, val2, val3))
df2 = pd.DataFrame(list_of_values, columns=['Unix Time', 'UTC', 'Val. 1', 'Val. 2', 'Val. 3'])
这可能会加速很多事情。