Добавить DataFrame внутри функции

1

У меня есть функциональный test который принимает DataFrame и добавляет к нему данные. Я хочу, чтобы глобальная переменная, помещенная в функцию, была изменена. У меня есть сценарий ниже:

import pandas as pd
global dff

def test(df):
    df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
    return(df)

dff = pd.DataFrame()
test(dff)

После этого dff остается пустым; он не редактировался. Однако, если вы это сделаете:

import pandas as pd

def test(df):
    df['asdf'] = [1,2,3]
    return(df)

dff = pd.DataFrame()
test(dff)

dff будет иметь [1,2,3] под столбцом 'asfd'. Обратите внимание, что мне даже не пришлось объявлять переменную global.

Почему это происходит?

Я действительно хотел бы знать, потому что второй, я думаю, я понимаю переменные рабочие пространства, я доказал свою несостоятельность, и мне становится надоело постоянно работать в этой BS *

Я знаю, что решение проблемы:

import pandas as pd

def test(df):
    df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
    return(df)

dff = pd.DataFrame()
dff = test(dff)

но я просто пытаюсь понять, почему первоначальный метод не работает, особенно в свете второго сценария, который я показал.

* Очевидно, что это не полная BS, но я не могу понять это после 3 лет случайного программирования

Теги:
pandas
dataframe
function

2 ответа

1
Лучший ответ

Обновить:

Я нашел очень приятный разговор на PyCon 2015, который объясняет, что я пытаюсь объяснить ниже, но с диаграммами, которые делают его значительно яснее. Я оставлю объяснение ниже, чтобы объяснить, как работают оригинальные 3 скрипта, но я бы предложил посмотреть видео:

Ned Batchelder - Факты и мифы о названиях и ценностях Python - PyCon 2015


Итак, я думаю, что я понял, что происходит в двух сценариях выше. Я попробую разбить его. Не стесняйтесь исправить меня, если потребуется.

Несколько правил:

  1. Переменные - это имена ссылок/указателей на базовый объект, который фактически хранит данные. Например, уличные адреса. Улица не является домом; он просто указывает на дом. Таким образом, адрес (101 Streetway Rd.) Является указателем. В GPS вы можете обозначить его как "Главная". Слово "дом" было бы самой переменной.

  2. Функции работают с объектами, а не с переменными или указателями. Когда вы передаете переменную функции, вы фактически передаете объект, а не переменную или указатель. Продолжая пример дома, если вы хотите добавить колоду в дом, вы хотите, чтобы подрядчики настила работали над домом, а не с метафизическим адресом.

  3. Команда return в функции возвращает указатель на объект. Таким образом, это будет адрес дома, а не дом или имя, которое вы могли бы назвать своим домом.

  4. = это функция, означающая "point to this object". Переменная перед = выход, переменная справа - это вход. Это был бы акт названия дома. Итак, Home = 101 Streetway Rd. превращает переменную Home point в дом на 101 Streetway Rd. Скажем, вы переехали в дом ваших соседей, который является 102 Streetway Rd. Это может быть сделано Home = Neighbor House. Теперь Home теперь называется указателем 102 Streetway Rd.

Здесь, я буду использовать ---> для обозначения "указывает на",

Прежде чем мы перейдем к сценариям, начнем с того, что мы хотим. Мы хотим, чтобы объект objdff указывал на varia

Сценарий 1:

(без global dff поскольку это ничего не делает)

import pandas as pd

def test(df):
    df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
    return(df)

dff = pd.DataFrame()
test(dff)

Итак, пройдите через функцию. Ничего интересного не происходит, пока мы не доберемся до:

dff = pd.DataFrame()

Здесь мы имеем varible dff быть назначены на объект, созданный pd.DataFrame, который является пустым dataframe. Мы будем называть этот объект objdff. Итак, в конце этой строки мы имеем dff ---> objdff.

Следующая строка: test(dff)

Функции работы на объектах, поэтому мы говорим, что мы собираемся запустить функцию test на объекте, dff очков, что objdff. Это приводит нас к самой функции.

def test(df):

Здесь мы имеем то, что является по существу = функция. Объект, переданный тестовой функции objdff, указывает на функциональную переменную df. Итак, теперь df --->objdff и dff---> objdff

