【问题标题】:Take the average only of two consecutive values in pandas仅取熊猫中两个连续值的平均值
【发布时间】:2016-03-29 20:48:09
【问题描述】:

我有一个分布不均的数据框,例如

2013-05-16 17:33:30  485.75     NaN     NaN
2013-05-16 17:34:00  479.16     NaN     NaN
2013-05-16 17:35:30     NaN  429.90     NaN
2013-05-16 17:36:00     NaN  433.39     NaN
2013-05-16 17:37:30     NaN     NaN  415.94
2013-05-16 17:38:00     NaN     NaN  401.59
2013-05-16 17:49:30  432.23     NaN     NaN
2013-05-16 17:51:00     NaN  424.08     NaN
2013-05-16 17:52:30     NaN     NaN  411.67
2013-05-16 18:01:30  471.01     NaN     NaN
2013-05-16 18:02:00  474.11     NaN     NaN
2013-05-16 18:03:30     NaN  440.76     NaN
2013-05-16 18:04:00     NaN  438.82     NaN
2013-05-16 18:17:30  469.46     NaN     NaN
2013-05-16 18:18:00  460.93     NaN     NaN

我可以分别处理每一列。因此,对于每一列,我可以有一个、两个三个甚至 4 个由nans 包围的连续值。我想要做的是一次只取两个连续的行,并用它们的平均值替换它们的值,也用它们的平均值替换它们的索引。因此,我将用值和索引的平均值替换仅一行的任何两行连续值。所以上面的例子会变成

2013-05-16 17:33:45  482.45     NaN     NaN
2013-05-16 17:35:45     NaN  431.69     NaN
2013-05-16 17:37:45     NaN     NaN  408.76
2013-05-16 17:49:30  432.23     NaN     NaN
2013-05-16 17:51:00     NaN  424.08     NaN
2013-05-16 17:52:30     NaN     NaN  411.67
2013-05-16 18:01:45  472.56     NaN     NaN
2013-05-16 18:03:45     NaN  439.78     NaN
2013-05-16 18:17:45  465.19     NaN     NaN

所以连续的值被平均,只有一个值的行被单独留下。我尝试过df.resample('30s').resample('2min')(df+df.shift(1))/2 之类的方法,但到目前为止还没有运气。有什么想法吗?

