webdevqa.jp.net

PandasでSettingWithCopyWarningを処理するにはどうすればいいですか?

バックグラウンド

Pandasを0.11から0.13.0rc1にアップグレードしました。今、アプリケーションは多くの新しい警告を出しています。そのうちの一つはこのように:

E:\FinReporter\FM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
  quote_df['TVol']   = quote_df['TVol']/TVOL_SCALE

それが正確に何を意味するのか知りたいですか?何か変更する必要がありますか?

quote_df['TVol'] = quote_df['TVol']/TVOL_SCALEを使用することを主張した場合、警告をどのように中断すればよいですか?

エラーを与える関数

def _decode_stock_quote(list_of_150_stk_str):
    """decode the webpage and return dataframe"""

    from cStringIO import StringIO

    str_of_all = "".join(list_of_150_stk_str)

    quote_df = pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
    quote_df.rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
    quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]
    quote_df['TClose'] = quote_df['TPrice']
    quote_df['RT']     = 100 * (quote_df['TPrice']/quote_df['TPCLOSE'] - 1)
    quote_df['TVol']   = quote_df['TVol']/TVOL_SCALE
    quote_df['TAmt']   = quote_df['TAmt']/TAMT_SCALE
    quote_df['STK_ID'] = quote_df['STK'].str.slice(13,19)
    quote_df['STK_Name'] = quote_df['STK'].str.slice(21,30)#.decode('gb2312')
    quote_df['TDate']  = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])

    return quote_df

その他のエラーメッセージ

E:\FinReporter\FM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
  quote_df['TVol']   = quote_df['TVol']/TVOL_SCALE
E:\FinReporter\FM_EXT.py:450: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
  quote_df['TAmt']   = quote_df['TAmt']/TAMT_SCALE
E:\FinReporter\FM_EXT.py:453: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
  quote_df['TDate']  = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])
432
bigbug

SettingWithCopyWarningは、次のように、特に最初の選択が copy を返すときに常に期待通りに動作するとは限らない、潜在的に混乱を招く「連鎖」割り当てを示すために作成されました。 [背景説明については GH5390GH5597 を参照してください。]

df[df['A'] > 2]['B'] = new_val  # new_val not set in df

この警告は、次のように書き換えることを提案しています。

df.loc[df['A'] > 2, 'B'] = new_val

しかし、これはあなたの用法には合いません。

df = df[df['A'] > 2]
df['B'] = new_val

書き込みを元のフレームに戻すことを気にしなくても構わないことは明らかですが(残念ながら参照を上書きしたため)、このパターンは最初の連鎖割り当ての例と区別できないため、(誤検知)警告になります。さらに読みたい場合は、誤検知の可能性が インデックスに関するドキュメント で対処されています。次の割り当てでこの新しい警告を安全に無効にすることができます。

pd.options.mode.chained_assignment = None  # default='warn'
557
Garrett

一般に、SettingWithCopyWarningのポイントは、ユーザー(および特に新しいユーザー)にmayが元のイメージではなく、コピーに対して操作していることを示すことです。 are false positives(IOWの実行内容がわかっている場合はokになります)。 1つの可能性は、@ Garrettが示唆するように(デフォルトではwarn)警告をオフにすることです。

別のオプションを次に示します。

In [1]: df = DataFrame(np.random.randn(5, 2), columns=list('AB'))

In [2]: dfa = df.ix[:, [1, 0]]

In [3]: dfa.is_copy
Out[3]: True

In [4]: dfa['A'] /= 2
/usr/local/bin/ipython:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
  #!/usr/local/bin/python

is_copyフラグをFalseに設定できます。これにより、チェックが事実上無効になりますそのオブジェクトの場合

In [5]: dfa.is_copy = False

In [6]: dfa['A'] /= 2

明示的にコピーした場合、それ以上の警告は発生しません。

In [7]: dfa = df.ix[:, [1, 0]].copy()

In [8]: dfa['A'] /= 2

