2017-07-21 7 views
2

warningsを無視して、pandas DataFrameをサブクラス化しようとしています。その理由は次のとおりです。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 

は使用例です。

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') 

問題は、この修正である:私は私が1つのステップで、その周波数を指定することができますインデックスはSubFrameを使用して何の周波数

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

を持っていない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 

を持っていると言いますdf

print(df.index.freq) 
<MonthEnd> 

ここでは何が起こっているのですか?これを避けるにはどうすればよいですか?

また、私はよく、すべてのことを理解していないcopiedコードを使用すると公言します。上記の__init__内で何が起こっていますか?ここでpopとargs/kwargsを使用する必要がありますか? (なぜ私はいつものようのparamsを指定することはできません?)

+0

サブクラスの典型的なユースケースは、修正することです/何らかの方法で基本クラスの機能を拡張します。あなたは本当にここでそれをやっていません。 DataFrameを特定の方法で設定するだけです。サブクラス化するのではなく、必要な方法で構築されたDataFrameを返すだけのファクトリタイプの関数/オブジェクトを作成することができます。サブクラス化は、この特定のユースケースに対して多くの意味を持たないようです。 – clockwatcher

+0

"あなたが望む方法で構築されたDataFrameを単に返すファクトリタイプの関数/オブジェクトを作成します。あなたはそれを詳述できますか?今私が持っているのは、データフレームが属性である標準の 'Class(オブジェクト)'です。そして、はい、ここには示されていない、他にもいくつかの方法を定義して機能を拡張しています。 –

+1

パイプでpiRSquaredの2番目の提案を見てください。彼はサブクラス化していないことに注意してください。 DataFrameをセットアップする方法で単にDataFrameを返す関数を作成しています。サブクラス化する必要はありません。あなたは行動を変えていません。ファクトリクラスの使い方の1つは、必要な方法で設定されたオブジェクトを作成することです。新しいDataFrameを最初のコピーに基づいて作成する場合は、既存のDataFrameをパラメータとして使用してコピーし、頻度を追加してからコピーを作成する関数を作成します。サブクラスはありません。 – clockwatcher

答えて

3

私は警告に追加します。私はあなたを落胆させたくない、私は実際にあなたの努力に拍手を送る。

しかし、これは何が起こっているかについてのあなたの最後の質問ではありません。

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

selfは骨善意データフレームである:あなたが実行した後、言った

。他のデータフレームをコンストラクタに渡して作成しました。

だから観察された行動は、あなたがコンストラクタに別のデータフレームを渡すことで、1つのデータフレームを構築するとき、あなたが同じオブジェクトを指して終わることで、一貫性のある実験

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 

としてこれを試してみてください。

あなたの質問に答えるために、サブクラス化は元のオブジェクトの突然変異を許可しているものではありません...パンダが渡されたデータフレームからデータフレームを構築する方法です。

は、あなたが特定の例外を除いてpd.DataFrame.__init__にすべてargskwargsに渡したい__init__

で何が起こっているコピー

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

でインスタンス化することによって、これを避けkwargsあなたのサブクラスを対象としています。この場合、freqddofです。 popは値を取得し、私は実装したいどのようにpd.DataFrame.__init__


に渡す前に、kwargsからキーを削除するのに便利な方法です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') 
+0

私は「コピーでインスタンス化することでこれを回避する」を除いてあなたに従います。 'copy()'は 'super(SubFrame、self)... 'の中でどこに行きますか?なぜですか?私は 'super'の仕組みに基づいて' self.copy'を疑ったでしょうが、それはエラーを投げています –

+0

私は 'SubFrame .__ init__'がコピーを強制するようには分かりません。私はいずれにせよ揺れることができた)。あなたはパンダがすることを変えるだろうから。代わりに 'sf = SubFrame(df.copy()、freq = 'M')'の代わりに 'sf = SubFrame(df、freq = 'M' – piRSquared

+0

さて、サブクラス化するには[ここ](http://pandas.pydata.org/pandas-docs/stable/internals.html#subclassing-pandas-data-structures)の2つの選択肢がありますこれらのいずれかが、この特定のケースで私がやろうとしていることに当てはまりますか? –

関連する問題