注意:对于每一行,只有一列有值,其他列总是NaN

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    你可以先convertdatetimeindexUnix time,然后从index新建一列,得到每一列的mean。最后 dropna 并通过 to_datetime 将 Unix 时间转换为日期时间:

    print df
                              a       b       c
    2013-05-16 17:33:30  485.75     NaN     NaN
    2013-05-16 17:34:00  479.16     NaN     NaN
    2013-05-16 17:35:30     NaN  429.90     NaN
    2013-05-16 17:36:00     NaN  433.39     NaN
    2013-05-16 17:37:30     NaN     NaN  415.94
    2013-05-16 17:38:00     NaN     NaN  401.59
    2013-05-16 17:49:30  432.23     NaN     NaN
    2013-05-16 17:51:00     NaN  424.08     NaN
    2013-05-16 17:52:30     NaN     NaN  411.67
    2013-05-16 18:01:30  471.01     NaN     NaN
    2013-05-16 18:02:00  474.11     NaN     NaN
    2013-05-16 18:03:30     NaN  440.76     NaN
    2013-05-16 18:04:00     NaN  438.82     NaN
    2013-05-16 18:17:30  469.46     NaN     NaN
    2013-05-16 18:18:00  460.93     NaN     NaN
    
    #convert to unix time (need integers from datetime for mean)
    df.index = df.index.astype(np.int64) // 10**9
    #create column index from df.index
    df = df.reset_index()
    print df
             index       a       b       c
    0   1368725610  485.75     NaN     NaN
    1   1368725640  479.16     NaN     NaN
    2   1368725730     NaN  429.90     NaN
    3   1368725760     NaN  433.39     NaN
    4   1368725850     NaN     NaN  415.94
    5   1368725880     NaN     NaN  401.59
    6   1368726570  432.23     NaN     NaN
    7   1368726660     NaN  424.08     NaN
    8   1368726750     NaN     NaN  411.67
    9   1368727290  471.01     NaN     NaN
    10  1368727320  474.11     NaN     NaN
    11  1368727410     NaN  440.76     NaN
    12  1368727440     NaN  438.82     NaN
    13  1368728250  469.46     NaN     NaN
    14  1368728280  460.93     NaN     NaN
    
    df = pd.concat([df.groupby(df.a.isnull().diff().cumsum().fillna(0)).mean().set_index('index')[['a']],
                    df.groupby(df.b.isnull().diff().cumsum().fillna(0)).mean().set_index('index')[['b']],
                    df.groupby(df.c.isnull().diff().cumsum().fillna(0)).mean().set_index('index')[['c']]], axis=1)
    
    #drop rows with all NaN, remove index name (new in 0.18)
    df = df.dropna(how='all').rename_axis(None)  
    #convert unix time to datetime
    df.index = pd.to_datetime(df.index, unit='s')
    print df  
                               a        b        c
    2013-05-16 17:33:45  482.455      NaN      NaN
    2013-05-16 17:35:45      NaN  431.645      NaN
    2013-05-16 17:37:45      NaN      NaN  408.765
    2013-05-16 17:49:30  432.230      NaN      NaN
    2013-05-16 17:51:00      NaN  424.080      NaN
    2013-05-16 17:52:30      NaN      NaN  411.670
    2013-05-16 18:01:45  472.560      NaN      NaN
    2013-05-16 18:03:45      NaN  439.790      NaN
    2013-05-16 18:17:45  465.195      NaN      NaN 
    

    解释:

    首先,您需要根据值创建组,其中列包含数字。你需要 fillna 和值 0,因为有时函数 diff 之后的第一个值返回 NaN。在此示例中,它仅是 a 列。但在实际数据中,它也可以在b 列和c 列中。

    df1 = pd.DataFrame( {'isnull': df.a.isnull()})
    df1['diff'] = df1['isnull'].diff()
    df1['cumsum'] = df1['diff'].cumsum().fillna(0)
    print df1
       isnull   diff  cumsum
    0   False    NaN     0.0
    1   False  False     0.0
    2    True   True     1.0
    3    True  False     1.0
    4    True  False     1.0
    5    True  False     1.0
    6   False   True     2.0
    7    True   True     3.0
    8    True  False     3.0
    9   False   True     4.0
    10  False  False     4.0
    11   True   True     5.0
    12   True  False     5.0
    13  False   True     6.0
    14  False  False     6.0
    

    然后您可以通过此群组groupby 并聚合mean。因为你丢失了index,所以我创建了新的列index,它也是聚合的。然后我从index 列中set_index 并仅过滤一列abc,因为我concat 通过这个新索引将所有聚合数据帧。

    print df.groupby(df.a.isnull().cumsum().fillna(0)).mean()
            index        a       b       c
    a                                     
    0  1368725625  482.455     NaN     NaN
    1  1368725730      NaN  429.90     NaN
    2  1368725760      NaN  433.39     NaN
    3  1368725850      NaN     NaN  415.94
    4  1368726225  432.230     NaN  401.59
    5  1368726660      NaN  424.08     NaN
    6  1368727120  472.560     NaN  411.67
    7  1368727410      NaN  440.76     NaN
    8  1368727990  465.195  438.82     NaN
    
    print df.groupby(df.a.isnull().cumsum().fillna(0)).mean().set_index('index')
                      a       b       c
    index                              
    1368725625  482.455     NaN     NaN
    1368725730      NaN  429.90     NaN
    1368725760      NaN  433.39     NaN
    1368725850      NaN     NaN  415.94
    1368726225  432.230     NaN  401.59
    1368726660      NaN  424.08     NaN
    1368727120  472.560     NaN  411.67
    1368727410      NaN  440.76     NaN
    1368727990  465.195  438.82     NaN
    print df.groupby(df.a.isnull().cumsum().fillna(0)).mean().set_index('index')[['a']]
                     a
    index              
    1368725625  482.455
    1368725730      NaN
    1368725760      NaN
    1368725850      NaN
    1368726225  432.230
    1368726660      NaN
    1368727120  472.560
    1368727410      NaN
    1368727990  465.195
    

    如果您需要更自动的方法,请使用:

    #convert to unix time (need integers from datetime for mean)
    df.index = df.index.astype(np.int64) // 10**9
    #create column index from df.index
    df = df.reset_index()
    #print df
    
    dfs = []
    #select all columns without first index column
    for col in df.columns[1:]:
        dfs.append(df.groupby(df[col].isnull().diff().cumsum().fillna(0)).mean().set_index('index')[[col]])
    df = pd.concat(dfs, axis=1)
    
    #drop rows with all NaN
    df = df.dropna(how='all').rename_axis(None)  
    #convert unix time to datetime
    df.index = pd.to_datetime(df.index, unit='s')
    print df
                               a        b        c
    2013-05-16 17:33:45  482.455      NaN      NaN
    2013-05-16 17:35:45      NaN  431.645      NaN
    2013-05-16 17:37:45      NaN      NaN  408.765
    2013-05-16 17:49:30  432.230      NaN      NaN
    2013-05-16 17:51:00      NaN  424.080      NaN
    2013-05-16 17:52:30      NaN      NaN  411.670
    2013-05-16 18:01:45  472.560      NaN      NaN
    2013-05-16 18:03:45      NaN  439.790      NaN
    2013-05-16 18:17:45  465.195      NaN      NaN
    

    【讨论】:

    • 我想知道是否有一种方法可以避免手动设置每一列并使其更加自动化。不过,答案很好。
    • 答案已编辑,请检查。抱歉耽搁了。
    • 谢谢,您的编辑正是我在 40 分钟前实现您的答案时所做的:) 我更多地指的是一种无需遍历列的方法(对不起,我不是t 很清楚)。
    • 我认为附加到DataFramesdfs 列表的方式很好地实现为concat 函数中的输入。
    猜你喜欢
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 2020-04-23
    • 2021-04-04
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    相关资源
    最近更新 更多