提问人:AndysPythonStuff 提问时间:10/25/2023 最后编辑:AndysPythonStuff 更新时间:10/26/2023 访问量:63
从原始多索引创建新的 pandas 多索引 df
Making new pandas multiindex df from original multiindex
问:
我有一个多索引数据帧 df1,它是使用 yfinance 从雅虎提取的,带有时间序列索引和两级多索引列。级别 0 是“调整收盘价”、“最高价”和“成交量”,级别 1 是公司代码列表,如下所示:
调整关闭 | 高 | 卷 | |||||||
---|---|---|---|---|---|---|---|---|---|
C1级 | C2型 | C3型 | C1级 | C2型 | C3型 | C1级 | C2型 | C3型 | |
日期 | |||||||||
02-01-2020 | 12.78 | 41.73 | 24.03 | 13.50 | 41.77 | 26.43 | 100000 | 1234300 | 23454 |
03-01-2020 | 12.29 | 41.11 | 23.61 | 12.77 | 42.09 | 23.99 | 100022 | 1555555 | 23999 |
我试图通过对 df2 的列进行计算来制作一个新的数据帧 df1。
例如,使用相同的时间序列索引,Id 喜欢将新数据帧中的第一列 df2 设置为 df1 的(0 级)价格列中每个(1 级)交易品种的百分比增长。然后 df2 中的列是价格(级别 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 级值/键(不确定正确的术语)是 Ive 在 df1 上进行的计算,例如百分比变化、滚动平均值等?
谢谢。
答:
0赞
Aymen Azoui
10/25/2023
#1
试试这个:
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
评论
0赞
AndysPythonStuff
10/26/2023
谢谢。直觉上,这是 Id 尝试过的方法(如果我知道怎么做!我使用了您的代码,它产生了以下结果:空 DataFrame 列:[] 索引:[02-01-2020,03-01-2020,然后是红色页面:PerformanceWarning:DataFrame 高度碎片化。这通常是多次调用的结果,性能很差。请考虑改用 pd.concat(axis=1) 一次联接所有列。要获取去碎片化的帧,请使用 'newframe = frame.copy()frame.insert
1赞
Timeless
10/26/2023
#2
IIUC,作为一种简单的方法,您可以在预定义的计算对上连接
多个 x
:
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 = {k: [(w, f"{pre}{w}MA") for w in [10, 20, 50, 100, 200]]
for k, pre in [("Adj Close", "$"), ("Volume", "V")]}
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')
评论
0赞
AndysPythonStuff
10/26/2023
谢谢。。。我尝试了我的代码,并打开了一个新笔记本,两次我都得到:NameError:名称“i”未定义。我换了k,得到了一个结果。然而。。。你的代码比我的水平高出很多,所以我要一行一行地看一遍。毫无疑问,我学到了很多东西。谢谢!
0赞
Timeless
10/26/2023
哎呀,我们需要改成.我更新了我的答案。请随时提出任何问题;)i
w
0赞
AndysPythonStuff
10/27/2023
再次感谢。我还不假装理解你的代码,而且 pvs 超出了我目前的理解水平,但我一直在使用它,我确实有问题......1)你定义了函数xs(df,m),但是当你稍后调用它时,df.pipe(xs, “Adj Close”).pct_change() 你没有指定任何参数?为什么?另外,我不知道pipe()...2) 在 pct 中,您管道了 2 个函数,这似乎是这个想法,但在 tmp 和 chk 中,您没有......有什么理由吗?我问是因为 df.xs(“High”, axis=1) 似乎与 df.pipe(xs, “High”) 相同。谢谢。。。
评论