Добавить одну строку в панды DataFrame


872

Я понимаю, что pandas предназначен для загрузки полностью заполненных, DataFrameно мне нужно создать пустой DataFrame, а затем добавить строки, одну за другой . Каков наилучший способ сделать это?

Я успешно создал пустой DataFrame с:

res = DataFrame(columns=('lib', 'qty1', 'qty2'))

Затем я могу добавить новую строку и заполнить поле:

res = res.set_value(len(res), 'qty1', 10.0)

Это работает, но кажется очень странным: - / (не удается добавить строковое значение)

Как я могу добавить новую строку в мой DataFrame (с другим типом столбцов)?


70
Обратите внимание, что это очень неэффективный способ создания большого DataFrame; новые массивы должны быть созданы (копирование существующих данных) при добавлении строки.
— Уэс МакКинни

5
@WesMcKinney: Спасибо, это действительно приятно знать. Быстро ли добавлять столбцы в огромные таблицы?
— максимум

4
Если это слишком неэффективно для вас, вы можете предварительно выделить дополнительную строку и затем обновить ее.
— user1154664

Ответы:


571

Вы можете использовать df.loc[i], где строка с индексом iбудет такой, какой вы указываете ее в кадре данных.

>>> import pandas as pd
>>> from numpy.random import randint

>>> df = pd.DataFrame(columns=['lib', 'qty1', 'qty2'])
>>> for i in range(5):
>>>     df.loc[i] = ['name' + str(i)] + list(randint(10, size=2))

>>> df
     lib qty1 qty2
0  name0    3    3
1  name1    2    4
2  name2    2    8
3  name3    2    1
4  name4    9    6

25
Подумайте о добавлении индекса для предварительного выделения памяти (см. Мой ответ)
— FooBar

34
@MaximG: я настоятельно рекомендую обновление. Текущая версия Pandas - 0.15.0.
— Фред

44
.locссылается на столбец индекса, поэтому, если вы работаете с существующим ранее DataFrame с индексом, который не является непрерывной последовательностью целых чисел, начинающейся с 0 (как в вашем примере), .locперезапишет существующие строки или вставит строки, или создать пробелы в вашем индексе. Более надежным (но не надежным) подходом для добавления существующего df.loc[df.index.max() + 1] = [randint(...кадра данных ненулевой длины будет: или предварительное заполнение индекса, как предложено @FooBar.
— варенье

4
@hobs df.index.max()- это nanкогда DataFrame пуст.
— flow2k

4
@hobs Одно из решений, о котором я подумал, - это использование троичного оператора:df.loc[0 if pd.isnull(df.index.max()) else df.index.max() + 1]
— flow2k

477

В случае, если вы можете получить все данные для фрейма данных заранее, существует гораздо более быстрый подход, чем добавление фрейма данных:

  1. Создайте список словарей, в котором каждый словарь соответствует строке входных данных.
  2. Создайте фрейм данных из этого списка.

У меня была похожая задача, для которой добавление строки данных за строкой занимало 30 минут, а создание кадра данных из списка словарей выполнялось за считанные секунды.

rows_list = []
for row in input_rows:

        dict1 = {}
        # get input row in dictionary format
        # key = col_name
        dict1.update(blah..) 

        rows_list.append(dict1)

df = pd.DataFrame(rows_list)               

48
Я перешел к тому же и в любой ситуации, когда не могу получить все данные заранее. Разница в скорости поражает.
— Fantabolous

47
Копирование из документов pandas: It is worth noting however, that concat (and therefore append) makes a full copy of the data, and that constantly reusing this function can create a significant performance hit. If you need to use the operation over several datasets, use a list comprehension.( pandas.pydata.org/pandas-docs/stable/… )
— thikonom

5
Это прекрасно работает! За исключением случаев, когда я создал фрейм данных, имена столбцов были в неправильном порядке ...
— user5359531

5
@ user5359531 В этом случае вы можете использовать заказанный dict
— ShikharDua

21
@ user5359531 Вы можете вручную указать столбцы, и порядок будет сохранен. pd.DataFrame (row_list, columns = ['C1', 'C2', 'C3']) сделает
— Марчелло Гречи Линс

288

Вы можете использовать pandas.concat()или DataFrame.append(). Подробности и примеры см. В разделе « Объединение, объединение и объединение» .


6
Привет, так каков ответ для методов, использующих append () или concat (). У меня та же проблема, но я все еще пытаюсь ее решить.
— notilas

109
Это правильный ответ, но это не очень хороший ответ (почти только ссылка).
— JWG

5
Я думаю, что ответ @ Фреда является более правильным. Проблема, связанная с этим ответом, заключается в том, что IIUC без необходимости копирует весь DataFrame каждый раз, когда добавляется строка. Использование .locмеханизма, которого можно избежать, особенно если вы осторожны.
— Кен Уильямс,

7
Но если вы хотите использовать DataFrame.append(), вы должны удостовериться, что ваши данные строк - это прежде всего DataFrame, а не список.
— StayFoolish

203

Это было давно, но я столкнулся с той же проблемой. И нашел здесь много интересных ответов. Поэтому я запутался, какой метод использовать.

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

ОБНОВЛЕНО в 2019 году с использованием новых версий пакетов. Также обновляется после комментария @FooBar

СКОРОСТЬ

  1. Использование .append ( ответ NPE )
  2. Использование .loc ( ответ Фреда )
  3. Использование .loc с предварительным распределением (ответ FooBar )
  4. Использование dict и создание DataFrame в конце ( ответ Шихардуа )

Результаты (в секундах):

|------------|-------------|-------------|-------------|
|  Approach  |  1000 rows  |  5000 rows  | 10 000 rows |
|------------|-------------|-------------|-------------|
| .append    |    0.69     |    3.39     |    6.78     |
|------------|-------------|-------------|-------------|
| .loc w/o   |    0.74     |    3.90     |    8.35     |
| prealloc   |             |             |             |
|------------|-------------|-------------|-------------|
| .loc with  |    0.24     |    2.58     |    8.70     |
| prealloc   |             |             |             |
|------------|-------------|-------------|-------------|
|  dict      |    0.012    |   0.046     |   0.084     |
|------------|-------------|-------------|-------------|

Также спасибо @krassowski за полезный комментарий - я обновил код.

Поэтому я использую дополнение через словарь для себя.


Код:

import pandas as pd
import numpy as np
import time

del df1, df2, df3, df4
numOfRows = 1000
# append
startTime = time.perf_counter()
df1 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows-4):
    df1 = df1.append( dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']), ignore_index=True)
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df1.shape)

# .loc w/o prealloc
startTime = time.perf_counter()
df2 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows):
    df2.loc[i]  = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df2.shape)