OPが上に示しているコードは、正当なものであり、おそらく私もそうしているものですが、技術的にはこの警告のケースであり、誤検知ではありません。 notを警告する別の方法は、reindexを介して選択操作を行うことです。

quote_df = quote_df.reindex(columns=['STK', ...])

または、

quote_df = quote_df.reindex(['STK', ...], axis=1)  # v.0.21
138
Jeff

PandasでSettingWithCopyWarningを処理する方法

この記事は、読者を対象としています。

  1. この警告の意味を理解したい
  2. この警告を抑制するさまざまな方法を理解したい
  3. 将来的にこの警告を回避するために、コードを改善し、優れたプラクティスに従う方法を理解したいと思います。

セットアップ

np.random.seed(0)
df = pd.DataFrame(np.random.choice(10, (3, 5)), columns=list('ABCDE'))
df
   A  B  C  D  E
0  5  0  3  3  7
1  9  3  5  2  4
2  7  6  8  8  1

SettingWithCopyWarningとは何ですか?

この警告にどう対処するかを知るためには、それが何を意味するのか、なぜそもそもなぜそれが上がるのかを理解することが重要です。

DataFrameをフィルタリングするとき、内部レイアウトとさまざまな実装の詳細に応じて、フレームをスライス/インデックスしてviewまたはcopyのいずれかを返すことができます。 「ビュー」とは、その用語が示すように、元のデータへのビューであるため、ビューを変更すると元のオブジェクトが変更される場合があります。一方、「コピー」は元のデータを複製したものであり、コピーを変更しても元のデータには影響しません。

他の回答で述べたように、SettingWithCopyWarningは「連鎖割り当て」操作にフラグを立てるために作成されました。上記の設定でdfを検討してください。列 "A"の値が> 5の場合、列 "B"のすべての値を選択するとします。Pandasでは、これをさまざまな方法で行うことができますが、他の方法よりも正確です。例えば、

df[df.A > 5]['B']

1    3
2    6
Name: B, dtype: int64

そして、

df.loc[df.A > 5, 'B']

1    3
2    6
Name: B, dtype: int64

これらは同じ結果を返すので、これらの値だけを読んでいるのであれば、違いはありません。それで、問題は何ですか?連鎖割り当ての問題は、ビューまたはコピーが返されるかどうかを予測するのが一般に難しいということです。 したがって、値を代入しようとすると、これが主に問題になります。 前の例を基にして、このコードがインタープリタによってどのように実行されるかを考えます。

df.loc[df.A > 5, 'B'] = 4
# becomes
df.__setitem__((df.A > 5, 'B'), 4)

1回の__setitem__呼び出しでdfを呼び出します。 OTOH、このコードを検討してください:

