Aggiungi una riga a Panda DataFrame


871

Capisco che Panda è progettato per caricare completamente popolato DataFramema ho bisogno di creare un DataFrame vuoto quindi aggiungere righe, una per una . Qual è il modo migliore per farlo?

Ho creato correttamente un DataFrame vuoto con:

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

Quindi posso aggiungere una nuova riga e riempire un campo con:

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

Funziona ma sembra molto strano: - / (non riesce ad aggiungere valore stringa)

Come posso aggiungere una nuova riga al mio DataFrame (con diversi tipi di colonne)?


70
Nota che questo è un modo molto inefficiente per costruire un DataFrame di grandi dimensioni; nuovi array devono essere creati (copiando i dati esistenti) quando si aggiunge una riga.
Wes McKinney,

5
@WesMcKinney: Grazie, è davvero bello saperlo. È molto veloce aggiungere colonne a tabelle enormi?
massimo

4
Se è troppo inefficiente per te, puoi preallocare una riga aggiuntiva e quindi aggiornarla.
user1154664,

Risposte:


571

È possibile utilizzare df.loc[i], dove la riga con indice isarà quella specificata per essere nel frame di dati.

>>> 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
Considera di aggiungere l'indice per preallocare la memoria (vedi la mia risposta)
FooBar,

34
@MaximG: consiglio vivamente un aggiornamento. La versione attuale di Pandas è 0.15.0.
fred,