# .loc with prealloc
df3 = pd.DataFrame(index=np.arange(0, numOfRows), columns=['A', 'B', 'C', 'D', 'E'] )
startTime = time.perf_counter()
for i in range( 1,numOfRows):
    df3.loc[i]  = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df3.shape)

# dict
startTime = time.perf_counter()
row_list = []
for i in range (0,5):
    row_list.append(dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']))
for i in range( 1,numOfRows-4):
    dict1 = dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E'])
    row_list.append(dict1)

df4 = pd.DataFrame(row_list, columns=['A','B','C','D','E'])
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df4.shape)

PS Я считаю, что моя реализация не идеальна, и, возможно, есть некоторая оптимизация.


4
Использование df2.index.max()for .locбез необходимости увеличивает вычислительную сложность. Простое df2.loc[i] = ...сделало бы. Для меня это сократило время с 10 секунд до 8,64 секунд
— Крассовски

Пожалуйста, удалите мое имя из списка, поскольку вы не придерживаетесь моего подхода в своем тесте: вы не распределяете память, предоставляя индекс подходящего размера.
— FooBar

@FooBar Привет! Я рад, что вы как автор увидели мой ответ :) Вы правы, я упустил этот важный момент. Я предпочитаю добавить еще одну строку для моей таблицы результатов, поскольку ваш подход показывает другой результат!
— Mikhail_Sam

@Mikhail_Sam Как бы вы использовали сводную таблицу, чтобы записать ее в файл Excel, используя самый быстрый метод, dict?
— FabioSpaghetti

1
Просто хотел добавить еще один комментарий о том, почему Dict to Pandas DataFrame - лучший способ. В моих экспериментах с набором данных, который имеет несколько различных типов данных в таблице, использование методов добавления Pandas уничтожает типизацию, тогда как использование Dict и только создание DataFrame из него ОДНАЖДЫ, кажется, сохраняет исходные типы данных нетронутыми.
— trumpetlicks