df[df.A > 5]['B'] = 4
# becomes
df.__getitem__(df.A > 5).__setitem__('B", 4)

現在、__getitem__がビューまたはコピーのどちらを返したかによっては、__setitem__操作 が機能しない場合があります .

通常、ラベルベースの代入には loc を、整数ベースの代入には iloc を使用する必要があります。これは、元のコードに対して常に動作することを保証するためです。また、単一セルを設定するには、 at および iat を使用する必要があります。

より多くのことが ドキュメント にあります。


locを使用して行われたすべてのブール索引付け操作は、ilocを使用しても行うことができます。唯一の違いは、ilocは、インデックスには整数/位置、ブール値の配列には整数、位置には列に整数/位置のインデックスが必要であることです。

例えば、

df.loc[df.A > 5, 'B'] = 4

Nasと書くことができます

df.iloc[(df.A > 5).values, 1] = 4

そして、

df.loc[1, 'A'] = 100

と書くことができます

df.iloc[1, 0] = 100

等々。


警告を抑制する方法を教えてください。

dfの "A"列に対する単純な操作を考えてください。 「A」を選択して2で割ると警告が表示されますが、操作は機能します。

df2 = df[['A']]
df2['A'] /= 2
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/IPython/__main__.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

df2
     A
0  2.5
1  4.5
2  3.5

この警告を直接黙らせる方法は2つあります。

  1. deepcopyを作成します

    df2 = df[['A']].copy(deep=True)
    df2['A'] /= 2
    
  2. 変更pd.options.mode.chained_assignment
    None"warn"、または"raise"に設定できます。 "warn"がデフォルトです。 Noneは警告を完全に抑制し、"raise"SettingWithCopyErrorをスローして操作が実行されないようにします。

    pd.options.mode.chained_assignment = None
    df2['A'] /= 2
    

@Peter Cotton コメントでは、コンテキストマネージャを使ってモードを邪魔にならないように変更する( this Gist から変更)という、いい方法を思いついた。終了したら元の状態にリセットします。

class ChainedAssignent:
    def __init__(self, chained=None):
        acceptable = [None, 'warn', 'raise']
        assert chained in acceptable, "chained must be in " + str(acceptable)
        self.swcw = chained

    def __enter__(self):
        self.saved_swcw = pd.options.mode.chained_assignment
        pd.options.mode.chained_assignment = self.swcw
        return self

    def __exit__(self, *args):
        pd.options.mode.chained_assignment = self.saved_swcw

使い方は次のとおりです。

# some code here
with ChainedAssignent():
    df2['A'] /= 2
# more code follows

または、例外を発生させる

with ChainedAssignent(chained='raise'):
    df2['A'] /= 2

SettingWithCopyError: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

「XY問題」:私は何を間違っていますか?

多くの場合、ユーザーはなぜ最初にこの例外が発生したのかを完全に理解することなく、この例外を抑制する方法を探そうとします。これは、 XY問題 の良い例です。ここでは、ユーザーが問題 "Y"を解決しようとしていますが、これは実際にはより根深い問題 "X"の症状です。この警告に遭遇する一般的な問題に基づいて質問が提起され、解決策が提示されます。

質問1
データフレームがあります

df
       A  B  C  D  E
    0  5  0  3  3  7
    1  9  3  5  2  4
    2  7  6  8  8  1

Col "A"> 5〜1000の値を割り当てたいのですが。

      A  B  C  D  E
0     5  0  3  3  7
1  1000  3  5  2  4
2  1000  6  8  8  1

これを行うための間違った方法:

df.A[df.A > 5] = 1000         # works, because df.A returns a view
df[df.A > 5]['A'] = 1000      # does not work
df.loc[df.A  5]['A'] = 1000   # does not work

locを使用した正しい方法:

df.loc[df.A > 5, 'A'] = 1000


質問21
cell(1、 'D')の値を12345に設定しようとしています。期待される出力は

   A  B  C      D  E
0  5  0  3      3  7
1  9  3  5  12345  4
2  7  6  8      8  1

df['D'][1]のように、このセルにアクセスするさまざまな方法を試してみました。これを行うための最良の方法は何ですか?

1.この質問は特に警告に関連するものではありませんが、将来的に警告が発生する可能性がある状況を回避するために、この特定の操作を正しく行う方法を理解しておくことをお勧めします。

これを行うには、以下のいずれかの方法を使用できます。

df.loc[1, 'D'] = 12345
df.iloc[1, 3] = 12345
df.at[1, 'D'] = 12345
df.iat[1, 3] = 12345


質問3
何らかの条件に基づいて値をサブセット化しようとしています。データフレームがあります

   A  B  C  D  E
1  9  3  5  2  4
2  7  6  8  8  1

"C" == 5になるように "D"の値を123に割り当てたいのですが。

df2.loc[df2.C == 5, 'D'] = 123

どちらでも構いませんが、私はstillSettingWithCopyWarningを取得しています。これをどのように修正しますか?

これは実際にはおそらくパイプラインの上位のコードが原因です。 df2は、次のようにもっと大きなものから作成しましたか?

df2 = df[df.A > 5]

?この場合、ブールインデックスはビューを返すので、df2はオリジナルを参照します。 df2copyに代入するだけです。

df2 = df[df.A > 5].copy()
# Or,
# df2 = df.loc[df.A > 5, :]


質問4
列 "C"をからインプレースでドロップしようとしています

   A  B  C  D  E
1  9  3  5  2  4
2  7  6  8  8  1

しかし使用

df2.drop('C', axis=1, inplace=True)

SettingWithCopyWarningをスローします。なんでこんなことが起こっているの?

これは、df2が他のスライス操作からのビューとして作成されている必要があるためです。

df2 = df[df.A > 5]

ここでの解決策は、copy()dfにするか、またはlocを使用することです。

67
cs95

Pandasデータフレームコピー警告

あなたが行ってこのようなことをすると:

quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]