44
.locfa riferimento alla colonna dell'indice, quindi se stai lavorando con un DataFrame preesistente con un indice che non è una sequenza continua di numeri interi che iniziano con 0 (come nell'esempio), .locsovrascriveranno le righe esistenti o inseriranno righe oppure creare lacune nel tuo indice. Un approccio più solido (ma non infallibile) per aggiungere un frame di dati di lunghezza diversa da zero sarebbe: df.loc[df.index.max() + 1] = [randint(...o prepopolare l'indice come suggerito da @FooBar.
Piani cottura

4
@hobs df.index.max()è nanquando DataFrame è vuoto.
flow2k

4
@hobs Una soluzione a cui ho pensato è usare l'operatore ternario:df.loc[0 if pd.isnull(df.index.max()) else df.index.max() + 1]
flow2k

475

Nel caso in cui sia possibile ottenere tutti i dati per il frame di dati in anticipo, esiste un approccio molto più veloce rispetto all'aggiunta a un frame di dati:

  1. Creare un elenco di dizionari in cui ciascun dizionario corrisponde a una riga di dati di input.
  2. Crea un frame di dati da questo elenco.

Avevo un compito simile per cui l'aggiunta di un frame di dati riga per riga ha richiesto 30 minuti e la creazione di un frame di dati da un elenco di dizionari completato in pochi secondi.

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
Sono passato a farlo anche per qualsiasi situazione in cui non riesco a ottenere tutti i dati in anticipo. La differenza di velocità è sorprendente.
fantabolous,

47
Copia da pandas docs: 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
Funziona benissimo! Tranne quando ho creato il frame di dati, i nomi delle colonne erano tutti nell'ordine sbagliato ...
user5359531

5
@ user5359531 In questo caso puoi usare il dict ordinato
ShikharDua,

21
@ user5359531 È possibile specificare manualmente le colonne e l'ordine verrà conservato. pd.DataFrame (rows_list, colonne = ['C1', 'C2', 'C3']) farà il trucco
Marcello Grechi Lins

288

Puoi usare pandas.concat()o DataFrame.append(). Per dettagli ed esempi, vedere Unisci, unisci e concatena .


6
Ciao, quindi qual è la risposta per i metodi usando append () o concat (). Ho lo stesso problema, ma sto ancora cercando di capirlo.
notilas

109
Questa è la risposta giusta, ma non è un'ottima risposta (quasi solo link).
jwg

5
Penso che la risposta di @ fred sia più corretta. IIUC il problema con questa risposta è che copia inutilmente l'intero DataFrame ogni volta che viene aggiunta una riga. Usando il .locmeccanismo che può essere evitato, specialmente se stai attento.
Ken Williams,

7
Ma se si desidera utilizzare DataFrame.append(), è necessario assicurarsi che i dati della riga siano anche DataFrame, in primo luogo, non un elenco.
StayFoolish

202

È passato molto tempo, ma ho dovuto affrontare anche lo stesso problema. E ho trovato qui molte risposte interessanti. Quindi ero confuso quale metodo usare.

Nel caso di aggiungere molte righe al frame di dati, sono interessato alle prestazioni di velocità . Quindi ho provato 4 metodi più popolari e ho verificato la loro velocità.

AGGIORNATO NEL 2019 utilizzando nuove versioni di pacchetti. Aggiornato anche dopo il commento @FooBar

PRESTAZIONI DI VELOCITÀ

  1. Utilizzo di .append ( risposta di NPE )
  2. Usare .loc ( la risposta di fred )
  3. Usare .loc con preallocazione ( la risposta di FooBar )
  4. Utilizzando dict e creare DataFrame alla fine ( la risposta di ShikharDua )

Risultati (in secondi):

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

Anche grazie a @krassowski per un commento utile - ho aggiornato il codice.

Quindi uso l'aggiunta tramite il dizionario per me stesso.


Codice:

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 Credo che la mia realizzazione non sia perfetta e forse c'è qualche ottimizzazione.


4
L'uso di df2.index.max()per .locaumenta inutilmente la complessità computazionale. Semplice df2.loc[i] = ...lo farebbe. Per me ha ridotto il tempo da 10 a 8,64 secondi
Krassowski il

Rimuovi il mio nome dall'elenco, poiché non segui il mio approccio nel test: non stai preallocando la memoria fornendo un indice di dimensioni adeguate.
FooBar,

@FooBar Hi! Mi fa piacere che l'autore abbia visto la mia risposta :) hai ragione, ho perso questo punto importante. Preferisco aggiungere un'altra riga per la mia tabella dei risultati poiché il tuo approccio mostra il diverso risultato!
Mikhail_Sam

@Mikhail_Sam Come useresti pivot-table per scriverlo su un file Excel usando il metodo più veloce, dict?
Fabio Spaghetti

1
Volevo solo lanciare un altro commento sul perché il Dict to Pandas DataFrame è un modo migliore. Nella mia sperimentazione con un set di dati che ha diversi tipi di dati nella tabella, l'uso dei metodi di append di Pandas distrugge la digitazione, mentre l'uso di un Dict e la creazione del DataFrame da esso UNA VOLTA sembra mantenere intatti i tipi di dati originali.
trumpetlicks,

109

Se conosci il numero di voci ex ante, dovresti preallocare lo spazio fornendo anche l'indice (prendendo l'esempio di dati da una risposta diversa):

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

Confronto di velocità

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

E - come dai commenti - con una dimensione di 6000, la differenza di velocità diventa ancora più grande:

Aumentare le dimensioni dell'array (12) e il numero di righe (500) rende la differenza di velocità più evidente: 313ms contro 2,29s


3
Bella risposta. Questa dovrebbe essere la norma in modo che lo spazio delle righe non debba essere allocato in modo incrementale.
Ely,

8
Aumentare le dimensioni dell'array (12) e il numero di righe (500) rende più evidente la differenza di velocità: 313ms contro 2.29s
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
Questo! Sto cercando da un po 'di tempo, e questo è il primo post che mostra davvero come assegnare valori particolari a una riga! Domanda bonus: qual è la sintassi per le coppie nome-colonna / valore? Immagino che debba essere qualcosa che usa un dict, ma non riesco a farlo bene.
jhin

3
questo non è efficiente in quanto copia l'intero DataFrame quando lo estendi.
impermeabile

72

Per aggiungere in modo efficiente, vedere Come aggiungere una riga aggiuntiva a un frame di dati Panda e Impostazione con ingrandimento .

Aggiungere righe attraverso loc/ixil esistenti non dati dell'indice chiave. per esempio :

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

O:

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

Gli utenti hanno chiesto l'attrezzo (aggiungere una nuova riga). Qui vediamo come aggiungere una riga in un indice definito o aggiungere una colonna.
Guilherme Felipe Reis,

1
eventuali parametri di riferimento su come funziona rispetto al metodo dict
PirateApp

questo non è efficiente in quanto copia l'intero DataFrame.
impermeabile

66

Puoi aggiungere una singola riga come dizionario usando l' ignore_indexopzione.

>>> 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
Potresti anche menzionare che f.append(<stuff>)crea un nuovo oggetto, piuttosto che semplicemente aggiungere l'oggetto corrente in atto, quindi se stai provando ad aggiungere a un frame di dati in uno script, devi diref = f.append(<stuff>)
Blairg23,

2
c'è un modo per farlo sul posto?
lol

@LOL no. vedi github.com/pandas-dev/pandas/issues/2801 - gli array sottostanti non possono essere estesi, quindi devono essere copiati.
impermeabile

46

Per motivi di Pythonic, qui aggiungi la mia risposta:

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

Puoi anche creare un elenco di elenchi e convertirlo in un frame di dati -

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)

