python pandas:如何计算derivative/gradient
python pandas: how to calculate derivative/gradient
鉴于我有以下两个向量:
In [99]: time_index
Out[99]:
[1484942413,
1484942712,
1484943012,
1484943312,
1484943612,
1484943912,
1484944212,
1484944511,
1484944811,
1484945110]
In [100]: bytes_in
Out[100]:
[1293981210388,
1293981379944,
1293981549960,
1293981720866,
1293981890968,
1293982062261,
1293982227492,
1293982391244,
1293982556526,
1293982722320]
其中 bytes_in 是一个增量计数器,time_index 是一个 unix 时间戳列表(纪元)。
Objective:我要计算的是码率
这意味着我将构建一个类似
的数据框
In [101]: timeline = pandas.to_datetime(time_index, unit="s")
In [102]: recv = pandas.Series(bytes_in, timeline).resample("300S").mean().ffill().apply(lambda i: i*8)
In [103]: recv
Out[103]:
2017-01-20 20:00:00 10351849683104
2017-01-20 20:05:00 10351851039552
2017-01-20 20:10:00 10351852399680
2017-01-20 20:15:00 10351853766928
2017-01-20 20:20:00 10351855127744
2017-01-20 20:25:00 10351856498088
2017-01-20 20:30:00 10351857819936
2017-01-20 20:35:00 10351859129952
2017-01-20 20:40:00 10351860452208
2017-01-20 20:45:00 10351861778560
Freq: 300S, dtype: int64
问题:现在,奇怪的是,手动计算梯度给了我:
In [104]: (bytes_in[1]-bytes_in[0])*8/300
Out[104]: 4521.493333333333
这是正确的值..
在用 pandas 计算梯度时给我
In [124]: recv.diff()
Out[124]:
2017-01-20 20:00:00 NaN
2017-01-20 20:05:00 1356448.0
2017-01-20 20:10:00 1360128.0
2017-01-20 20:15:00 1367248.0
2017-01-20 20:20:00 1360816.0
2017-01-20 20:25:00 1370344.0
2017-01-20 20:30:00 1321848.0
2017-01-20 20:35:00 1310016.0
2017-01-20 20:40:00 1322256.0
2017-01-20 20:45:00 1326352.0
Freq: 300S, dtype: float64
与上面不同,1356448.0不同于4521.493333333333
能否请您指教我做错了什么?
pd.Series.diff()
只取差值。它也不会除以索引的增量。
这会给你答案
recv.diff() / recv.index.to_series().diff().dt.total_seconds()
2017-01-20 20:00:00 NaN
2017-01-20 20:05:00 4521.493333
2017-01-20 20:10:00 4533.760000
2017-01-20 20:15:00 4557.493333
2017-01-20 20:20:00 4536.053333
2017-01-20 20:25:00 4567.813333
2017-01-20 20:30:00 4406.160000
2017-01-20 20:35:00 4366.720000
2017-01-20 20:40:00 4407.520000
2017-01-20 20:45:00 4421.173333
Freq: 300S, dtype: float64
您也可以使用 numpy.gradient
传递 bytes_in
和您期望的增量。这不会将长度减一,而是对边进行假设。
np.gradient(bytes_in, 300) * 8
array([ 4521.49333333, 4527.62666667, 4545.62666667, 4546.77333333,
4551.93333333, 4486.98666667, 4386.44 , 4387.12 ,
4414.34666667, 4421.17333333])
一个天真的解释是 diff 从字面上减去了后面的条目,而 np.gradient 使用中心差异方案。
由于 Pandas 系列/DataFrame 中没有内置 derivative
方法,您可以使用 https://github.com/scls19fr/pandas-helper-calc.
它将为 Pandas 系列和 DataFrame 提供一个名为 calc
的新访问器,以计算数值导数和积分。
所以你将能够简单地做到
recv.calc.derivative()
它在后台使用 diff()
。
或者如果您想计算变化率,您可以使用 df.pct_change()
作为参数,您可以输入 df.pct_change(n)
,其中 n
是回顾期,假设您有日期时间索引数据框。
要获得正确的时间导数,请更改 serie
的索引
def derivate(serie):
df1 = (serie.diff() / serie.index.to_series().diff().dt.total_seconds()).dropna()
df1.index = serie.index[0:-1]
return df1
鉴于我有以下两个向量:
In [99]: time_index
Out[99]:
[1484942413,
1484942712,
1484943012,
1484943312,
1484943612,
1484943912,
1484944212,
1484944511,
1484944811,
1484945110]
In [100]: bytes_in
Out[100]:
[1293981210388,
1293981379944,
1293981549960,
1293981720866,
1293981890968,
1293982062261,
1293982227492,
1293982391244,
1293982556526,
1293982722320]
其中 bytes_in 是一个增量计数器,time_index 是一个 unix 时间戳列表(纪元)。
Objective:我要计算的是码率
这意味着我将构建一个类似
的数据框In [101]: timeline = pandas.to_datetime(time_index, unit="s")
In [102]: recv = pandas.Series(bytes_in, timeline).resample("300S").mean().ffill().apply(lambda i: i*8)
In [103]: recv
Out[103]:
2017-01-20 20:00:00 10351849683104
2017-01-20 20:05:00 10351851039552
2017-01-20 20:10:00 10351852399680
2017-01-20 20:15:00 10351853766928
2017-01-20 20:20:00 10351855127744
2017-01-20 20:25:00 10351856498088
2017-01-20 20:30:00 10351857819936
2017-01-20 20:35:00 10351859129952
2017-01-20 20:40:00 10351860452208
2017-01-20 20:45:00 10351861778560
Freq: 300S, dtype: int64
问题:现在,奇怪的是,手动计算梯度给了我:
In [104]: (bytes_in[1]-bytes_in[0])*8/300
Out[104]: 4521.493333333333
这是正确的值..
在用 pandas 计算梯度时给我
In [124]: recv.diff()
Out[124]:
2017-01-20 20:00:00 NaN
2017-01-20 20:05:00 1356448.0
2017-01-20 20:10:00 1360128.0
2017-01-20 20:15:00 1367248.0
2017-01-20 20:20:00 1360816.0
2017-01-20 20:25:00 1370344.0
2017-01-20 20:30:00 1321848.0
2017-01-20 20:35:00 1310016.0
2017-01-20 20:40:00 1322256.0
2017-01-20 20:45:00 1326352.0
Freq: 300S, dtype: float64
与上面不同,1356448.0不同于4521.493333333333
能否请您指教我做错了什么?
pd.Series.diff()
只取差值。它也不会除以索引的增量。
这会给你答案
recv.diff() / recv.index.to_series().diff().dt.total_seconds()
2017-01-20 20:00:00 NaN
2017-01-20 20:05:00 4521.493333
2017-01-20 20:10:00 4533.760000
2017-01-20 20:15:00 4557.493333
2017-01-20 20:20:00 4536.053333
2017-01-20 20:25:00 4567.813333
2017-01-20 20:30:00 4406.160000
2017-01-20 20:35:00 4366.720000
2017-01-20 20:40:00 4407.520000
2017-01-20 20:45:00 4421.173333
Freq: 300S, dtype: float64
您也可以使用 numpy.gradient
传递 bytes_in
和您期望的增量。这不会将长度减一,而是对边进行假设。
np.gradient(bytes_in, 300) * 8
array([ 4521.49333333, 4527.62666667, 4545.62666667, 4546.77333333,
4551.93333333, 4486.98666667, 4386.44 , 4387.12 ,
4414.34666667, 4421.17333333])
一个天真的解释是 diff 从字面上减去了后面的条目,而 np.gradient 使用中心差异方案。
由于 Pandas 系列/DataFrame 中没有内置 derivative
方法,您可以使用 https://github.com/scls19fr/pandas-helper-calc.
它将为 Pandas 系列和 DataFrame 提供一个名为 calc
的新访问器,以计算数值导数和积分。
所以你将能够简单地做到
recv.calc.derivative()
它在后台使用 diff()
。
或者如果您想计算变化率,您可以使用 df.pct_change()
作为参数,您可以输入 df.pct_change(n)
,其中 n
是回顾期,假设您有日期时间索引数据框。
要获得正确的时间导数,请更改 serie
def derivate(serie):
df1 = (serie.diff() / serie.index.to_series().diff().dt.total_seconds()).dropna()
df1.index = serie.index[0:-1]
return df1