The Right Way ™ per creare un DataFrame
TLDR; (basta leggere il testo in grassetto)
La maggior parte delle risposte qui ti dirà come creare un DataFrame vuoto e compilarlo, ma nessuno ti dirà che è una brutta cosa da fare.
Ecco il mio consiglio: attendi fino a quando non sei sicuro di avere tutti i dati di cui hai bisogno per lavorare. Utilizzare un elenco per raccogliere i dati, quindi inizializzare un DataFrame quando si è pronti.
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
È sempre più economico aggiungere a un elenco e creare un DataFrame in una volta, piuttosto che creare un DataFrame vuoto (o uno dei NaN) e aggiungerlo più e più volte. Gli elenchi occupano anche meno memoria e sono una struttura di dati molto più leggera con cui lavorare , aggiungere e rimuovere (se necessario).
L'altro vantaggio di questo metodo è dtypesautomaticamente dedotto (piuttosto che assegnarlo objecta tutti).
L'ultimo vantaggio è che a RangeIndexviene creato automaticamente per i tuoi dati , quindi è una cosa in meno di cui preoccuparsi (dai un'occhiata ai metodi poveri appende di locseguito, vedrai elementi in entrambi che richiedono una gestione appropriata dell'indice).
Cose che NON dovresti fare
appendo concatall'interno di un ciclo
Ecco l'errore più grande che ho visto dai principianti:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
# or similarly,
# df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)
La memoria viene ri-assegnato per ogni appendo concatoperazioni che avete. Abbina questo ad un loop e avrai un'operazione di complessità quadratica . Dalla df.appendpagina del documento :
L'aggiunta facoltativa di righe a un DataFrame può essere più intensiva dal punto di vista computazionale rispetto a un singolo concatenato. Una soluzione migliore è aggiungere quelle righe a un elenco e quindi concatenare l'elenco con il DataFrame originale tutto in una volta.
L'altro errore associato df.appendè che gli utenti tendono a dimenticare che append non è una funzione sul posto , quindi il risultato deve essere assegnato nuovamente. Devi anche preoccuparti dei tipi:
df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypes
A object # yuck!
B float64
C object
dtype: object
Trattare con le colonne di oggetti non è mai una buona cosa, perché i panda non possono vettorializzare le operazioni su quelle colonne. Dovrai farlo per risolverlo:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc all'interno di un ciclo
Ho anche visto locusato per aggiungere a un DataFrame che è stato creato vuoto:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
Come in precedenza, non è stata pre-allocata la quantità di memoria necessaria ogni volta, quindi la memoria viene ricresciuta ogni volta che si crea una nuova riga . È altrettanto brutto appende persino più brutto.
DataFrame vuoto di NaNs
E poi, sta creando un DataFrame di NaN e tutte le avvertenze ad esso associate.
df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
A B C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
Crea un DataFrame di colonne di oggetti, come gli altri.
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
L'aggiunta ha ancora tutti i problemi come i metodi sopra.
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
La prova è nel budino
Il tempismo di questi metodi è il modo più veloce per vedere quanto differiscono in termini di memoria e utilità.

Codice di riferimento per riferimento.