【问题标题】:Is there a fast way to avoid for loops for generating a new data frame based on data from another data frame?有没有一种快速的方法来避免基于来自另一个数据帧的数据生成新数据帧的循环?
【发布时间】:2020-08-08 18:37:57
【问题描述】:

我需要在包含多个实时信号和一个时间戳列的数据框中找到某些触发器之间的数据。这些触发器保存在单独的数据框中。我有一个带有 for 循环的工作解决方案,它在我使用的相对较大的数据集上需要很长时间。我正在尝试通过列表理解来加快速度,但我找不到可行的解决方案。有谁知道如何更快地做到这一点?

for循环解决方案:

这是触发器数据框的样子:

      timestamp_x  start_trig            id        timestamp_y  end_trig
0   1592724037612         1.0            12      1592724068408      -1.0
1   1592724459283         1.0            23      1592724490290      -1.0
2   1592724514246         1.0            17      1592724545450      -1.0

这是将旧数据框中名称为“data”的行附加到名称为 new_df 的新数据框中的代码

for i in range(len(df_trig)):
            mask = data[(data['timestamp'] > df_trig.iloc[i].timestamp_x) & (data['timestamp'] < df_trig.iloc[i].timestamp_y)]
            new_df = new_df.append(mask)

这是我尝试用生成器解决的问题,但它不适合我:

new_df = pd.DataFrame(data[(data['timestamp'] > low_lim) & (data['timestamp'] < upp_lim)] for low_lim,upp_lim in zip(df_trig['timestamp_x'], df_trig['timestamp_y']))

提前感谢您的回答!

编辑:

原始数据框包含如下:

        timestamp          id        param1
0   1592724037612          23          56.1
1   1592724037712          23          56.1
2   1592724037812          23          56.0
...
100 1592724047612          17          54.7

目标是移动位于其他数据框的任何触发器对之间的所有行。因此,新数据框看起来几乎相同,只是缺少了超出触发数据框定义的范围的行。

【问题讨论】:

  • 您的预期输出如何?
  • @sygneto 我编辑了上面的原始问题以使其更易于理解。非常感谢您的帮助。

标签: python pandas


【解决方案1】:

我找到了一个基于列表理解的解决方案,它加快了处理时间:

list_cycles = [data[(data['timestamp'] > low_lim) & (data['timestamp'] < upp_lim)] for low_lim,upp_lim in zip(df_trig['timestamp_x'], df_trig['timestamp_y'])]
new_df = pd.concat(list_cycles,ignore_index = True)

【讨论】:

  • 来自 Pandas 文档:“迭代地将行附加到 DataFrame 比单个连接的计算量更大。更好的解决方案是将这些行附加到列表中,然后将列表与原始 DataFrame 连接起来一次全部。” pandas.pydata.org/pandas-docs/stable/reference/api/…
  • @jsmart 感谢您的建议。 “list_cycles”是一个数据帧列表,每个帧都携带一对开始和结束触发器的行。在我在这里进行研究期间,我发现一个线程告诉我 pd.concat 是在列表中生成通用数据框的最有效方法。您建议我附加一个列表,其中包含来自分离的数据框的所有行,然后生成该列表的新数据框,对吗?这是否会提高性能,我可能会弄清楚。
  • 是的,这是正确的(即,列表推导构建了一个数据框列表,并在最后将其连接起来)。这比每次通过列表重复附加到数据帧要快。请考虑发布您的绩效结果。
  • 尝试将 list_cycles 更改为“生成器理解”,如下所示:list_cycles = (data[(data['timestamp'] &gt; low_lim) &amp; (data['timestamp'] &lt; upp_lim)] for low_lim,upp_lim in zip(df_trig['timestamp_x'], df_trig['timestamp_y'])) - 右侧用括号括起来,而不是方括号。原因:内存使用量较低。
  • 在从循环更改为生成器表达式并进行了其他一些小的改进之后,我设法在 2 分钟内运行了代码,而之前运行了 1.5 小时。我不知道为什么改进如此疯狂。
【解决方案2】:

我做了一些没有 for 循环的代码。据我所知,使用 pandas 库的内置函数比使用 for 循环更快。但是,我不确定在你的情况下这是否足够快。

  1. 设置

数据帧触发

数据框数据

  1. 将三角函数合并到笛卡尔产品风格等数据。这使得所有的情况都是行。 我在堆栈溢出中找到了实现这一点的技巧,它使用临时键。

    data.assign(key=1).merge(trig.assign(key=1)).drop(columns='key')

    它会产生

  1. 筛选符合触发器的行。

    data.assign(key=1).merge(trig.assign(key=1)).drop(columns='key').query('timestamp_x

    它会产生

【讨论】:

  • @sagmoo 谢谢你的回答。虽然这适用于小数据集和几个触发信号,但它不适用于我,因为触发数据帧包含近 300 行,而原始数据集包含 1,000,000 行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 2015-12-31
  • 2018-12-25
  • 2018-07-15
  • 1970-01-01
  • 2018-12-10
相关资源
最近更新 更多