109

Если вы знаете количество записей ex ante, вам следует предварительно выделить место, указав также индекс (взяв пример данных из другого ответа):

import pandas as pd
import numpy as np
# we know we're gonna have 5 rows of data
numberOfRows = 5
# create dataframe
df = pd.DataFrame(index=np.arange(0, numberOfRows), columns=('lib', 'qty1', 'qty2') )

# now fill it up row by row
for x in np.arange(0, numberOfRows):
    #loc or iloc both work here since the index is natural numbers
    df.loc[x] = [np.random.randint(-1,1) for n in range(3)]
In[23]: df
Out[23]: 
   lib  qty1  qty2
0   -1    -1    -1
1    0     0     0
2   -1     0    -1
3    0    -1     0
4   -1     0     0

Сравнение скорости

In[30]: %timeit tryThis() # function wrapper for this answer
In[31]: %timeit tryOther() # function wrapper without index (see, for example, @fred)
1000 loops, best of 3: 1.23 ms per loop
100 loops, best of 3: 2.31 ms per loop

И - как видно из комментариев - при размере 6000 разница в скорости становится еще больше:

Увеличение размера массива (12) и количества строк (500) делает разницу в скорости более заметной: 313 мс против 2,29 с


3
Отличный ответ. Это должно быть нормой, чтобы пространство строк не распределялось постепенно.
— Ely

8
Увеличение размера массива (12) и количества строк (500) делает разницу в скорости более яркой: 313 мс против 2,29 с
— Tickon

80
mycolumns = ['A', 'B']
df = pd.DataFrame(columns=mycolumns)
rows = [[1,2],[3,4],[5,6]]
for row in rows:
    df.loc[len(df)] = row

2
Эта! Я долго искал, и это первый пост, который действительно показывает, как назначать определенные значения строке! Дополнительный вопрос: каков синтаксис для пар столбец-имя / значение? Я предполагаю, что это должно быть что-то, используя диктовку, но я не могу понять это правильно.
— января

3
это неэффективно, поскольку фактически копирует весь DataFrame при его расширении.
— водонепроницаемый

72

Для эффективного добавления см. Как добавить дополнительную строку в фрейм данных pandas и Настройка с расширением .

Добавьте строки loc/ixв несуществующие данные индекса ключа. например:

In [1]: se = pd.Series([1,2,3])

In [2]: se
Out[2]: 
0    1
1    2
2    3
dtype: int64

In [3]: se[5] = 5.

In [4]: se
Out[4]: 
0    1.0
1    2.0
2    3.0
5    5.0
dtype: float64

Или:

In [1]: dfi = pd.DataFrame(np.arange(6).reshape(3,2),
   .....:                 columns=['A','B'])
   .....: 

In [2]: dfi
Out[2]: 
   A  B
0  0  1
1  2  3
2  4  5

In [3]: dfi.loc[:,'C'] = dfi.loc[:,'A']

In [4]: dfi
Out[4]: 
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4
In [5]: dfi.loc[3] = 5

In [6]: dfi
Out[6]: 
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4
3  5  5  5

Пользователи попросили внедрить (добавить новую строку). Здесь мы видим, как добавить строку в определенный индекс или добавить столбец.
— Гильерме Фелипе Рейс

1
любые тесты того, как это работает, по сравнению с методом dict
— PirateApp

это не эффективно, поскольку фактически копирует весь DataFrame.
— водонепроницаемый

66

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

>>> f = pandas.DataFrame(data = {'Animal':['cow','horse'], 'Color':['blue', 'red']})
>>> f
  Animal Color
0    cow  blue
1  horse   red
>>> f.append({'Animal':'mouse', 'Color':'black'}, ignore_index=True)
  Animal  Color
0    cow   blue
1  horse    red
2  mouse  black

37
Вы также можете упомянуть, что f.append(<stuff>)создаете новый объект, а не просто добавляете его к текущему объекту на месте, поэтому, если вы пытаетесь добавить к фрейму данных в сценарии, вам нужно сказатьf = f.append(<stuff>)
— Blairg23

2
Есть ли способ сделать это на месте?
— LOL

@хах нет. см. github.com/pandas-dev/pandas/issues/2801 - базовые массивы не могут быть расширены, поэтому их необходимо скопировать.
— водонепроницаемый

46

Ради пути Pythonic, здесь добавьте мой ответ:

