Pandas 分组 ewm
Pandas groupby ewm
我已经标记了事件(时间序列)数据,其中事件以给定标签的随机间隔发生。我想计算组内 ewma 并将其作为新列添加到数据框中 "X1_EWMA"。到目前为止,这是代码:
import pandas as pd
import numpy as np
import altair as alt
n = 1000
df = pd.DataFrame({
'T': pd.date_range('20190101', periods=n, freq='H'),
'C1': np.random.choice(list('PYTHON'), n),
'C2': np.random.choice(list('FUN'), n),
'X1': np.random.randn(n),
'X2': 100 + 10 * np.random.randn(n)
})
ts = df.set_index('T')
display(df.head())
display(ts.head())
感谢 SO: Pandas Groupby and apply method with custom function),我能够使用以下方法计算分组 EWMA:
ewm = ts.groupby(['C1']).apply(lambda x: x['X1'].ewm(halflife=10).mean())
ewm.head()
它产生一个系列,由一个分类变量和日期时间索引。该序列的长度与原始数据帧和时间序列(df 和 ts)相同
现在我想我可以做一些体操,通过连接行索引(假设排序顺序没有改变)将它连接回原始数据框(df),但这似乎不正确,并且可能甚至是一种冒险的方法,因为 groupby 仅在一个分类标签内 - 我需要小心并做一些 checks/sorts/re-indexing。
似乎应该有一种更简单的方法可以将时间序列列直接添加到数据框 (df) 或时间序列 (ts),而无需创建单独的序列或数据框并将它们连接起来。如果我想添加滚动统计信息,情况也是如此,例如:
ts.groupby('C1').rolling(10).mean()
在此先感谢您的帮助或意见。
基于已接受答案的结果:
import pandas as pd
import numpy as np
import math
import altair as alt
alt.renderers.enable('notebook') # for rendering in the notebook
alt.data_transformers.enable('json') # for plotting data larger than 5000 points
# make a dataframe to test
n = 1000
df = pd.DataFrame({
'T': pd.date_range('20190101', periods=n, freq='H'),
'C1': np.random.choice(list('PYTHON'), n),
'C2': np.random.choice(list('FUN'), n),
'X1': np.linspace(0, 2*math.pi, n),
'X2': np.random.randn(n),
})
# add a new variable that is a function of X1, X2 + a random outlier probability
df['X3'] = 0.2 * df['X2'] + np.sin(df['X1']) + np.random.choice(a=[0, 2], size=n, p=[0.98, 0.02])
# make it a time series for later resampling use cases.
ts = df.set_index('T')
# SOLUTION: Add the ewma line with groupby().transform().
ts['ewm'] = ts.groupby(['C1'])['X3'].transform(lambda x: x.ewm(halflife=1).mean())
# plot the points and ewma using altair faceting and layering
points = alt.Chart().mark_circle(size=20, opacity=0.9).encode(
x = 'T',
y = 'X3',
color = 'C2',
).properties(width=270, height=170)
lines = alt.Chart().mark_line(size=1, color='red', opacity=1).encode(
x = 'T',
y = 'ewm'
)
alt.layer(points, lines).facet(facet='C1', data=ts.reset_index()).properties(columns=3)
你能试试这个吗?
不要设置 ts = df.set_index('T')
。然后你可以按照下面的方式做
ts['ewm']=ts.groupby(['C1'], sort=False).apply(lambda x: x['X1'].ewm(halflife=10).mean()).reset_index(drop=True)
让我们解决这个问题,使用 transform
:
t['ewm'] = ts.groupby(['C1'])['X1'].transform(lambda x: x.ewm(halflife=10).mean()).values()
接受的答案对于大型数据集来说非常慢。
我所做的是:
ts['ewm'] = ts.groupby(['C1']).ewm(halflife=10).mean().values
它似乎工作得很好
我已经标记了事件(时间序列)数据,其中事件以给定标签的随机间隔发生。我想计算组内 ewma 并将其作为新列添加到数据框中 "X1_EWMA"。到目前为止,这是代码:
import pandas as pd
import numpy as np
import altair as alt
n = 1000
df = pd.DataFrame({
'T': pd.date_range('20190101', periods=n, freq='H'),
'C1': np.random.choice(list('PYTHON'), n),
'C2': np.random.choice(list('FUN'), n),
'X1': np.random.randn(n),
'X2': 100 + 10 * np.random.randn(n)
})
ts = df.set_index('T')
display(df.head())
display(ts.head())
感谢 SO: Pandas Groupby and apply method with custom function),我能够使用以下方法计算分组 EWMA:
ewm = ts.groupby(['C1']).apply(lambda x: x['X1'].ewm(halflife=10).mean())
ewm.head()
它产生一个系列,由一个分类变量和日期时间索引。该序列的长度与原始数据帧和时间序列(df 和 ts)相同
现在我想我可以做一些体操,通过连接行索引(假设排序顺序没有改变)将它连接回原始数据框(df),但这似乎不正确,并且可能甚至是一种冒险的方法,因为 groupby 仅在一个分类标签内 - 我需要小心并做一些 checks/sorts/re-indexing。
似乎应该有一种更简单的方法可以将时间序列列直接添加到数据框 (df) 或时间序列 (ts),而无需创建单独的序列或数据框并将它们连接起来。如果我想添加滚动统计信息,情况也是如此,例如:
ts.groupby('C1').rolling(10).mean()
在此先感谢您的帮助或意见。
基于已接受答案的结果:
import pandas as pd
import numpy as np
import math
import altair as alt
alt.renderers.enable('notebook') # for rendering in the notebook
alt.data_transformers.enable('json') # for plotting data larger than 5000 points
# make a dataframe to test
n = 1000
df = pd.DataFrame({
'T': pd.date_range('20190101', periods=n, freq='H'),
'C1': np.random.choice(list('PYTHON'), n),
'C2': np.random.choice(list('FUN'), n),
'X1': np.linspace(0, 2*math.pi, n),
'X2': np.random.randn(n),
})
# add a new variable that is a function of X1, X2 + a random outlier probability
df['X3'] = 0.2 * df['X2'] + np.sin(df['X1']) + np.random.choice(a=[0, 2], size=n, p=[0.98, 0.02])
# make it a time series for later resampling use cases.
ts = df.set_index('T')
# SOLUTION: Add the ewma line with groupby().transform().
ts['ewm'] = ts.groupby(['C1'])['X3'].transform(lambda x: x.ewm(halflife=1).mean())
# plot the points and ewma using altair faceting and layering
points = alt.Chart().mark_circle(size=20, opacity=0.9).encode(
x = 'T',
y = 'X3',
color = 'C2',
).properties(width=270, height=170)
lines = alt.Chart().mark_line(size=1, color='red', opacity=1).encode(
x = 'T',
y = 'ewm'
)
alt.layer(points, lines).facet(facet='C1', data=ts.reset_index()).properties(columns=3)
你能试试这个吗?
不要设置 ts = df.set_index('T')
。然后你可以按照下面的方式做
ts['ewm']=ts.groupby(['C1'], sort=False).apply(lambda x: x['X1'].ewm(halflife=10).mean()).reset_index(drop=True)
让我们解决这个问题,使用 transform
:
t['ewm'] = ts.groupby(['C1'])['X1'].transform(lambda x: x.ewm(halflife=10).mean()).values()
接受的答案对于大型数据集来说非常慢。
我所做的是:
ts['ewm'] = ts.groupby(['C1']).ewm(halflife=10).mean().values
它似乎工作得很好