从原始的multiindex创建新的pandas multiindex df

问题描述 投票:0回答:2

我有一个多索引数据框 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 所做的计算,例如百分比变化、滚动平均值等?

谢谢。

python pandas dataframe multi-index
2个回答
0
投票

试试这个:

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
投票

IIUC,作为一种简单的方法,您可以在预定义的计算对上进行

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')
© www.soinside.com 2019 - 2024. All rights reserved.