2016-01-19 7 views
9

私はRからpandasに切り替えました。私は私が問題を理解すると思うインデックス作成操作でビューまたはコピーを返すかどうかが定義されていない場合、pandasのビューポイントとは何ですか?

df_a = pd.DataFrame({'col1': [1,2,3,4]})  

# Filtering step, which may or may not return a view 
df_b = df_a[df_a['col1'] > 1] 

# Add a new column to df_b 
df_b['new_col'] = 2 * df_b['col1'] 

# SettingWithCopyWarning!! 

のような何かをするとき、私は喜んで私が間違って得たものを学びますけれども、私は日常的に、SettingWithCopyWarningsを取得します。与えられた例では、df_bdf_aのビューであるかどうかは不定です。したがって、df_bに割り当てる効果は不明です。それはdf_aに影響しますか?私たちは本当に私たちはビューを作成するかどうか、のために良い景色は何であるかどうかを確認することはできません場合:

df_a = pd.DataFrame({'col1': [1,2,3,4]})  

# Filtering step, definitely a copy now 
df_b = df_a[df_a['col1'] > 1].copy() 

# Add a new column to df_b 
df_b['new_col'] = 2 * df_b['col1'] 

# No Warning now 

私は、私が行方不明です何かがあると思います。問題は、フィルタリング時に明示的にコピーを作成することにより解決することができます?パンダのドキュメント(http://pandas-docs.github.io/pandas-docs-travis/indexing.html?highlight=view#indexing-view-versus-copy

からの簡単な例外では、それはそれ[のGetItem]が表示またはコピーを返すかどうかを予測するのは非常に難しい(それがどの程度、配列のメモリレイアウトに依存しますパンダは保証しません)

さまざまなインデックス方法についても同様の警告があります。

コード全体で.copy()呼び出しを振りかけるのは非常に面倒でerrorproneです。自分のDataFrameを操作するために間違ったスタイルを使用していますか?それとも、パフォーマンスが非常に高いので、明らかに不自然さを正当化するのでしょうか?

+0

この新しい警告は、次の割り当てによって安全に無効にすることができます。 'pd.options.mode.chained_assignment = None' –

+0

Hmmm、おそらくインデックスをリセットするのに役立ちます' df_b = df_a [df_a ['col1']> 1] .reset_index(drop = True) '。 – jezrael

+2

@GeorgePetrov私はそれを無効にすることを強くお勧めします!警告は正当な理由で出てきます。何かがあれば、警告の代わりに例外に宣伝することをお勧めします。 –

答えて

10

短い答えは、これは救済されているパンダの欠陥です。

the problem hereの詳細については、より長い議論がありますが、主な取り組みは、今すぐスライスして新しいコピーし、あなたはビューについて考える必要はありません。修正はまもなくこのrefactoring project.を介して行われますが、実際には直接修正しようとしましたが(see here)、現在のアーキテクチャでは実現できませんでした。

実際には、私たちはバックグラウンドで意見を守ります - 彼らは提供することができるときにパンダのスーパーメモリを効率的かつ高速にしますが、ユーザーから見れば隠れてしまいますDataFrameをスライス、インデックス作成、またはカットすると、元に戻すものは事実上新しいコピーになります。

(これは、ユーザがデータだけを読んでいるときのビューを作成することによって達成されていますが、割り当て操作が使用されるたびに割り当てが行われる前に、ビューはコピーに変換されます。)

ベストの推測があります修正は一年以内になる - 間もなく、私は一部の.copy()が必要かもしれない、恐れている、ごめんなさい!

2

私はこれがちょっと面白いことに同意します。私の現在のプラクティスは、私がしたいことが何であれ "機能的"な方法を探すことです(私の経験では、これらはほとんど常にカラムとシリーズ名の変更を除いて存在します)。ときにはコードがよりエレガントになることもありますが、時にはそれが悪化します(私はとassignが好きではありません)。しかし、少なくとも私は変更について心配する必要はありません。だから、インデックス作成のための

、代わりにスライス表記を使用しての、あなたはデフォルトでコピーを返しますquery使用することができます。

In [5]: df_a.query('col1 > 1') 
Out[5]: 
    col1 
1  2 
2  3 
3  4 

が、私は少しthis blog post.

編集でそれを展開します。をコメントに挙げられているように、私はqueryがデフォルトでコピーを返すのは間違っているようですが、assignスタイルを使用すると、割り当ては結果を返す前にコピーを作成します:すべて

df_b = (df_a.query('col1 > 1') 
      .assign(newcol = 2*df_a['col1'])) 
+0

df_b ['new1col'] = 2 * df_b ['col1'] 'がまだSettingWithCopyWarningを与えているのはなぜですか?df_b = df_a.query( 'col1> – screenpaver

+0

@maxymoo:これは私の質問の第2の部分、すなわちSettingWithCopyの問題を避けるためのプログラミングスタイルです。ありがとう!私は本当にあなたのブログの投稿が好きでした!あなたはスクリーンペイバーから質問に答えることができますか?私はあなたのブログの投稿の提案のほとんどがうまくいくと思いますが、.query()はすべてのケースでコピーを返すようには見えません!だから私はメソッドチェーンでフィルタリングを行うことができますか? – sjk

+0

@screenpaverとskj、私の更新された回答は役に立ちますか? – maxymoo

関連する問題