res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
res = res.append([{'qty1':10.0}], ignore_index=True)
print(res.head())

   lib  qty1  qty2
0  NaN  10.0   NaN

27

Вы также можете создать список списков и преобразовать его в фрейм данных -

import pandas as pd

columns = ['i','double','square']
rows = []

for i in range(6):
    row = [i, i*2, i*i]
    rows.append(row)

df = pd.DataFrame(rows, columns=columns)

дающий

    я двойной квадрат
0 0 0 0
1 1 2 1
2 2 4 4
3 3 6 9
4 4 8 16
5 5 10 25

15

Это не ответ на вопрос ОП, а игрушечный пример, иллюстрирующий ответ @ShikharDua, который я нашел очень полезным.

Хотя этот фрагмент тривиален, в реальных данных у меня было 1000 строк и много столбцов, и я хотел иметь возможность группировать по разным столбцам, а затем выполнять приведенную ниже статистику для более чем одного столбца тега. Таким образом, наличие надежного метода построения фрейма данных по одной строке за раз было большим удобством. Спасибо @ShikharDua!

import pandas as pd 

BaseData = pd.DataFrame({ 'Customer' : ['Acme','Mega','Acme','Acme','Mega','Acme'],
                          'Territory'  : ['West','East','South','West','East','South'],
                          'Product'  : ['Econ','Luxe','Econ','Std','Std','Econ']})
BaseData

columns = ['Customer','Num Unique Products', 'List Unique Products']

rows_list=[]
for name, group in BaseData.groupby('Customer'):
    RecordtoAdd={} #initialise an empty dict 
    RecordtoAdd.update({'Customer' : name}) #
    RecordtoAdd.update({'Num Unique Products' : len(pd.unique(group['Product']))})      
    RecordtoAdd.update({'List Unique Products' : pd.unique(group['Product'])})                   

    rows_list.append(RecordtoAdd)

AnalysedData = pd.DataFrame(rows_list)

print('Base Data : \n',BaseData,'\n\n Analysed Data : \n',AnalysedData)

14

Выяснил простой и приятный способ:

>>> df
     A  B  C
one  1  2  3
>>> df.loc["two"] = [4,5,6]
>>> df
     A  B  C
one  1  2  3
two  4  5  6

1
Обратите внимание, что это скопирует весь DataFrame под капот. Базовые массивы не могут быть расширены, поэтому их необходимо скопировать.
— водонепроницаемый

10

Вы можете использовать генератор объекта для создания Dataframe, который будет более эффективным в использовании памяти по списку.

num = 10

# Generator function to generate generator object
def numgen_func(num):
    for i in range(num):
        yield ('name_{}'.format(i), (i*i), (i*i*i))

# Generator expression to generate generator object (Only once data get populated, can not be re used)
numgen_expression = (('name_{}'.format(i), (i*i), (i*i*i)) for i in range(num) )

df = pd.DataFrame(data=numgen_func(num), columns=('lib', 'qty1', 'qty2'))

Чтобы добавить raw в существующий DataFrame, вы можете использовать метод append.

df = df.append([{ 'lib': "name_20", 'qty1': 20, 'qty2': 400  }])

9

Создайте новую запись (фрейм данных) и добавьте в old_data_frame .
передать список значений и имена соответствующих столбцов, чтобы создать новую запись (data_frame)

new_record = pd.DataFrame([[0,'abcd',0,1,123]],columns=['a','b','c','d','e'])

old_data_frame = pd.concat([old_data_frame,new_record])

8

Вот способ добавить / добавить строку в pandas DataFrame

def add_row(df, row):
    df.loc[-1] = row
    df.index = df.index + 1  
    return df.sort_index()

add_row(df, [1,2,3]) 

Может использоваться для вставки / добавления строки в пустые или заполненные панды DataFrame


1
это добавление с индексом в порядке убывания
— Parthiban Rajendran

5

Вместо списка словарей, как в ответе Шикхардуа, мы также можем представить нашу таблицу в виде словаря списков , где каждый список хранит один столбец в порядке строк, если мы заранее знаем наши столбцы. В конце мы создаем наш DataFrame один раз.

Для столбцов c и n строк используется 1 словарь и c списков, а не 1 список и n словарей. В методе списка словарей каждый словарь хранит все ключи и требует создания нового словаря для каждой строки. Здесь мы только добавляем к спискам, что является постоянным временем и теоретически очень быстро.