pandas.ix この場合 は、新しいスタンドアロンのデータフレームを返します。

このデータフレームで値を変更しても、元のデータフレームは変更されません。

これはパンダがあなたに警告しようとしていることです。


なぜ.ixは悪い考えです

.ixオブジェクトは複数のことをやろうとします、そしてきれいなコードについて何かを読んだことがある人にとっては、これは強い匂いです。

このデータフレームを考えます。

df = pd.DataFrame({"a": [1,2,3,4], "b": [1,1,2,2]})

ふたつのふるまい

dfcopy = df.ix[:,["a"]]
dfcopy.a.ix[0] = 2

動作1:dfcopyはスタンドアロンのデータフレームになりました。変更してもdfは変わりません

df.ix[0, "a"] = 3

動作2:これは元のデータフレームを変更します。


代わりに.locを使用してください

パンダの開発者たちは.ixオブジェクトは非常に臭い[推測的]であることを認識していたため、データのアクセスと割り当てに役立つ2つの新しいオブジェクトを作成しました。 (もう一方は.iloc

.locは、データのコピーを作成しようとしないため、高速です。

.locは既存のデータフレームをインプレースで修正することを意図しています、そしてそれはよりメモリ効率が良いです。

.locは予測可能で、1つの振る舞いをします。


ソリューション

あなたのコード例でしていることは、たくさんのカラムを持つ大きなファイルをロードし、そしてそれをより小さくなるように修正することです。

pd.read_csv関数はこれの多くを手助けすることができて、またファイルのロードをずっと速くすることができます。

だからこれを行う代わりに

quote_df = pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
quote_df.rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]

これを行う

columns = ['STK', 'TPrice', 'TPCLOSE', 'TOpen', 'THigh', 'TLow', 'TVol', 'TAmt', 'TDate', 'TTime']
df = pd.read_csv(StringIO(str_of_all), sep=',', usecols=[0,3,2,1,4,5,8,9,30,31])
df.columns = columns

これはあなたが興味を持っているカラムを読むだけで、そしてそれらに適切な名前を付けます。邪悪な.ixオブジェクトを使って魔法のようなことをする必要はありません。

34
firelynx

疑問を取り除くために、私の解決策は通常のコピーではなくスライスのディープコピーを作成することでした。これはあなたの状況によっては適用できないかもしれません(メモリの制約/スライスのサイズ、パフォーマンスの低下の可能性 - 特にコピーが私の場合のようにループで行われている場合など)

明確にするために、これは私が受けた警告です。

/opt/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:54:
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation:
http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

スライスのコピーにドロップしていた列が原因で警告がスローされたことに疑問がありました。技術的にはスライスのコピーに値を設定しようとはしていませんが、それでもスライスのコピーを修正したものです。以下は、私が疑いを確認するために取った(単純化された)ステップです。私はそれが警告を理解しようとしている人々の助けになることを願います。

例1:元の列に列をドロップするとコピーに影響する

私たちはすでにそれを知っていましたが、これは健康的な思い出です。これは _ではなく_ /警告の意味です。

>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1

    A   B
0   111 121
1   112 122
2   113 123


>> df2 = df1
>> df2

A   B
0   111 121
1   112 122
2   113 123

# Dropping a column on df1 affects df2
>> df1.drop('A', axis=1, inplace=True)
>> df2
    B
0   121
1   122
2   123

Df2に影響を与えるためにdf1に加えられた変更を避けることは可能です

>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1

A   B
0   111 121
1   112 122
2   113 123