Перемещение на следующую строку: df = df.append(...)

Начнем с df.append(...). .append(...) передается на objdff. Это заставляет объект objdff запускать функцию, называемую "append". Как отметил @Jai, метод .append(...) использует команду return для вывода абсолютно нового DataFrame, к которому добавлены данные. Мы будем называть новый объект objdff_apnd.

Теперь мы можем перейти на часть df =... Теперь у нас есть df = objdff_apnd. Сейчас это довольно просто. Переменная df теперь указывает на объект objdff_apnd.

В конце этой строки мы имеем df ---> objdff_apnd и df ---> objdff_apnd dff ---> objdff. Здесь и лежит проблема. Объект, который мы хотим (objdff_apnd), не указывает на dff.

Поэтому в конце переменная dff по-прежнему указывает на objdff, а не objdff_apnd. Это приводит нас к сценарию 3 (см. Ниже).

Сценарий 2:

import pandas as pd

def test(df):
    df['asdf'] = [1,2,3]
    return(df)

dff = pd.DataFrame()
test(dff)

Так же, как Script 1, dff ---> objdff. Во время test(dff) переменная функции df ---> objdff. Здесь все по-другому.

Операция (?) df['asdf'] = [1,2,3] снова отправляется в базовый объект objdff. В прошлый раз это привело к созданию нового объекта. Однако на этот раз операция ['asdf'] напрямую редактирует объект objdff. Таким образом, объект objdff имеет дополнительный столбец "asdf".

Поэтому в конце мы имеем df ---> objdff и df ---> objdff dff ---> objdff. Поэтому они указывают на один и тот же объект, что означает, что переменная dff указывает на отредактированный объект.

Как только мы objdff функцию, переменная dff прежнему указывает на objdff, в которой есть новые данные. Это дает нам желаемый результат.

Сценарий 3:

import pandas as pd

def test(df):
    df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
    return(df)

dff = pd.DataFrame()
dff = test(dff)

Этот скрипт точно идентичен сценарию 1, за исключением dff = test(dff). Мы займемся этим через секунду.

Продолжая с конца сценария 1, мы остановились, когда завершился функциональный test(dff), и мы имеем dff ---> objdff и df ---> objdff_apnd.

Функция test имеет return команду, и поэтому возвращает объект objdff_apnd. Это превращает строку dff = test(dff) в dff = objdff_apnd.

Поэтому в конце мы имеем dff ---> objdff_apnd, что является именно тем результатом, который мы хотим.

1
  • Я думаю, что кадры данных pandas, список и словарь все эти типы данных передаются по ссылке на функцию и, следовательно, это поведение.
  • В первом скрипте вы добавляете, который добавляется к целому новому объекту, поскольку append возвращает новый объект, и, следовательно, он не заполняет исходный фреймворк.
  • Во втором скрипте вы назначаете конкретный столбец данных в исходный объект dataframe и, следовательно, заполняете исходный объект DataFrame столбцом, потому что вы изменяете исходный объект
  • вы можете проверить этот ответ: python pandas dataframe, это пропуск по значению или передача по ссылке
  • Проверьте этот пример:

    def test1(a):
        a.append(1)
    
    def test2(a):
        a = [1, 2, 3]
    
    def test3(a):
        a[0] = 10
    
    aa = list()
    test1(aa)
    print(aa)
    
    aa = list()
    test2(aa)
    print(aa)
    
    aa = list([1])
    test3(aa)
    print(aa)
    
  • Выход:

    [1]
    []
    [10]
    
  • Отнесите этот пример выше примера с примером dataframe pandas
  • Если вы проверяете функцию append Dataframe:
    DataFrame.append(other, ignore_index=False, verify_integrity=False, sort=None)[source] Append rows of other to the end of this frame, returning a new object. Columns not in this frame are added as new columns.
  • Как вы можете видеть в описании, что append возвращает новый объект
  • То, как вы используете global ключевое слово не так... Я думаю, что даже если у вас нет global в первом сценарии, все равно это не будет иметь никакого значения... Я не подробности о global ключевом слове, так что я не буду упомянуть что-нибудь об этом. Но я знаю, как использовать ключевое слово, и это определенно не правильный способ его использования

Ещё вопросы

Сообщество Overcoder
Наверх
Меню