AttributeError: 'DataFrame'对象在Python中没有属性'colmap'。[英] AttributeError: 'DataFrame' object has no attribute 'colmap' in Python

本文是小编为大家收集整理的关于AttributeError: 'DataFrame'对象在Python中没有属性'colmap'。的处理方法,想解了AttributeError: 'DataFrame'对象在Python中没有属性'colmap'。的问题怎么解决?AttributeError: 'DataFrame'对象在Python中没有属性'colmap'。问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我是一名 Python 初学者,我尝试使用以下来源的代码:使用 python 中的带宽方法进行投资组合再平衡

到目前为止,代码运行良好.

问题是,如果我不想像往常那样调用函数 rebalance(df, tol),而是从数据帧中的某个位置调用,例如:rebalance(df[500:], tol),我会收到以下错误:

AttributeError: 'DataFrame' object has no attribute 'colmap'.所以我的问题是:我必须如何调整代码才能做到这一点?

代码如下:

<小时>
import datetime as DT
import numpy as np
import pandas as pd
import pandas.io.data as PID

def setup_df():
    df1 = PID.get_data_yahoo("IBM", 
                             start=DT.datetime(1970, 1, 1), 
                             end=DT.datetime.today())
    df1.rename(columns={'Adj Close': 'ibm'}, inplace=True)

    df2 = PID.get_data_yahoo("F", 
                             start=DT.datetime(1970, 1, 1), 
                             end=DT.datetime.today())
    df2.rename(columns={'Adj Close': 'ford'}, inplace=True)

    df = df1.join(df2.ford, how='inner')
    df = df[['ibm', 'ford']]
    df['sh ibm'] = 0
    df['sh ford'] = 0
    df['ibm value'] = 0
    df['ford value'] = 0
    df['ratio'] = 0
    # This is useful in conjunction with iloc for referencing column names by
    # index number
    df.colmap = dict([(col, i) for i,col in enumerate(df.columns)])
    return df

def invest(df, i, amount):
    """
    Invest amount dollars evenly between ibm and ford
    starting at ordinal index i.
    This modifies df.
    """
    c = df.colmap
    halfvalue = amount/2
    df.iloc[i:, c['sh ibm']] = halfvalue / df.iloc[i, c['ibm']]
    df.iloc[i:, c['sh ford']] = halfvalue / df.iloc[i, c['ford']]

    df.iloc[i:, c['ibm value']] = (
        df.iloc[i:, c['ibm']] * df.iloc[i:, c['sh ibm']])
    df.iloc[i:, c['ford value']] = (
        df.iloc[i:, c['ford']] * df.iloc[i:, c['sh ford']])
    df.iloc[i:, c['ratio']] = (
        df.iloc[i:, c['ibm value']] / df.iloc[i:, c['ford value']])

def rebalance(df, tol):
    """
    Rebalance df whenever the ratio falls outside the tolerance range.
    This modifies df.
    """
    i = 0
    amount = 100
    c = df.colmap
    while True:
        invest(df, i, amount)
        mask = (df['ratio'] >= 1+tol) | (df['ratio'] <= 1-tol)
        # ignore prior locations where the ratio falls outside tol range
        mask[:i] = False
        try:
            # Move i one index past the first index where mask is True
            # Note that this means the ratio at i will remain outside tol range
            i = np.where(mask)[0][0] + 1
        except IndexError:
            break
        amount = (df.iloc[i, c['ibm value']] + df.iloc[i, c['ford value']])
    return df

df = setup_df()
tol = 0.05 #setting the bandwidth tolerance
rebalance(df, tol)

df['portfolio value'] = df['ibm value'] + df['ford value']
df["ibm_weight"] = df['ibm value']/df['portfolio value']
df["ford_weight"] = df['ford value']/df['portfolio value']

print df['ibm_weight'].min()
print df['ibm_weight'].max()
print df['ford_weight'].min()
print df['ford_weight'].max()

# This shows the rows which trigger rebalancing
mask = (df['ratio'] >= 1+tol) | (df['ratio'] <= 1-tol)
print(df.loc[mask])

推荐答案

您遇到的问题是由于我的设计决策失误造成的.colmap 是 setup_df 中的 df 上定义的属性:

df.colmap = dict([(col, i) for i,col in enumerate(df.columns)])

它不是 DataFrame 的标准属性.

df[500:] 返回一个新的 DataFrame,它是通过将 df 中的数据复制到新的 DataFrame 中生成的.由于 colmap 不是标准属性,因此不会复制到新的 DataFrame 中.

要在 setup_df 返回的 DataFrame 以外的 DataFrame 上调用 rebalance,请将 c = df.colmap 替换为

c = dict([(col, j) for j,col in enumerate(df.columns)])

我也在原帖中进行了此更改.

PS.在另一个问题中,我选择在 df 本身上定义 colmap每次调用 rebalance 时都不必重新计算这个字典和 invest.

你的问题告诉我,这个小优化不值得做这些函数如此依赖于返回的 DataFrame 的特殊性setup_df.

<小时>

使用rebalance(df[500:], tol)会遇到第二个问题:

由于df[500:]返回df部分的副本,rebalance(df[500:], tol)将修改此副本而不是原始 df.如果对象,df[500:],在 rebalance(df[500:], tol) 之外没有引用,这将是垃圾在对 rebalance 的调用完成后收集.所以整个计算会丢失.因此 rebalance(df[500:], tol) 没有用.

相反,您可以修改 rebalance 以接受 i 作为参数:

def rebalance(df, tol, i=0):
    """
    Rebalance df whenever the ratio falls outside the tolerance range.
    This modifies df.
    """
    c = dict([(col, j) for j, col in enumerate(df.columns)])
    while True:
        mask = (df['ratio'] >= 1+tol) | (df['ratio'] <= 1-tol)
        # ignore prior locations where the ratio falls outside tol range
        mask[:i] = False
        try:
            # Move i one index past the first index where mask is True
            # Note that this means the ratio at i will remain outside tol range
            i = np.where(mask)[0][0] + 1
        except IndexError:
            break
        amount = (df.iloc[i, c['ibm value']] + df.iloc[i, c['ford value']])
        invest(df, i, amount)
    return df

然后您可以使用从第 500 行开始重新平衡 df

rebalance(df, tol, i=500)

请注意,这会找到第一行在或之后 i=500 需要再平衡.它不一定在 i=500 本身重新平衡.这允许您为任意 i 调用 rebalance(df, tol, i),而无需提前确定是否需要对行 i 进行重新平衡.

本文地址:https://www.itbaoku.cn/post/1728076.html