Додайте один рядок до панд DataFrame


868

Я розумію, що панди призначені для завантаження повністю заселених, DataFrameале мені потрібно створити порожній DataFrame, а потім додавати рядки, по одному . Який найкращий спосіб зробити це?

Я успішно створив порожній DataFrame з:

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

Тоді я можу додати новий рядок і заповнити поле:

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

Це працює, але здається дуже дивним: - / (не вдається додати значення рядка)

Як я можу додати новий рядок до моєї DataFrame (з різними типами стовпців)?


70
Зауважте, що це дуже неефективний спосіб створити великий DataFrame; під час додавання рядка потрібно створити нові масиви (копіюючи наявні дані).
Уес Маккінні

5
@WesMcKinney: Thx, це дійсно добре знати. Чи дуже швидко додавати стовпчики до величезних таблиць?
макс

4
Якщо це занадто неефективно для вас, ви можете виділити додатковий рядок і потім оновити його.
користувач1154664

Відповіді:


568
>>> 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.
fred

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

474

Якщо ви можете отримати всі дані для фрейму даних заздалегідь, існує набагато швидший підхід, ніж додавання до кадру даних:

  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
Я перейшов до цього, як і для будь-якої ситуації, коли я не можу отримати всі дані наперед. Різниця в швидкості вражає.
фантастичний

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 У цьому випадку ви можете використовувати замовлений
дикт

20
@ user5359531 Ви можете вручну вказати стовпці, і порядок буде збережено. pd.DataFrame (rows_list, columns = ['C1', 'C2', 'C3']) зробить трюк
Marcello Grechi Lins

288

Ви можете використовувати pandas.concat()або DataFrame.append(). Докладніше та приклади див. У розділі Об’єднання, приєднання та об'єднання .


6
Привіт, так що відповідь на методи, які використовують додавання () або concat (). У мене така ж проблема, але все ж намагаюся розібратися в цьому.
notilas

109
Це правильна відповідь, але це не дуже хороша відповідь (майже лише посилання).
jwg

5
Я думаю, що відповідь @ fred правильніша. Проблема IIUC у цій відповіді полягає в тому, що він без необхідності копіює весь DataFrame кожного разу, коли додається рядок. Використання .locмеханізму, якого можна уникнути, особливо якщо ви обережні.
Кен Вільямс

7
Але якщо ви хочете використовувати DataFrame.append(), ви повинні переконатися, що ваші дані рядків також є фреймом DataFrame, а не списком.
StayFoolish

201

Минуло давно, але я зіткнувся і з тією ж проблемою. І знайшов тут багато цікавих відповідей. Тож мене заплутало, який метод використовувати.

У разі додавання багато рядків до фрейму даних я зацікавився швидкістю . Тому я спробував 4 найпопулярніші методи і перевірив їх швидкість.

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

ШВИДКІСТЬ

  1. Використання .append ( відповідь NPE )
  2. Використання .loc ( відповідь Фреда )
  3. Використання .loc з попереднім розміщенням ( відповідь FooBar )
  4. Використання dict та створення DataFrame в кінці кінців ( відповідь ShikharDua )

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

|------------|-------------|-------------|-------------|
|  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()для .locдаремно збільшує обчислювальну складність. Просте df2.loc[i] = ...б зробити. Для мене це скоротило час з 10s до 8.64s
krassowski

Будь ласка, видаліть моє ім’я зі списку, оскільки ви не дотримуєтесь мого підходу у вашому тесті: Ви не попередньо розміщуєте пам’ять, надаючи індекс відповідного розміру.
FooBar

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

@Mikhail_Sam Як би ви скористалися зведеною таблицею, щоб записати її у файл excel, використовуючи найшвидший метод, dict?
FabioSpaghetti

1
Просто хотілося викинути ще один коментар щодо того, чому «Dict to Pandas DataFrame» - кращий спосіб. У моєму експерименті з набором даних, який містить кілька різних типів даних у таблиці, використання методів додавання Pandas знищує введення тексту, тоді як використання Dict і лише створення DataFrame з нього ONCE, здається, зберігають початкові типи даних неушкодженими.
сурми

109

Якщо ви знаєте кількість попередніх записів, вам слід виділити пробіл, також надавши індекс (взявши приклад даних з іншої відповіді):

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 с
Тікон

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

Для ефективного додавання див. Як додати додатковий рядок до фрейму даних панди та Налаштування зі збільшенням .

Додайте рядки до даних 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
будь-які орієнтири щодо того, як це працює в порівнянні з методом
диктату

це не ефективно, оскільки воно фактично копіює весь 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

@lol ні. см github.com/pandas-dev/pandas/issues/2801 - основні масиви не можуть бути розширені таким чином , вони повинні бути скопійовані.
водонепроникний

46

Заради піфонічного способу, тут додайте мою відповідь:

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

26

Ви також можете створити список списків і перетворити його в кадр даних -

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'))

Щоб додати сировину до існуючої DataFrame, ви можете використовувати метод додавання.

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

9

Створіть новий запис (кадр даних) та додайте до old_data_frame .
передати список значень та відповідних назв стовпців для створення new_record (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

Замість списку словників, як у відповіді ShikharDua, ми також можемо представити нашу таблицю як словник списків , де кожен список зберігає один стовпчик у порядку рядків, якщо ми знаємо наші стовпці заздалегідь. Наприкінці ми один раз побудуємо нашу 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

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)

1

Все, що вам потрібно, це 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] 

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 з даними з решти рядків, чи є спосіб пришвидшити обчислення ? і її прийнята відповідь.
Армалі

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)

З ігнором_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 з символьним індексом (не числовим). Отже, я ввожу дані для нового рядка в протоці () та індексую у списку.

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.