2017-02-21 13 views
0

Мой сценарий заключается в том, что функция должна иметь возможность изменять значения внутри pandas.DataFrame. Но я не хочу раскрывать всю функцию DataFrame для функции, а именно части, которые необходимо изменить. Причиной такой прозрачности является то, что функция будет более общей с возможностью указать, какая часть DataFrame должна быть изменена извне. Imaging Я могу написать функцию mult(df_view, a), которая умножает все значения в представлении на a. Обратите внимание: я не хочу создавать новый DataFrame. Изменение стоимости должно быть на месте.Python Pandas: как передать «представления» DataFrames в функцию?

Это моя попытка:

df = pd.DataFrame([[1,1],[1,1]]) 

def mult(df_view, a): 
    df_view *= a 

mult(df.loc[1,1], 2) 

print(df) 

Это (ненужный) выход:

0 1 
0 1 1 
1 1 1 

Ожидаемый результат:

0 1 
0 1 1 
1 1 2 

Обратите внимание, что если мы делаем назначение (т. е. без функции), он работает:

df = pd.DataFrame([[1,1],[1,1]]) 

df.loc[1,1] *= 2 

print(df) 

... дает:

0 1 
0 1 1 
1 1 2 

Таким образом, по-видимому, я Мессинг что-то при переходе через эту точку зрения вызова функции. Я прочитал это blog post from Jeff Knupp, и я думаю, что я понимаю, как работает привязка имени и имени python. Мое понимание DataFrames заключается в том, что когда я вызываю df.loc[1,1], он генерирует прокси-объект, который указывает на исходный DataFrame с окном [1,1], так что дальнейшие операции (например, назначение) передаются только элементам внутри окна. Теперь, когда я передаю этот df.loc[1,1] через вызов функции, функция связывает имя df_view с прокси-объектом. Поэтому в моей теории любое изменение (т. Е. df_view *= a) должно применяться к представлению и, следовательно, к элементам в исходном DataFrame. Из результата ясно, что этого не происходит, и кажется, что DataFrame копируется в процессе (я не уверен, где), потому что некоторые значения были изменены за пределами исходного DataFrame.

ответ

0

Просто проверьте

>>> type(df.loc[1, 1]) 
numpy.int64 

Так, очевидно, что это не будет работать - вы передаете в одной непреложной междунар, который не имеет привязки к внешнему DataFrame.

Вам необходимо было перейти в фактическом виде с простой индексацией (изменчивой конструкцией), это было бы , скорее всего, работа.

>>> mult(df.loc[:, 1], 2) 
>>> df 
    0 1 
0 1 2 
1 1 2 

Но некоторые другие операционные системы не будут работать.

>>> mult(df.loc[:, :1], 2) 
>>> df 
    0 1 
0 1 2 
1 1 2 

В общем, я думаю, что этот поток управления является плохой идеей - лучший вариант будет работать непосредственно по индексу, как вы показали работы. Панда, как правило, более дружелюбна (ИМХО), когда вы придерживаетесь неизменности, когда это возможно.

+0

Данные сверхновые numpy.int64' не означает значение в DataFrame не могут быть назначены к. На самом деле это было сделано в случае 'df.loc [1, 1] * = 2'. Как вы указали, логика того, когда/почему передача «представления» в функцию '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' Это не определенный ответ (хотя и полезный в том смысле, что вы указали некоторые успешные и неудачные случаи). – Roy

+0

@Roy Python проходит по назначению, а когда вы напрямую используете 'df.loc [1, 1] * = 2', вы все равно присваиваете _element_ этого DataFrame, а не фактическое значение, которое передается функции. [Это хорошее чтение] (http://nedbatchelder.com/text/names.html) по этому вопросу. – miradulo

0

Проблема в том, что иногда бывает difficult to detect, копия данных выполнена.

Вы можете обойти трудности при индексации в функции:

def mult(df,i,j,a): 
    df.loc[i,j]*=a 

mult(df,1,1,2) 
mult(df,1,slice(0,2),6) 
print(df) 

для

0 1 
0 1 1 
1 6 12 
+0

Хотя ваше предложение должно работать, это именно то, что мой вопрос пытался избежать (т. Е. Иметь протокол передачи координат представления в функцию, а функция только имеет доступ к указанному разделу DataFrame). Таким образом, я не могу отметить это как ответ. – Roy

Смежные вопросы