【问题标题】:How do I count number of occurrences per minute in a pandas data frame [duplicate]如何计算熊猫数据框中每分钟出现的次数[重复]
【发布时间】:2020-03-29 18:38:48
【问题描述】:

我有一个这样的熊猫数据框:

timestamp           status  
2019-01-01 09:00:00 FAILED
2019-01-01 09:00:00 FAILED
2019-01-01 09:00:00 UNKNOWN
2019-01-01 09:00:00 PASSED
2019-01-01 09:00:00 PASSED
2019-01-01 09:01:00 PASSED
2019-01-01 09:01:00 FAILED 

如何对每分钟的数据进行分组,统计每分钟每个状态的数量,得到这个数据框:

timestamp           PASSED FAILED UNKNOWN   
2019-01-01 09:00:00 2      2      1
2019-01-01 09:01:00 1      1      0

【问题讨论】:

  • pd.crosstab(df['timestamp'],df['status'])
  • 你有没有想要按分钟分组的第二个值?
  • 尝试了您的建议,似乎可行,非常感谢!在原始数据中,时间戳在一分钟内会有多个条目,因此在秒的范围内会有所不同。例如时间戳状态 2019-01-01 09:00:01 失败 2019-01-01 09:00:02 失败 2019-01-01 09:00:10 未知 2019-01-01 09:00:13 通过 2019-01- 01 09:00:24 通过 2019-01-01 09:01:02 通过 2019-01-01 09:01:30 失败
  • 如果答案是交叉表,则问题是枢轴

标签: python pandas pandas-groupby


【解决方案1】:

如果时间戳有秒数,您可以先将它们删除以按整分钟分组。

df2 = (
    df
    .groupby(df['timestamp'].map(lambda x: x.replace(second=0)))['status']
    .value_counts()
    .unstack(fill_value=0)
    .reset_index()
)
>>> df2
status           timestamp  FAILED  PASSED  UNKNOWN
0      2019-01-01 09:00:00       2       2        1
1      2019-01-01 09:01:00       1       1        0

您可能还希望填写范围内的每一分钟。与上面相同的代码,但不要在最后重置索引。那么:

df2 = df2.reindex(pd.date_range(df2.index[0], df2.index[-1], freq='1min'), fill_value=0)

时间

时间肯定会因数据集(小型与大型、异构数据与同质等)而异。鉴于数据集基本上是一个日志,人们会期望大量数据的时间戳变化很大。为了创建更合适的测试数据,让示例数据帧大 100k 倍,然后使时间戳唯一(每分钟一个)。

df_ = pd.concat([df] * 100000)
df_['timestamp'] = pd.date_range(df_.timestamp.iat[0], periods=len(df_), freq='1min')

以下是新的时间安排:

%timeit pd.crosstab(df_['timestamp'],df['status'])
# 4.27 s ± 150 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df_.groupby(['timestamp','status']).size().unstack(fill_value=0)
# 567 ms ± 34.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
(
    df_
    .groupby(['timestamp', 'status'])
    .size()
    .unstack(fill_value=0)
    .reset_index()
)
# 614 ms ± 27.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
(
    df_
    .groupby(df['timestamp'].map(lambda x: x.replace(second=0)))['status']
    .value_counts()
    .unstack(fill_value=0)
    .reset_index()
)
# 147 ms ± 6.66 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

  • 我认为 unstack 有 fill_value 选项,可以让你从 fillna().astype() 轻松。
  • 一般来说,groupby().value_count().unstack() 的性能优于其他方法。 +1
  • 通常这与对两列进行分组相同,请参阅我的第二种方法@Quang Hoang
  • @ansev 您的示例数据框包含多少行。只是玩具示例中的 7?另外,我不相信您的方法可以将时间戳包含秒的分钟分组。
  • 你是什么意思“恶化数据框的大小”?
【解决方案2】:

方法一:

pd.crosstab(df['timestamp'],df['status'])

status               FAILED  PASSED  UNKNOWN
timestamp                                   
2019-01-01-09:00:00       2       2        1
2019-01-01-09:01:00       1       1        0

如果你想要像列这样的时间戳:

pd.crosstab(df['timestamp'],df['status'],colnames=[None]).reset_index()

             timestamp  FAILED  PASSED  UNKNOWN
0  2019-01-01-09:00:00       2       2        1
1  2019-01-01-09:01:00       1       1        0

方法二:

df.groupby(['timestamp','status']).size().unstack(fill_value=0)

时间对比:

看来方法2是最快的。

%%timeit
new_df=pd.crosstab(df['timestamp'],df['status'])
21 ms ± 759 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
new_df=df.groupby(['timestamp','status']).size().unstack(fill_value=0)
4.65 ms ± 290 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
df2 = (
    df
    .groupby(df['timestamp'].map(lambda x: x.replace(second=0)))['status']
    .value_counts()
    .unstack()
    .fillna(0)
    .astype(int)
    .reset_index()
)

8.5 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

【讨论】:

    【解决方案3】:

    这将起作用:

    df.groupby(['timestamp', 'status']).size().unstack(level=1)
    

    【讨论】:

      猜你喜欢
      • 2019-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-12
      • 2023-03-13
      • 2016-06-05
      相关资源
      最近更新 更多