如何有效地获取 Pandas DataFrame 中行之间的日志变化率?
How to get log rate of change between rows in Pandas DataFrame effectively?
假设我有一些 DataFrame(在我的例子中大约有 10000 行,这只是一个最小的例子)
>>> import pandas as pd
>>> sample_df = pd.DataFrame(
{'col1': list(range(1, 10)), 'col2': list(range(10, 19))})
>>> sample_df
col1 col2
0 1 10
1 2 11
2 3 12
3 4 13
4 5 14
5 6 15
6 7 16
7 8 17
8 9 18
出于我的目的,我需要为 DataFrame 中的每个 col_i
计算由 ln(col_i(n+1) / col_i(n))
表示的系列,其中 n
表示行号。
我如何计算这个?
背景知识
我知道我可以使用
以一种非常简单的方式获得每列之间的差异
>>> sample_df.diff()
col1 col2
0 NaN NaN
1 1 1
2 1 1
3 1 1
4 1 1
5 1 1
6 1 1
7 1 1
8 1 1
或百分比变化,即(col_i(n+1) - col_i(n))/col_i(n+1)
,使用
>>> sample_df.pct_change()
col1 col2
0 NaN NaN
1 1.000000 0.100000
2 0.500000 0.090909
3 0.333333 0.083333
4 0.250000 0.076923
5 0.200000 0.071429
6 0.166667 0.066667
7 0.142857 0.062500
8 0.125000 0.058824
我一直在努力寻找一种直接的方法来将每个连续的列直接除以前一列。如果我什至知道该怎么做,我可以在事后将自然对数应用于系列中的每个元素。
目前,为了解决我的问题,我正在创建另一列,将每列的行元素向下移动 1,然后在两列之间应用公式。不过,这对我来说似乎很乱而且次优。
如有任何帮助,我们将不胜感激!
您可以使用 shift 来实现您的建议。
>>> sample_df['col1'].shift()
0 NaN
1 1.0
2 2.0
3 3.0
4 4.0
5 5.0
6 6.0
7 7.0
8 8.0
Name: col1, dtype: float64
最终答案是:
import math
(sample_df['col1'] / sample_df['col1'].shift()).apply(lambda row: math.log(row))
0 NaN
1 0.693147
2 0.405465
3 0.287682
4 0.223144
5 0.182322
6 0.154151
7 0.133531
8 0.117783
Name: col1, dtype: float64
只需使用 np.log:
np.log(df.col1 / df.col1.shift())
您也可以按照@nikita 的建议使用 apply ,但这会比较慢。
另外,如果你想对整个数据框做这件事,你可以这样做:
np.log(df / df.shift())
IIUC:
一个比率的对数是对数的差:
sample_df.apply(np.log).diff()
或者更好:
np.log(sample_df).diff()
时机
假设我有一些 DataFrame(在我的例子中大约有 10000 行,这只是一个最小的例子)
>>> import pandas as pd
>>> sample_df = pd.DataFrame(
{'col1': list(range(1, 10)), 'col2': list(range(10, 19))})
>>> sample_df
col1 col2
0 1 10
1 2 11
2 3 12
3 4 13
4 5 14
5 6 15
6 7 16
7 8 17
8 9 18
出于我的目的,我需要为 DataFrame 中的每个 col_i
计算由 ln(col_i(n+1) / col_i(n))
表示的系列,其中 n
表示行号。
我如何计算这个?
背景知识
我知道我可以使用
以一种非常简单的方式获得每列之间的差异>>> sample_df.diff()
col1 col2
0 NaN NaN
1 1 1
2 1 1
3 1 1
4 1 1
5 1 1
6 1 1
7 1 1
8 1 1
或百分比变化,即(col_i(n+1) - col_i(n))/col_i(n+1)
,使用
>>> sample_df.pct_change()
col1 col2
0 NaN NaN
1 1.000000 0.100000
2 0.500000 0.090909
3 0.333333 0.083333
4 0.250000 0.076923
5 0.200000 0.071429
6 0.166667 0.066667
7 0.142857 0.062500
8 0.125000 0.058824
我一直在努力寻找一种直接的方法来将每个连续的列直接除以前一列。如果我什至知道该怎么做,我可以在事后将自然对数应用于系列中的每个元素。
目前,为了解决我的问题,我正在创建另一列,将每列的行元素向下移动 1,然后在两列之间应用公式。不过,这对我来说似乎很乱而且次优。
如有任何帮助,我们将不胜感激!
您可以使用 shift 来实现您的建议。
>>> sample_df['col1'].shift()
0 NaN
1 1.0
2 2.0
3 3.0
4 4.0
5 5.0
6 6.0
7 7.0
8 8.0
Name: col1, dtype: float64
最终答案是:
import math
(sample_df['col1'] / sample_df['col1'].shift()).apply(lambda row: math.log(row))
0 NaN
1 0.693147
2 0.405465
3 0.287682
4 0.223144
5 0.182322
6 0.154151
7 0.133531
8 0.117783
Name: col1, dtype: float64
只需使用 np.log:
np.log(df.col1 / df.col1.shift())
您也可以按照@nikita 的建议使用 apply ,但这会比较慢。
另外,如果你想对整个数据框做这件事,你可以这样做:
np.log(df / df.shift())
IIUC:
一个比率的对数是对数的差:
sample_df.apply(np.log).diff()
或者更好:
np.log(sample_df).diff()