【问题标题】:pandas groupby datetime columns by periodspandas groupby datetime 列按句点
【发布时间】:2021-06-21 04:24:11
【问题描述】:

我有以下数据框:

df=pd.DataFrame(np.array([[1,2,3,4,7,9,5],[2,6,5,4,9,8,2],[3,5,3,21,12,6,7],[1,7,8,4,3,4,3]]),
              columns=['9:00:00','9:05:00','09:10:00','09:15:00','09:20:00','09:25:00','09:30:00'])


>>> 9:00:00     9:05:00       09:10:00  09:15:00    09:20:00    09:25:00    09:30:00 ....
a       1          2             3         4           7           9           5
b       2          6             5         4           9           8           2
c       3          5             3         21         12           6           7
d       1          7             8         4           3           4           3

我想为每一行(例如 a、b、c、d ...)获取特定时间之间的平均值。时间在 9-15 之间,我想按期间分组,例如计算 09:00:00 到 11:00:00、11-12 之间、13-15 之间(或我决定的任何时间段)之间的平均值到)。 我首先尝试将列值转换为日期时间格式,然后我认为这样做会更容易:

df.columns = pd.to_datetime(df.columns,format="%H:%M:%S")

但后来我得到了带有假年份“1900-01-01 09:00:00”的冷却名称...... 而且,列标题类型是对象,所以我感觉有点失落......

我的最终目标是能够仅在定义的时间段内(例如 9-11 等...)的列之间计算具有每行平均值的新列

