Właściwy sposób ™ do utworzenia DataFrame
TLDR; (po prostu przeczytaj pogrubiony tekst)
Większość odpowiedzi tutaj powie ci, jak utworzyć pustą ramkę danych i wypełnić ją, ale nikt nie powie ci, że to źle.
Oto moja rada: poczekaj, aż będziesz mieć pewność, że masz wszystkie dane, z którymi musisz pracować. Użyj listy, aby zebrać swoje dane, a następnie zainicjuj ramkę DataFrame, gdy będziesz gotowy.
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
To jest zawsze tańsze, aby dołączyć do listy i utworzyć DataFrame za jednym razem , niż jest, aby utworzyć pusty DataFrame (lub jedną z Nans) i dołączyć do niej w kółko. Listy zajmują również mniej pamięci i są znacznie lżejszą strukturą danych do pracy , dołączania i usuwania (w razie potrzeby).
Inną zaletą tej metody jest dtypes
automatyczne wnioskowanie (zamiast przypisywania object
ich wszystkim).
Ostatnią zaletą jest to, że jest tworzony automatycznie dla swoich danych , więc jest to jeden mniej rzeczy się martwić (spójrz na biednych i metodach poniżej, widać zarówno elementy, które wymagają obsługi indeksu odpowiednio).RangeIndex
append
loc
Rzeczy, których NIE powinieneś robić
append
lub concat
wewnątrz pętli
Oto największy błąd, jaki widziałem od początkujących:
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)
Pamięć jest przydzielana ponownie dla każdej operacji append
lub concat
operacji. Połącz to z pętlą, a otrzymasz kwadratową operację złożoności . Ze strony df.append
dokumentu :
Iteracyjne dołączanie wierszy do DataFrame może być bardziej wymagające obliczeniowo niż pojedynczy konkatenat. Lepszym rozwiązaniem jest dodanie tych wierszy do listy, a następnie połączenie listy z oryginalną ramką DataFrame jednocześnie.
Innym błędem związanym z df.append
tym jest to, że użytkownicy często zapominają, że append nie jest funkcją lokalną , więc wynik należy przypisać z powrotem. Musisz także martwić się o typy:
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
Radzenie sobie z kolumnami obiektów nigdy nie jest dobrą rzeczą, ponieważ pandy nie mogą wektoryzować operacji na tych kolumnach. Musisz to zrobić, aby to naprawić:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc
wewnątrz pętli
Widziałem również loc
używane do dołączania do DataFrame, który został utworzony pusty:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
Tak jak poprzednio, nie przydzielono wstępnie wymaganej ilości pamięci za każdym razem, więc pamięć jest odnawiana za każdym razem, gdy tworzysz nowy wiersz . Jest tak samo zły, jak append
i jeszcze bardziej brzydki.
Pusta ramka danych dla NaNs
Następnie powstaje ramka danych NaNs i wszystkie związane z tym zastrzeżenia.
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
Tworzy ramkę danych kolumn obiektowych, podobnie jak inne.
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
Dołączanie nadal ma wszystkie problemy, jak powyższe metody.
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
Dowód jest w budyniu
Pomiar tych metod jest najszybszym sposobem, aby zobaczyć, jak bardzo różnią się one pod względem pamięci i użyteczności.
Kod porównawczy w celach informacyjnych.