我有一个多索引数据框 df1,是使用 yfinance 从 yahoo 提取的,具有时间序列索引和两级多索引列。级别 0 是“调整收盘价”、“最高价”和“成交量”,级别 1 是公司代码列表,如下所示:
调整关闭 | 高 | 音量 | |||||||
---|---|---|---|---|---|---|---|---|---|
C1 | C2 | C3 | C1 | C2 | C3 | C1 | C2 | C3 | |
日期 | |||||||||
2020年2月1日 | 12.78 | 41.73 | 24.03 | 13.50 | 41.77 | 26.43 | 100000 | 1234300 | 23454 |
2020年3月1日 | 12.29 | 41.11 | 23.61 | 12.77 | 42.09 | 23.99 | 100022 | 1555555 | 23999 |
我正在尝试通过对 df1 的列进行计算来创建一个新的数据框 df2。
例如,使用相同的时间序列索引,我想在新数据帧 df2 中创建第一个列,即 df1 的(级别 0)价格列中每个(级别 1)符号的增长百分比。然后 df2 中的columns是价格(级别 0)每个交易品种(级别 1)的滚动移动平均值。还有一列,如果今天的最高价高于昨天的调整收盘价,则写入布尔值 True。
基本上,df2 中的每个列将通过操作 df1 中相应 1 级公司符号的 0 级数据来制作。
(我说的是列我现在知道它不是一列,而是一组按级别0分组的列)
所以我写了一个函数:
def indicators_df(df1):
# Create a new DataFrame with the same index as df1
df2 = pd.DataFrame(index=df1.index)
# Plus / minus change %
df2['Pct'] = df1['Adj Close'].pct_change().fillna(0)
# Price MAs
df2['$10MA'] = df1['Adj Close'].rolling(window=10).mean()
df2['$20MA'] = df1['Adj Close'].rolling(window=20).mean()
df2['$50MA'] = df1['Adj Close'].rolling(window=50).mean()
df2['$100MA'] = df1['Adj Close'].rolling(window=100).mean()
df2['$200MA'] = df1['Adj Close'].rolling(window=200).mean()
# Volume MAs
df2['V10MA'] = df1['Volume'].rolling(window=10).mean()
df2['V20MA'] = df1['Volume'].rolling(window=20).mean()
df2['V50MA'] = df1['Volume'].rolling(window=50).mean()
df2['V100MA'] = df1['Volume'].rolling(window=100).mean()
df2['V200MA'] = df1['Volume'].rolling(window=200).mean()
return df2
返回此错误:
ValueError: Cannot set a DataFrame with multiple columns to the single column Pct
我尝试了很多变体,但不断收到相同的错误,直到我意识到(我认为......)我试图将所有 1 级公司符号的结果放在新数据帧 df2 的一列中,该数据帧不是多索引.
那么我该如何正确编写函数,创建一个新的多索引数据帧,其中 0 级值/键(不确定正确的术语)是我对 df1 所做的计算,例如百分比变化、滚动平均值等?
谢谢。
试试这个:
import pandas as pd
def indicators_df(df1):
df2 = pd.DataFrame(index=df1.index)
for col in df1.columns.levels[1]:
df2[('Pct', col)] = df1['Adj Close', col].pct_change().fillna(0)
df2[('$10MA', col)] = df1['Adj Close', col].rolling(window=10).mean()
df2[('$20MA', col)] = df1['Adj Close', col].rolling(window=20).mean()
df2[('$50MA', col)] = df1['Adj Close', col].rolling(window=50).mean()
df2[('$100MA', col)] = df1['Adj Close', col].rolling(window=100).mean()
df2[('$200MA', col)] = df1['Adj Close', col].rolling(window=200).mean()
df2[('V10MA', col)] = df1['Volume', col].rolling(window=10).mean()
df2[('V20MA', col)] = df1['Volume', col].rolling(window=20).mean()
df2[('V50MA', col)] = df1['Volume', col].rolling(window=50).mean()
df2[('V100MA', col)] = df1['Volume', col].rolling(window=100).mean()
df2[('V200MA', col)] = df1['Volume', col].rolling(window=200).mean()
return df2
concat
多个 xs
:
def indicators_df(df):
def xs(df, m):
return df.xs(m, axis=1, drop_level=False)
def rn(df, d):
return df.rename(d, axis=1, level=0)
pct = (df.pipe(xs, "Adj Close").pct_change()
.fillna(0).pipe(rn, {"Adj Close": "Pct"}))
tmp = df.pipe(xs, "High")
chk = tmp.eq(tmp.shift()).pipe(rn, {"High": "Check"})
_map = {c: [(i, f"{c[0]}{i}MA") for i in windows]
for c in ["Adj Close", "Volume"]}
pvs = [df.pipe(xs, l0).rolling(b).mean()
.pipe(rn, {l0:l1}) for (l0, p) in _map.items()
for (b,l1) in p]
return pd.concat([pct, chk, *pvs], axis=1)
输出:
print(indicators_df(df))
Pct Check ... V100MA V200MA
C1 C2 C3 C1 C2 ... C2 C3 C1 C2 C3
Date ...
02-01-2020 0.00 0.00 0.00 False False ... NaN NaN NaN NaN NaN
03-01-2020 -0.04 -0.01 -0.02 False False ... NaN NaN NaN NaN NaN
[2 rows x 36 columns]
使用的输入:
df = pd.DataFrame.from_dict(
{'index': ['02-01-2020', '03-01-2020'],
'columns': [
('Adj Close', 'C1'), ('Adj Close', 'C2'), ('Adj Close', 'C3'),
('High', 'C1'), ('High', 'C2'), ('High', 'C3'), ('Volume', 'C1'),
('Volume', 'C2'),('Volume', 'C3')],
'data': [[12.78, 41.73, 24.03, 13.5, 41.77,
26.43, 100000, 1234300, 23454],
[12.29, 41.11, 23.61, 12.77, 42.09,
23.99, 100022, 1555555, 23999]],
'index_names': ['Date'],
'column_names': [None, None]}, orient='tight')