1412 Stimmen

Erstellen Sie ein Pandas-Datenframe, indem Sie Zeile für Zeile hinzufügen

Wie erstelle ich ein leeres DataFrame und füge dann Zeilen einzeln hinzu?

Ich habe ein leeres DataFrame erstellt:

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

Dann kann ich eine neue Zeile am Ende hinzufügen und ein einzelnes Feld ausfüllen mit:

df = df._set_value(index=len(df), col='qty1', value=10.0)

Das funktioniert nur für ein Feld auf einmal. Gibt es einen besseren Weg, um eine neue Zeile zum df hinzuzufügen?

915voto

fred Punkte 9085

Sie können df.loc[i] verwenden, wobei die Zeile mit dem Index i das im DataFrame angegebene sein wird.

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

806voto

ShikharDua Punkte 8431

Wenn Sie alle Daten für das Datenrahmen im Voraus erhalten können, gibt es einen wesentlich schnelleren Ansatz als das Anhängen an einen Datenrahmen:

  1. Erstellen Sie eine Liste von Wörterbüchern, wobei jedes Wörterbuch einer Eingabedatenzeile entspricht.
  2. Erstellen Sie einen Datenrahmen aus dieser Liste.

Ich hatte eine ähnliche Aufgabe, bei der das Anhängen an einen Datenrahmen zeilenweise 30 Minuten dauerte und das Erstellen eines Datenrahmens aus einer Liste von Wörterbüchern innerhalb von Sekunden abgeschlossen wurde.

rows_list = []
for row in input_rows:

        dict1 = {}
        # Eingangszeile im Wörterbuchformat erhalten
        # Schlüssel = Spaltenname
        dict1.update(blah..) 

        rows_list.append(dict1)

df = pd.DataFrame(rows_list)

457voto

Mikhail_Sam Punkte 9146

Im Falle des Hinzufügens vieler Zeilen zum DataFrame interessiere ich mich für die Leistung. Also habe ich die vier beliebtesten Methoden ausprobiert und ihre Geschwindigkeit überprüft.

Leistung

  1. Verwendung von .append (NPE's Antwort)
  2. Verwendung von .loc (Fred's Antwort)
  3. Verwendung von .loc mit Vorbelegung (FooBar's Antwort)
  4. Verwendung von dict und Erstellen des DataFrame am Ende (ShikharDua's Antwort)

Ausführungszeitergebnisse (in Sekunden):

Ansatz

1000 Zeilen

5000 Zeilen

10 000 Zeilen

.append

0,69

3,39

6,78

.loc ohne Vorbelegung

0,74

3,90

8,35

.loc mit Vorbelegung

0,24

2,58

8,70

dict

0,012

0,046

0,084

Also verwende ich die Addition über das Wörterbuch für mich.


Code:

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('Vergangene Zeit: {:6.3f} Sekunden für {:d} Zeilen'.format(time.perf_counter() - startTime, numOfRows))
print(df1.shape)

# .loc ohne Vorbelegung
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('Vergangene Zeit: {:6.3f} Sekunden für {:d} Zeilen'.format(time.perf_counter() - startTime, numOfRows))
print(df2.shape)

# .loc mit Vorbelegung
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('Vergangene Zeit: {:6.3f} Sekunden für {:d} Zeilen'.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('Vergangene Zeit: {:6.3f} Sekunden für {:d} Zeilen'.format(time.perf_counter() - startTime, numOfRows))
print(df4.shape)

P.S.: Ich glaube, meine Realisierung ist nicht perfekt, und vielleicht gibt es Optimierungen, die vorgenommen werden könnten.

357voto

NPE Punkte 462670

Sie könnten pandas.concat() verwenden. Für Details und Beispiele siehe Zusammenführen, Verbinden und Konkatenieren.

Zum Beispiel:

def append_row(df, row):
    return pd.concat([
                df, 
                pd.DataFrame([row], columns=row.index)]
           ).reset_index(drop=True)

df = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
new_row = pd.Series({'lib':'A', 'qty1':1, 'qty2': 2})

df = append_row(df, new_row)

341voto

cs95 Punkte 325143

NIEMALS ein DataFrame wachsen lassen!

Ja, Leute haben bereits erklärt, dass man NIEMALS ein DataFrame wachsen lassen sollte und dass man seine Daten an eine Liste anhängen und erst am Ende in ein DataFrame umwandeln sollte. Aber verstehen Sie auch warum?

Hier sind die wichtigsten Gründe, entnommen aus meinem Beitrag hier.

  1. Es ist immer günstiger/schneller, Daten an eine Liste anzuhängen und dann in einem Schritt ein DataFrame zu erstellen.
  2. Listen belegen weniger Speicherplatz und sind eine viel leichtgewichtigere Datenstruktur zum Arbeiten, Anhängen und Entfernen.
  3. dtypes werden automatisch für Ihre Daten abgeleitet. Andererseits werden sie automatisch zu object, wenn Sie ein leeres DataFrame aus NaNs erstellen, was schlecht ist.
  4. Ein Index wird automatisch für Sie erstellt, anstatt dass Sie darauf achten müssen, den richtigen Index für die Zeile, die Sie hinzufügen, zuzuweisen.

So häuft man seine Daten auf die richtige Weise an™

data = []
for a, b, c in some_function_that_yields_data():
    data.append([a, b, c])

df = pd.DataFrame(data, columns=['A', 'B', 'C'])

Diese Optionen sind schrecklich

  1. append oder concat in einer Schleife

    append und concat sind an sich nicht schlecht in Isolation. Das Problem beginnt, wenn Sie sie iterativ innerhalb einer Schleife aufrufen - dies führt zu einer quadratischen Speicherauslastung.

    # Erstellt ein leeres DataFrame und fügt hinzu
    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)  
        # Das ist genauso schlecht:
        # df = pd.concat(
        #       [df, pd.Series({'A': i, 'B': b, 'C': c})], 
        #       ignore_index=True)
  2. Leeres DataFrame aus NaNs

    Erstellen Sie niemals ein DataFrame aus NaNs, da die Spalten mit object initialisiert werden (langsamer, nicht vektorisierbarer Typ).

    # Erstellt DataFrame aus NaNs und überschreibt Werte.
    df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
    for a, b, c in some_function_that_yields_data():
        df.loc[len(df)] = [a, b, c]

Der Beweis liegt im Pudding

Das Timing dieser Methoden ist der schnellste Weg zu sehen, wie sehr sie sich in Bezug auf ihren Speicher und ihre Nützlichkeit unterscheiden.

Bildbeschreibung hier eingeben

Benchmarking-Code zur Referenz.


Es sind Beiträge wie dieser, die mich daran erinnern, warum ich Teil dieser Gemeinschaft bin. Die Leute verstehen die Bedeutung, Leuten beizubringen, die richtige Antwort mit dem richtigen Code zu bekommen, nicht die richtige Antwort mit falschem Code. Sie könnten argumentieren, dass es kein Problem ist, loc oder append zu verwenden, wenn Sie nur eine einzelne Zeile zu Ihrem DataFrame hinzufügen. Allerdings wird oft erwartet, dass mehr als nur eine Zeile hinzugefügt wird - oft ist die Anforderung, iterativ eine Zeile in einer Schleife hinzuzufügen, wobei die Daten aus einer Funktion stammen (siehe verwandte Frage). In diesem Fall ist es wichtig zu verstehen, dass es keine gute Idee ist, ein DataFrame iterativ wachsen zu lassen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X