dando

    io doppio quadrato
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

Questa non è una risposta alla domanda OP ma un esempio di giocattolo per illustrare la risposta di @ShikharDua sopra la quale ho trovato molto utile.

Mentre questo frammento è banale, nei dati effettivi avevo migliaia di righe e molte colonne e volevo essere in grado di raggruppare per colonne diverse e quindi eseguire le statistiche di seguito per più di una colonna di taget. Quindi avere un metodo affidabile per costruire il frame di dati una riga alla volta è stata una grande comodità. Grazie @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

Capito un modo semplice e carino:

>>> 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
Nota che questo copierà l'intero DataFrame sotto il cofano. Gli array sottostanti non possono essere estesi, quindi devono essere copiati.
impermeabile

10

È possibile utilizzare l'oggetto generatore per creare Dataframe, che sarà più efficiente in termini di memoria sull'elenco.

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

Per aggiungere raw a DataFrame esistente è possibile utilizzare il metodo append.

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

9

Crea un nuovo record (frame di dati) e aggiungi a old_data_frame .
passa l'elenco di valori e i nomi delle colonne corrispondenti per creare un 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

Ecco il modo di aggiungere / aggiungere una riga 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]) 

Può essere usato per inserire / aggiungere una riga in DataFrame di panda vuoti o popolati


1
questo si aggiunge con l'indice in ordine decrescente
Parthiban Rajendran,

5

Invece di un elenco di dizionari come nella risposta di ShikharDua, possiamo anche rappresentare la nostra tabella come un dizionario di elenchi , in cui ogni elenco memorizza una colonna in ordine di riga, dato che conosciamo in anticipo le nostre colonne. Alla fine costruiamo il nostro DataFrame una volta.

Per le colonne c e n righe, utilizza 1 dizionario e elenchi c , contro 1 elenco e n dizionari. L'elenco dei metodi dei dizionari ha ogni dizionario che memorizza tutte le chiavi e richiede la creazione di un nuovo dizionario per ogni riga. Qui aggiungiamo solo alle liste, che è tempo costante e teoricamente molto veloce.

# 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

se si desidera aggiungere una riga alla fine, aggiungerla come elenco

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

4

Un altro modo per farlo (probabilmente non molto performante):

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

Puoi anche migliorare la classe DataFrame in questo modo:

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

2

Tutto ciò che serve è loc[df.shape[0]]oloc[len(df)]


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

o

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

1

Falla semplice. Prendendo l'elenco come input che verrà aggiunto come riga nel frame di dati: -

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

Spesso vediamo il costrutto df.loc[subscript] = …da assegnare a una riga DataFrame. Mikhail_Sam ha pubblicato benchmark contenenti, tra gli altri, questo costrutto e il metodo che utilizza dict e crea DataFrame alla fine . Trovò che quest'ultimo era di gran lunga il più veloce. Ma se sostituiamo il df3.loc[i] = …(con DataFrame preallocato) nel suo codice df3.values[i] = …, il risultato cambia in modo significativo, in quanto quel metodo funziona in modo simile a quello che usa dict. Quindi dovremmo considerare più spesso l'uso di df.values[subscript] = …. Si noti tuttavia che .valuesaccetta un pedice in base zero, che può essere diverso da DataFrame.index.


un esempio di codice sarebbe utile
baxx il

1
@baxx - Un esempio di codice è al link benchmarks ( # .loc with prealloc), un altro esempio è nella domanda che devo confrontare i dati di ogni riga di un Pandas DataFrame con i dati del resto delle righe, c'è un modo per accelerare il calcolo ? e la sua risposta accettata.
Armali

0

pandas.DataFrame.append

DataFrame.append (self, other, ignore_index = False, confirm_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)

Con ignore_index impostato su True:

df.append(df2, ignore_index=True)

0

prima di aggiungere una riga, dobbiamo convertire il frame di dati in dizionario in cui è possibile visualizzare le chiavi come colonne nel frame di dati e i valori delle colonne vengono nuovamente memorizzati nel dizionario, ma la chiave per ogni colonna è il numero di indice nel frame di dati. Quell'idea mi fa scrivere il codice qui sotto.

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

Per questo puoi concatenare due DataFrame. Fondamentalmente mi sono imbattuto in questo problema per aggiungere una nuova riga a un DataFrame esistente con un indice di caratteri (non numerico). Quindi, inserisco i dati per una nuova riga in un condotto () e indicizzo in un elenco.

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

Ciò si occuperà di aggiungere un elemento a un DataFrame vuoto. Il problema è che df.index.max() == nanper il primo indice:

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)]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.