>> import copy
>> df2 = copy.deepcopy(df1)
>> df2
A   B
0   111 121
1   112 122
2   113 123

# Dropping a column on df1 does not affect df2
>> df1.drop('A', axis=1, inplace=True)
>> df2
    A   B
0   111 121
1   112 122
2   113 123

例2:コピー上の列をドロップすると元の列に影響が出る

これは実際に警告を示しています。

>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1

    A   B
0   111 121
1   112 122
2   113 123

>> df2 = df1
>> df2

    A   B
0   111 121
1   112 122
2   113 123

# Dropping a column on df2 can affect df1
# No slice involved here, but I believe the principle remains the same?
# Let me know if not
>> df2.drop('A', axis=1, inplace=True)
>> df1

B
0   121
1   122
2   123

Df1に影響を与えるためにdf2に加えられた変更を避けることは可能です

>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1

    A   B
0   111 121
1   112 122
2   113 123

>> import copy
>> df2 = copy.deepcopy(df1)
>> df2

A   B
0   111 121
1   112 122
2   113 123

>> df2.drop('A', axis=1, inplace=True)
>> df1

A   B
0   111 121
1   112 122
2   113 123

乾杯!

6
Raphvanns

ここで私は直接質問に答えます。対処方法は?

スライスした後に.copy()を作る1

待って、スライスはコピーを返さないのですか?結局のところ、これは警告メッセージが言っているものです?長い答えを読んでください。

import pandas as pd
df = pd.DataFrame({'x':[1,2,3]})
df0 = df[df.x>2]

これは警告を出します。

df0['foo'] = 'bar'

これはしません:

df1 = df[df.x>2].copy()
df1['foo'] = 'bar'

df0df1はどちらもDataFrameオブジェクトですが、パンダが警告を出力することを可能にするものが異なっています。それが何であるか調べましょう。

import inspect
test = df[df.x>2]
test_copy = df[df.x>2].copy()
inspect.getmembers(test)
inspect.getmembers(test_copy)

選択したdiffツールを使用すると、いくつかのアドレス以外に重要な違いは次のとおりです。

|          | test    | test_copy |
| _is_copy | weakref | None      |
| _is_view | True    | False     |

警告するかどうかを決定するメソッドはDataFrame._check_setitem_copyをチェックする_is_copyです。

警告は.locを使用することを示唆していますが、.locというフレームに_is_copyを使用しても、同じ警告が表示されます。誤解を招く?はい。迷惑?あなたは賭けます。役に立ちましたか?連鎖割り当てが使用されている可能性があります。しかし、それはそのケースを識別することさえできず、無差別に警告を表示します。


1 これによりデータのディープコピーが作成されるため、大きなデータフレームや、浅いコピーが必要な場合には、この方法を使用したくないでしょう。警告:データフレームにpythonオブジェクトがある場合、copy.deepcopyとは対照的に参照のみがコピーされます。 doc に詳しい情報があります。

2
user443854

これはうまくいくはずです。

quote_df.loc[:,'TVol'] = quote_df['TVol']/TVOL_SCALE
2
jrouquie

スライスを変数に割り当てていて、次のように変数を使用して設定したい場合は、

df2 = df[df['A'] > 2]
df2['B'] = value

df2の条件計算が長すぎる、またはその他の理由でJeffsのソリューションを使用したくない場合は、以下を使用できます。

df.loc[df2.index.tolist(), 'B'] = value

df2.index.tolist()は、df2のすべてのエントリからインデックスを返します。これは、元のデータフレームの列Bの設定に使用されます。

2
Steohan

このような問題全体を回避することができます、と私は信じています:

return (
    pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
    .rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
    .ix[:,[0,3,2,1,4,5,8,9,30,31]]
    .assign(
        TClose=lambda df: df['TPrice'],
        RT=lambda df: 100 * (df['TPrice']/quote_df['TPCLOSE'] - 1),
        TVol=lambda df: df['TVol']/TVOL_SCALE,
        TAmt=lambda df: df['TAmt']/TAMT_SCALE,
        STK_ID=lambda df: df['STK'].str.slice(13,19),
        STK_Name=lambda df: df['STK'].str.slice(21,30)#.decode('gb2312'),
        TDate=lambda df: df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10]),
    )
)

