为什么子类化DataFrame会改变原始对象?

时间:2017-07-21 20:16:50

标签: python python-3.x pandas dataframe subclass

我忽略了warnings并尝试将pandas DataFrame子类化。我这样做的理由如下:

  • 我想保留DataFrame
  • 的所有现有方法
  • 我想在类实例化中设置一些额外的属性,稍后将用于定义我可以在子类上调用的其他方法。

这是一个片段:

class SubFrame(pd.DataFrame):

    def __init__(self, *args, **kwargs):
        freq = kwargs.pop('freq', None)
        ddof = kwargs.pop('ddof', None)
        super(SubFrame, self).__init__(*args, **kwargs)
        self.freq = freq
        self.ddof = ddof
        self.index.freq = pd.tseries.frequencies.to_offset(self.freq)

    @property
    def _constructor(self):
        return SubFrame

这是一个使用示例。说我有DataFrame

print(df)
               col0     col1     col2
2014-07-31  0.28393  1.84587 -1.37899
2014-08-31  5.71914  2.19755  3.97959
2014-09-30 -3.16015 -7.47063 -1.40869
2014-10-31  5.08850  1.14998  2.43273
2014-11-30  1.89474 -1.08953  2.67830

索引没有频率

print(df.index)
DatetimeIndex(['2014-07-31', '2014-08-31', '2014-09-30', '2014-10-31',
               '2014-11-30'],
              dtype='datetime64[ns]', freq=None)

使用SubFrame可以让我一步指定频率:

sf = SubFrame(df, freq='M')
print(sf.index)
DatetimeIndex(['2014-07-31', '2014-08-31', '2014-09-30', '2014-10-31',
               '2014-11-30'],
              dtype='datetime64[ns]', freq='M')

问题是,这会修改df

print(df.index.freq)
<MonthEnd>

这里发生了什么,我怎么能避免这种情况?

此外,我自称使用了我不太了解的copied代码。在__init__以上发生了什么?是否有必要在pop使用args / kwargs? (为什么我不能像往常一样指定params?)

1 个答案:

答案 0 :(得分:3)

我会添加警告。不是我想劝阻你,我实际上为你的努力喝彩。

然而,这不是你最后的问题。

那说,一旦你跑:

super(SubFrame, self).__init__(*args, **kwargs)

self是一个骨头数据框架。您通过将另一个数据帧传递给构造函数来创建它。

尝试将其作为实验

d1 = pd.DataFrame(1, list('AB'), list('XY'))
d2 = pd.DataFrame(d1)

d2.index.name = 'IDX'

d1

     X  Y
IDX      
A    1  1
B    1  1

因此,观察到的行为是一致的,因为当您通过将另一个数据帧传递给构造函数来构造一个数据帧时,您最终会指向相同的对象。

为了回答你的问题,子类化不是允许原始对象变异的东西......它是pandas从传递的数据帧构造数据帧的方式。

通过使用副本实例化来避免这种情况

d2 = pd.DataFrame(d1.copy())

__init__

中发生了什么

您希望将所有argskwargs传递给pd.DataFrame.__init__,但针对您的子类的特定kwargs除外。在这种情况下,freqddofpop是一种方便的方法,可以在将kwargs

传递给pd.DataFrame.__init__之前抓取值并从pipe删除密钥

我如何实施def add_freq(df, freq): df = df.copy() df.index.freq = pd.tseries.frequencies.to_offset(freq) return df df = pd.DataFrame(dict(A=[1, 2]), pd.to_datetime(['2017-03-31', '2017-04-30'])) df.pipe(add_freq, 'M')

foreach (var solid in this.Controls.OfType<PictureBox>())
{
    if (this.Location.X + this.Width / 2 >= solid.Location.X - solid.Width / 2)
        this.RightM = false;

    if (this.Location.X - this.Width / 2 >= solid.Location.X + solid.Width / 2)
         this.LeftM = false;

    if (this.Location.Y - this.Height / 2 <= solid.Location.Y + solid.Height / 2)
    {
        this.JumpB = false;
        this.ForceJump = 9;
    }

    if (this.Location.Y + this.Height / 2 >= solid.Location.Y - solid.Height / 2)
         this.JumpB = false;
    else
        this.Top -= ForceJump;
}