1. ホーム
  2. python

[解決済み] python pandas dataframe, pass-by-value or pass-by-reference?

2022-08-18 13:17:14

質問

関数にデータフレームを渡し、関数内で修正する場合、値渡しなのか、参照渡しなのか、どちらでしょうか?

次のコードを実行します。

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
def letgo(df):
    df = df.drop('b',axis=1)
letgo(a)

の値は a の値は関数呼び出しの後でも変わりません。パスバイバリューということでしょうか?

また、以下を試してみました。

xx = np.array([[1,2], [3,4]])
def letgo2(x):
    x[1,1] = 100
def letgo3(x):
    x = np.array([[3,3],[3,3]])

その結果 letgo2() は変更されます。 xxletgo3() がない。なぜこのようになるのでしょうか?

どのように解決するのですか?

簡単に言うと、Pythonは常に値渡しですが、Pythonの変数はすべて実際にはあるオブジェクトへのポインタなので、時々参照渡しのように見えることがあります。

Pythonではすべてのオブジェクトはmutableかnon-mutableのどちらかです。例えば、リスト、ディクショナリー、モジュール、Pandasデータフレームはmutableで、ints、string、tupleはnon-mutableです。Mutableなオブジェクトは内部で変更することができますが(例えば、リストに要素を追加する)、Non-Mutableなオブジェクトは変更することができません。

冒頭で述べたように、Pythonの変数はすべてオブジェクトへのポインタと考えることができます。変数を関数に渡すと、関数内の変数(ポインタ)は常に渡された変数(ポインタ)のコピーになります。つまり、内部変数に何か新しいものを代入しても、やっていることはローカル変数が別のオブジェクトを指すように変更するだけです。これは、変数が指していた元のオブジェクトを変更(変異)するわけではなく、外部変数が新しいオブジェクトを指すようになるわけでもありません。この時点では、外部変数はまだ元のオブジェクトを指していますが、内部変数は新しいオブジェクトを指しているのです。

元のオブジェクトを変更したい場合(Mutableデータ型でのみ可能)、オブジェクトを変更するようなことをしなければなりません。 を使わずに でオブジェクトを変更するようなことをしなければなりません。このため letgo()letgo3() は外部項目を変更しないままですが letgo2() はそれを変更します。

ursan が指摘するように、もし letgo() がこのようなものを使っていた場合、元のオブジェクトを変更(変異)してしまい df が指す元のオブジェクトを変更(変異)し、 それによってグローバルな a 変数で見られる値を変更することになります。

def letgo(df):
    df.drop('b', axis=1, inplace=True)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo(a)  # will alter a

場合によっては、実際に直接代入を行わなくても、元の変数を完全にくりぬいて、新しいデータで埋め合わせることができます。 v が指す元のオブジェクトを変更し、それによって v を使用したときに表示されるデータが変わります。

def letgo3(x):
    x[:] = np.array([[3,3],[3,3]])

v = np.empty((2, 2))
letgo3(v)   # will alter v

に直接何かを代入していないことに注意してください。 x の内部範囲全体に何かを割り当てていることに注意してください。 x .

どうしても完全に新しいオブジェクトを作成して外部から見えるようにしなければならない場合(pandasで時々あることです)、2つのオプションがあります。クリーン」なオプションは、例えば新しいオブジェクトを返すだけです。

def letgo(df):
    df = df.drop('b',axis=1)
    return df

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

もう一つの方法は、関数の外に出て、グローバル変数を直接変更することです。これは a を新しいオブジェクトに変更し、そのオブジェクトを参照するすべての関数は a を参照するすべての関数はその新しいオブジェクトを見ることになります。

def letgo():
    global a
    a = a.drop('b',axis=1)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo()   # will alter a!

グローバル変数を直接変更することは、通常は悪い考えです。なぜなら、あなたのコードを読む人は、どのように a がどのように変更されたかを理解するのが難しいからです。(私は一般的に、スクリプト内の多くの関数で使用される共有パラメータにグローバル変数を使用しますが、それらのグローバル変数を変更させないようにします)。