割り当てを使用します。 ドキュメント :より:新しい列をDataFrameに割り当て、新しい列に加えてすべての元の列を含む新しいオブジェクト(コピー)を返します。

Tom Augspurgerのパンダでのメソッドチェーニングに関する記事を見てください: https://tomaugspurger.github.io/method-chaining

1
hughdbrown

私にとっては、この問題は次のような単純化された例で発生しました。そして私はそれを解決することもできました(うまくいけば正しい解決策で):

警告付きの古いコード:

def update_old_dataframe(old_dataframe, new_dataframe):
    for new_index, new_row in new_dataframe.iterrorws():
        old_dataframe.loc[new_index] = update_row(old_dataframe.loc[new_index], new_row)

def update_row(old_row, new_row):
    for field in [list_of_columns]:
        # line with warning because of chain indexing old_dataframe[new_index][field]
        old_row[field] = new_row[field]  
    return old_row

これはold_row[field] = new_row[field]行の警告を出力しました

Update_rowメソッドの行は実際にはSeries型であるため、この行を次のように置き換えます。

old_row.at[field] = new_row.at[field]

すなわち methodSeriesのアクセス/検索用。どちらにしても両方ともうまく機能し、結果は同じです、このように私は警告を無効にする必要はありません(=他のどこかのチェーンインデックス作成問題のためにそれらを保管してください)。

これが誰かに役立つことを願っています。

1
Petr Szturc

単に警告を抑制したいという人もいるでしょう。

class SupressSettingWithCopyWarning:
    def __enter__(self):
        pd.options.mode.chained_assignment = None

    def __exit__(self, *args):
        pd.options.mode.chained_assignment = 'warn'

with SupressSettingWithCopyWarning():
    #code that produces warning
0
delica

このトピックは本当にPandasと混同されています。幸いなことに、それは比較的単純な解決策を持っています。

問題は、データフィルタリング操作(例えば、loc)がDataFrameのコピーまたはビューを返すかどうかが必ずしも明確ではないということです。したがって、そのようなフィルター処理されたDataFrameをさらに使用すると、混乱を招く可能性があります。

簡単な解決策は、(非常に大きなデータセットを扱う必要がない限り):

値を更新する必要があるときはいつでも、代入前に必ず暗黙的にDataFrameをコピーしてください。

df  # Some DataFrame
df = df.loc[:, 0:2]  # Some filtering (unsure whether a view or copy is returned)
df = df.copy()  # Ensuring a copy is made
df[df["Name"] == "John"] = "Johny"  # Assignment can be done now (no warning)

0
Mikulas

フォロー初心者質問/発言

私のような他の初心者のための説明かもしれません(私はボンネットの下で少し異なって動くように思われるRから来ます)。以下の無害に見える機能的なコードはSettingWithCopy警告を生成し続けました、そして、私は理由を理解することができませんでした。私は「連鎖インデックス」で発行されたものを読んで理解しましたが、私のコードには何も含まれていません:

def plot(pdb, df, title, **kw):
    df['target'] = (df['ogg'] + df['ugg']) / 2
    # ...

しかし、その後、遅すぎて、遅すぎて、plot()関数が呼び出される場所を調べました。

    df = data[data['anz_emw'] > 0]
    pixbuf = plot(pdb, df, title)

そのため "df"はデータフレームではなく、それがデータフレームをインデックス化することによって作成されたことを何らかの形で覚えているオブジェクトです(つまりビューですか?)。

 df['target'] = ...

に相当

 data[data['anz_emw'] > 0]['target'] = ...

これは連鎖インデックスです。私はその通りでしたか?

とにかく、

def plot(pdb, df, title, **kw):
    df.loc[:,'target'] = (df['ogg'] + df['ugg']) / 2

それを修正しました。

0
musbur