熊猫数据框中的平均连续2行

时间:2019-05-02 01:26:33

标签: python pandas dataframe

我有一个看起来如下的数据集

userid time           val1 val2 val3 val4
1      2010-6-1 0:15  12   16   17   11
1      2010-6-1 0:30  11.5 14   15.2 10
1      2010-6-1 0:45  12   14   15   10
1      2010-6-1 1:00  8    11   13   0
.................................
.................................
2      2010-6-1 0:15  14   16   17   11
2      2010-6-1 0:30  11   14   15.2 10
2      2010-6-1 0:45  11   14   15   10
2      2010-6-1 1:00  9    11   13   0
.................................
.................................
3 ...................................
.................................
.................................

我想获得每两行的平均值。预期结果将是

userid time           val1  val2  val3  val4
1      2010-6-1 0:30  11.75 15    16.1  10.5
1      2010-6-1 1:00  10    12.5  14    5
..............................
..............................
2      2010-6-1 0:30  12.5  15    16.1  10.5
2      2010-6-1 1:00  10    12.5  14    5
.................................
.................................
3 ...................................
.................................
.................................

目前我的方法是

data = pd.read_csv("sample_dataset.csv")
i = 0
while i < len(data) - 1:
    x = data.iloc[i:i+2].mean()
    x['time'] = data.iloc[i+1]['time']
    data.iloc[i] = x
    i+=2
for i in range(len(data)):
    if i % 2 != 1:
        del data.iloc[i]

但这是非常低效的。因此,有人可以指出我一种获得预期结果的更好方法吗?在数据集中,我有超过1000000行

3 个答案:

答案 0 :(得分:5)

我正在使用resample

df.set_index('time').resample('30Min',closed = 'right',label ='right').mean()
Out[293]: 
                      val1  val2  val3  val4
time                                        
2010-06-01 00:30:00  11.75  15.0  16.1  10.5
2010-06-01 01:00:00  10.00  12.5  14.0   5.0

方法2

df.groupby(np.arange(len(df))//2).agg(lambda x : x.iloc[-1] if x.dtype=='datetime64[ns]' else x.mean())
Out[308]: 
                 time   val1  val2  val3  val4
0 2010-06-01 00:30:00  11.75  15.0  16.1  10.5
1 2010-06-01 01:00:00  10.00  12.5  14.0   5.0

更新解决方案

df.groupby([df.userid,np.arange(len(df))//2]).agg(lambda x : x.iloc[-1] if x.dtype=='datetime64[ns]' else x.mean()).reset_index(drop=True)

答案 1 :(得分:2)

此解决方案保留在大熊猫中,并且比groupby-agg解决方案性能更高:

>>> df = pd.DataFrame({"a":range(10),
                   "b":range(0, 20, 2),
                   "c":pd.date_range('2018-01-01', periods=10, freq='H')})
>>> df

   a   b                   c
0  0   0 2018-01-01 00:00:00
1  1   2 2018-01-01 01:00:00
2  2   4 2018-01-01 02:00:00
3  3   6 2018-01-01 03:00:00
4  4   8 2018-01-01 04:00:00
5  5  10 2018-01-01 05:00:00
6  6  12 2018-01-01 06:00:00
7  7  14 2018-01-01 07:00:00
8  8  16 2018-01-01 08:00:00
9  9  18 2018-01-01 09:00:00

>>> pd.concat([(df.iloc[::2, :2] + df.iloc[1::2, :2].values) / 2,
            df.iloc[::2, 2]], axis=1)

     a     b                   c
0  0.5   1.0 2018-01-01 00:00:00
2  2.5   5.0 2018-01-01 02:00:00
4  4.5   9.0 2018-01-01 04:00:00
6  6.5  13.0 2018-01-01 06:00:00
8  8.5  17.0 2018-01-01 08:00:00

性能:

In [41]: n = 100000

In [42]: df = pd.DataFrame({"a":range(n), "b":range(0, n*2, 2), "c":pd.date_range('2018-01-01', periods= n, freq='S')})

In [44]: df.shape
Out[44]: (100000, 3)

In [45]: %timeit pd.concat([(df.iloc[::2, :2] + df.iloc[1::2, :2].values) / 2, df.iloc[::2, 2]], axis=1)
2.21 ms ± 49.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [46]: %timeit df.groupby(np.arange(len(df))//2).agg(lambda x : x.iloc[-1] if x.dtype=='datetime64[ns]' else x.mean())
7.9 s ± 218 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

答案 2 :(得分:0)

我尝试了两个提到的答案。两者都奏效。但诺亚的答案是我所经历的最快的答案。因此,我将该答案标记为解决方案。 这是我对Noah的回答,带有一些解释,并进行了修改以与我的数据集对应。

为了使用Noah;的回答时间栏应该在第一或最后(我可能错了)。因此,我将时间栏移到了结尾

col = data.columns.tolist()
tmp = col[10]
col[10] = col[1]
col[1] = tmp
data2 = data[col]

然后我进行了串联。在这里, :: 2 表示每隔一列,:10 表示从0到9的列。然后,我将时间列添加到第10个索引

x = pd.concat([(data2.iloc[::2, :10] + data2.iloc[1::2, :10].values) / 2, data2.iloc[::2, 10]], axis=1)