Python pandas: как вычислить производную/градиент
Учитывая, что у меня есть два следующих вектора:
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 (эпоха).
Цель: То, что я хотел бы рассчитать, - это битрейт.
Это означает, что я создам фрейм данных, например
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
Не могли бы вы рассказать о том, что я делаю неправильно?
Ответы
Ответ 1
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])
Ответ 2
Наивным объяснением было бы то, что diff буквально вычитает следующие записи, в то время как np.gradient использует центральную разностную схему.
Ответ 3
Поскольку в Pandas Series/DataFrame нет встроенного derivative
метода, вы можете использовать https://github.com/scls19fr/pandas-helper-calc.
Он предоставит новый метод доступа, называемый calc
для Pandas Series и DataFrames для вычисления числовых производных и интегралов.
Так что вы сможете просто сделать
recv.calc.derivative()
Это с помощью diff()
под капотом.