# current data
data = {"Animal":["cow", "horse"], "Color":["blue", "red"]}

# adding a new row (be careful to ensure every column gets another value)
data["Animal"].append("mouse")
data["Color"].append("black")

# at the end, construct our DataFrame
df = pd.DataFrame(data)
#   Animal  Color
# 0    cow   blue
# 1  horse    red
# 2  mouse  black

5

если вы хотите добавить строку в конце, добавьте его в список

valuestoappend = [va1,val2,val3]
res = res.append(pd.Series(valuestoappend,index = ['lib', 'qty1', 'qty2']),ignore_index = True)

4

Другой способ сделать это (вероятно, не очень производительный):

# add a row
def add_row(df, row):
    colnames = list(df.columns)
    ncol = len(colnames)
    assert ncol == len(row), "Length of row must be the same as width of DataFrame: %s" % row
    return df.append(pd.DataFrame([row], columns=colnames))

Вы также можете улучшить класс DataFrame следующим образом:

import pandas as pd
def add_row(self, row):
    self.loc[len(self.index)] = row
pd.DataFrame.add_row = add_row

2

Все, что вам нужно, это loc[df.shape[0]]илиloc[len(df)]


# Assuming your df has 4 columns (str, int, str, bool)
df.loc[df.shape[0]] = ['col1Value', 100, 'col3Value', False] 

или

df.loc[len(df)] = ['col1Value', 100, 'col3Value', False] 

1

Сделай это проще. Принимая список в качестве входных данных, который будет добавлен как строка в фрейме данных: -

import pandas as pd  
res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))  
for i in range(5):  
    res_list = list(map(int, input().split()))  
    res = res.append(pd.Series(res_list,index=['lib','qty1','qty2']), ignore_index=True)

0

Мы часто видим конструкцию, df.loc[subscript] = …присваиваемую одной строке DataFrame. Mikhail_Sam опубликовал тесты, содержащие, помимо прочего, эту конструкцию, а также метод, использующий dict и, в конце, создающий DataFrame . Он нашел последний самый быстрый на сегодняшний день. Но если мы заменим df3.loc[i] = …(с предварительно выделенным DataFrame) в его коде на df3.values[i] = …, результат значительно изменится, так как этот метод будет работать аналогично тому, который использует dict. Поэтому мы должны чаще принимать во внимание использование df.values[subscript] = …. Тем не менее, обратите внимание, что .valuesтребуется нулевой индекс, который может отличаться от DataFrame.index.


пример кода это было бы полезно
— baxx

1
@baxx - один пример кода находится в ссылке на бенчмаркинг ( # .loc with prealloc), другой пример в вопросе. Мне нужно сравнить данные из каждой строки в Pandas DataFrame с данными из остальных строк, есть ли способ ускорить вычисления ? и его принятый ответ.
— Armali

0

pandas.DataFrame.append

DataFrame.append (self, other, ignore_index = False, verify_integrity = False, sort = False) → 'DataFrame'

df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
df.append(df2)

Если для ignore_index установлено значение True:

df.append(df2, ignore_index=True)

0

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

df2=df.to_dict()
values=["s_101","hyderabad",10,20,16,13,15,12,12,13,25,26,25,27,"good","bad"] #this is total row that we are going to add
i=0
for x in df.columns:   #here df.columns gives us the main dictionary key
    df2[x][101]=values[i]   #here the 101 is our index number it is also key of sub dictionary
    i+=1

0

Вы можете объединить два DataFrames для этого. Я в основном сталкивался с этой проблемой, чтобы добавить новую строку в существующий DataFrame с индексом символов (не числовым). Итак, я ввожу данные для новой строки в duct () и индекс в списке.

new_dict = {put input for new row here}
new_list = [put your index here]

new_df = pd.DataFrame(data=new_dict, index=new_list)

df = pd.concat([existing_df, new_df])

-1

Это позаботится о добавлении элемента в пустой DataFrame. Проблема в том, что df.index.max() == nanдля первого индекса:

df = pd.DataFrame(columns=['timeMS', 'accelX', 'accelY', 'accelZ', 'gyroX', 'gyroY', 'gyroZ'])

df.loc[0 if math.isnan(df.index.max()) else df.index.max() + 1] = [x for x in range(7)]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.