Добавить одну строку в панды 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.