Ошибка «Объект DataFrame не имеет атрибута добавления»
Я пытаюсь добавить словарь к объекту DataFrame, но получаю следующую ошибку:
AttributeError: объект «DataFrame» не имеет атрибута «добавление»
Насколько я знаю, в DataFrame есть метод «добавить».
Фрагмент кода:
df = pd.DataFrame(df).append(new_row, ignore_index=True)
я ждал словаряnew_row
будет добавлен как новая строка.
Как я могу это исправить?
4 ответа
Начиная с версии pandas 2.0 (ранее устаревший) был удален .
Вам нужно использовать вместо этого (для большинства приложений):
df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)
Как отметил @cottontail , также можно использовать loc
, хотя это работает только в том случае, если новый индекс еще не присутствует в DataFrame (обычно это происходит, если индекс являетсяRangeIndex
:
df.loc[len(df)] = new_row # only use with a RangeIndex!
Почему его удалили?
Мы часто видим, как новые пользователи pandas пытаются писать код так, как если бы они делали это на чистом Python. Они используют iterrows
для доступа к элементам в цикле (см. здесь , почему этого не следует делать) или способом, аналогичным Python .
Однако, как отмечено в выпуске pandas #35407, pandas и на самом деле не одно и то же . находится на месте, а pandas создает новый DataFrame:
Я думаю, что нам следует исключить Series.append и DataFrame.append. Они проводят аналогию со list.append, но это плохая аналогия, поскольку поведение не является (и не может быть) на месте. Для создания результата необходимо скопировать данные для индекса и значений.
Это также очевидно популярные методы. DataFrame.append занимает примерно 10-е место по посещаемости в нашей документации API.
Если я не ошибаюсь, пользователям всегда лучше создать список значений и передать его конструктору или создать список NDFrames, за которым следует один конкат.
Как следствие, в то время какlist.append
амортизируется O(1) на каждом шаге цикла, pandas' равен
O(n)
, что делает его неэффективным при повторной вставке .
Что делать, если мне нужно повторить процесс?
С использованиемappend
илиconcat
многократно — не очень хорошая идея (это имеет квадратичное поведение, поскольку для каждого шага создается новый DataFrame).
В таком случае новые элементы должны быть собраны в список, а в конце цикла преобразованы в исходные и в конечном итоге объединены с ними.DataFrame
.
lst = []
for new_row in items_generation_logic:
lst.append(new_row)
# create extension
df_extended = pd.DataFrame(lst, columns=['A', 'B', 'C'])
# or columns=df.columns if identical columns
# concatenate to original
out = pd.concat([df, df_extended])
Отказ от ответственности: этот ответ, похоже, пользуется популярностью, но предложенный подход не следует использовать . не был изменен на , является частным внутренним методом и был удален из API панд. Утверждение : «Метод в pandas похож на list.append в Python. Вот почему метод добавления в pandas теперь изменен на ». совершенно неверно. Ведущий_
означает только одно: метод является частным и не предназначен для использования вне внутреннего кода pandas.
В новой версии Pandas метод изменен на . Вы можете просто использовать вместо , т.е.df._append(df2)
.
df = df1._append(df2,ignore_index=True)
Почему оно изменено?
The append
Метод в pandas похож на list.append в Python. Вот почему метод добавления в pandas теперь изменен на_append
.
Если это одна строка , это также может выполнить эту работу.
df.loc[len(df)] = new_row
При вызове кадр данных увеличивается с помощью индексной метки.len(df)
, что имеет смысл только в том случае, если индекс равен ;RangeIndex
создается по умолчанию, если явный индекс не передается конструктору фрейма данных.
Рабочий пример:
df = pd.DataFrame({'A': range(3), 'B': list('abc')})
df.loc[len(df)] = [4, 'd']
df.loc[len(df)] = {'A': 5, 'B': 'e'}
df.loc[len(df)] = pd.Series({'A': 6, 'B': 'f'})
Тем не менее, если вы увеличиваете кадр данных в цикле, используяDataFrame.append
или или рассмотрите возможность переписать свой код, чтобы увеличить список Python и один раз создать кадр данных.
Как отметил @mozway, увеличение кадра данных pandas имеет сложность O(n^2), поскольку на каждой итерации необходимо прочитать и скопировать весь кадр данных. Следующий график показывает разницу во времени выполнения относительно однократной конкатенации. 1 Как видите, оба способа увеличения фрейма данных намного медленнее, чем увеличение списка и однократное создание фрейма данных (например, для фрейма данных с 10 тысячами строкconcat
в цикле примерно в 800 раз медленнее иloc
в цикле примерно в 1600 раз медленнее).
1 Код, используемый для создания графика производительности:
import pandas as pd
import perfplot
def concat_loop(lst):
df = pd.DataFrame(columns=['A', 'B'])
for dic in lst:
df = pd.concat([df, pd.DataFrame([dic])], ignore_index=True)
return df.infer_objects()
def concat_once(lst):
df = pd.DataFrame(columns=['A', 'B'])
df = pd.concat([df, pd.DataFrame(lst)], ignore_index=True)
return df.infer_objects()
def loc_loop(lst):
df = pd.DataFrame(columns=['A', 'B'])
for dic in lst:
df.loc[len(df)] = dic
return df
perfplot.plot(
setup=lambda n: [{'A': i, 'B': 'a'*(i%5+1)} for i in range(n)],
kernels=[concat_loop, concat_once, loc_loop],
labels= ['concat in a loop', 'concat once', 'loc in a loop'],
n_range=[2**k for k in range(16)],
xlabel='Length of dataframe',
title='Enlarging a dataframe in a loop',
relative_to=1,
equality_check=pd.DataFrame.equals);
AttributeError: объект «DataFrame» не имеет атрибута «добавление». Вы имели в виду: '_append'?
Для Pandas с совместимостью TensorFlow 2.12 пользователям просто нужно внести небольшое изменение для успеха.
all_data = train_df.append(test_df)
Измените добавление на _aqppend
all_data = train_df._append(test_df)
И тогда программа сможет работать корректно.