【问题讨论】:

    标签: python pandas datetime pandas-groupby mean


    【解决方案1】:

    如果需要一段时间,例如每 2 小时:

    df.columns = pd.to_datetime(df.columns,format="%H:%M:%S")
    
    df1 = df.resample('2H', axis=1).mean()
    print (df1)
       1900-01-01 08:00:00
    0             4.428571
    1             5.142857
    2             8.142857
    3             4.285714
    

    如果需要一些自定义期间可以使用cut:

    df.columns = pd.to_datetime(df.columns,format="%H:%M:%S")
    
    bins = ['5:00:00','9:00:00','11:00:00','12:00:00', '23:59:59']
    dates = pd.to_datetime(bins,format="%H:%M:%S")
    labels = [f'{i}-{j}' for i, j in zip(bins[:-1], bins[1:])] 
    df.columns = pd.cut(df.columns, bins=dates, labels=labels, right=False)
    print (df)
       9:00:00-11:00:00  9:00:00-11:00:00  9:00:00-11:00:00  9:00:00-11:00:00  \
    0                 1                 2                 3                 4   
    1                 2                 6                 5                 4   
    2                 3                 5                 3                21   
    3                 1                 7                 8                 4   
    
       9:00:00-11:00:00  9:00:00-11:00:00  9:00:00-11:00:00  
    0                 7                 9                 5  
    1                 9                 8                 2  
    2                12                 6                 7  
    3                 3                 4                 3  
    

    最后每列使用mean,NaN 列的原因是列是分类:

    df2 = df.mean(level=0, axis=1)
    print (df2)
       9:00:00-11:00:00  5:00:00-9:00:00  11:00:00-12:00:00  12:00:00-23:59:59
    0          4.428571              NaN                NaN                NaN
    1          5.142857              NaN                NaN                NaN
    2          8.142857              NaN                NaN                NaN
    3          4.285714              NaN                NaN                NaN
    

    为避免NaNs 列将列名转换为字符串:

    df3 = df.rename(columns=str).mean(level=0, axis=1)
    print (df3)
       9:00:00-11:00:00
    0          4.428571
    1          5.142857
    2          8.142857
    3          4.285714
    

    编辑:上面使用 timedeltas 的解决方案,因为格式 HH:MM:SS:

    df.columns = pd.to_timedelta(df.columns)
    print (df)
       0 days 09:00:00  0 days 09:05:00  0 days 09:10:00  0 days 09:15:00  \
    0                1                2                3                4   
    1                2                6                5                4   
    2                3                5                3               21   
    3                1                7                8                4   
    
       0 days 09:20:00  0 days 09:25:00  0 days 09:30:00  
    0                7                9                5  
    1                9                8                2  
    2               12                6                7  
    3                3                4                3 
    

    bins = ['9:00:00','11:00:00','12:00:00']
    dates = pd.to_timedelta(bins)
    labels = [f'{i}-{j}' for i, j in zip(bins[:-1], bins[1:])] 
    df.columns = pd.cut(df.columns, bins=dates, labels=labels, right=False)
    print (df)
       9:00:00-11:00:00  9:00:00-11:00:00  9:00:00-11:00:00  9:00:00-11:00:00  \
    0                 1                 2                 3                 4   
    1                 2                 6                 5                 4   
    2                 3                 5                 3                21   
    3                 1                 7                 8                 4   
    
       9:00:00-11:00:00  9:00:00-11:00:00  9:00:00-11:00:00  
    0                 7                 9                 5  
    1                 9                 8                 2  
    2                12                 6                 7  
    3                 3                 4                 3 
    

    #missing values because not exist datetimes between 11:00:00-12:00:00
    df2 = df.mean(level=0, axis=1)
    print (df2)
       9:00:00-11:00:00  11:00:00-12:00:00
    0          4.428571                NaN
    1          5.142857                NaN
    2          8.142857                NaN
    3          4.285714                NaN
    
    df3 = df.rename(columns=str).mean(level=0, axis=1)
    print (df3)
       9:00:00-11:00:00
    0          4.428571
    1          5.142857
    2          8.142857
    3          4.285714
    

    【讨论】:

    • 感谢您的回答。在 2H 的第一个示例中,我得到了我的数据框中不存在的奇怪时间(例如 00:00:00 .02:00:00 ),尽管我只有 9-15 之间。在第二部分,由于某种原因,在 bins aleays 中的最后一个小时得到 NaN,我不确定为什么要执行 df.rename().mean(),比如我们为什么要计算两次平均值?
    • @Reut - 对于第一个 pandas,从 0 开始创建 2H 的范围,所以看起来需要像第二个解决方案那样的自定义标签。
    • @Reut - 如何使用, right=True
    • @jezreal 很抱歉,但我不明白你的回答,你能试着解释一下你的意思是什么意思 rehard costum label 和 right=True - wehere?
    • @Reut - 好的,你的bins在真实数据解决方案中是什么?
    【解决方案2】:

    我将向您展示我的代码和弹出后的结果。

    首先导入库和数据框

    import numpy as np
    import pandas as pd
    
    df=pd.DataFrame(np.array([[1,2,3,4,7,9,5],[2,6,5,4,9,8,2],[3,5,3,21,12,6,7], 
    [1,7,8,4,3,4,3]]),
              columns= 
             ['9:00:00','9:05:00','09:10:00','09:15:00','09:20:00','09:25:00','09:30:00'])
    

    最好创建一个类来定义什么是句号:

    class Period():
        def __init__(self,initial,end):
            self.initial=initial
            self.end=end
    
        def __repr__(self):
            return self.initial +' -- ' +self.end
    

    使用命令 .loc 我们可以得到一个包含我想要的列的子数据框:

           `def get_colMean(df,period):
               df2 = df.loc[:,period.initial:period.end]
               array_mean = df.mean(axis=1).values
    
               col_name = 'mean_'+period.initial+'--'+period.end
               pd_colMean = pd.DataFrame(array_mean,columns=[col_name])
    
               return pd_colMean`        
    

    最后我们使用 .join in orde 将我们的列添加到我们的原始数据帧中:

    def join_colMean(df,period):
        pd_colMean = get_colMean(df,period)
        df = df.join(pd_colMean)
        return df
    

    我将向您展示我的结果:

    【讨论】:

    • date 和 hours 有问题,如果我不将其更改为 datetime 我会得到 keyerror,如果我将其更改为 datetime 我会得到 OutOfBoundsDatetime: OutOfBounds nanosecond timestamp: 1-01- 01 09:05:00
    • @Reut 不改成datetime会有什么错误??
    猜你喜欢
    • 2015-06-03
    • 1970-01-01
    • 2019-09-19
    • 1970-01-01
    • 2013-05-17
    • 2021-06-25
    • 2018-10-19
    • 2017-04-06
    • 2018-11-17
    相关资源
    最近更新 更多