Pandy Pythona: wypełnij ramkę danych wiersz po wierszu

138

Wydaje się, że proste zadanie dodania wiersza do pandas.DataFrameobiektu jest trudne. Istnieją 3 pytania związane z przepełnieniem stosu, z których żadne nie daje roboczej odpowiedzi.

Oto, co próbuję zrobić. Mam DataFrame, której kształt już znam, a także nazwy wierszy i kolumn.

>>> df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])
>>> df
     a    b    c    d
x  NaN  NaN  NaN  NaN
y  NaN  NaN  NaN  NaN
z  NaN  NaN  NaN  NaN

Teraz mam funkcję do iteracyjnego obliczania wartości wierszy. Jak mogę wypełnić jeden z wierszy słownikiem lub pandas.Series? Oto różne próby, które zakończyły się niepowodzeniem:

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df['y'] = y
AssertionError: Length of values does not match length of index

Najwyraźniej próbował dodać kolumnę zamiast wiersza.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.join(y)
AttributeError: 'builtin_function_or_method' object has no attribute 'is_unique'

Bardzo mało informacyjny komunikat o błędzie.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.set_value(index='y', value=y)
TypeError: set_value() takes exactly 4 arguments (3 given)

Najwyraźniej służy to tylko do ustawiania indywidualnych wartości w ramce danych.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.append(y)
Exception: Can only append a Series if ignore_index=True

Cóż, nie chcę ignorować indeksu, w przeciwnym razie oto wynik:

>>> df.append(y, ignore_index=True)
     a    b    c    d
0  NaN  NaN  NaN  NaN
1  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN
3    1    5    2    3

Wyrównał nazwy kolumn z wartościami, ale utracił etykiety wierszy.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.ix['y'] = y
>>> df
                                  a                                 b  \
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

                                  c                                 d
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

To też się nie udało.

Jak więc to robisz?

xApple
źródło

Odpowiedzi:

97

df['y'] ustawi kolumnę

ponieważ chcesz ustawić wiersz, użyj .loc

Zauważ, że .ixjest to równoważne tutaj, twój nie powiódł się, ponieważ próbowałeś przypisać słownik do każdego elementu wiersza, yprawdopodobnie nie to, czego chcesz; konwersja na serię mówi pandom, że chcesz wyrównać dane wejściowe (na przykład nie musisz wtedy określać wszystkich elementów)

In [7]: df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])

In [8]: df.loc['y'] = pandas.Series({'a':1, 'b':5, 'c':2, 'd':3})

In [9]: df
Out[9]: 
     a    b    c    d
x  NaN  NaN  NaN  NaN
y    1    5    2    3
z  NaN  NaN  NaN  NaN
Jeff
źródło
Widzę. Więc locatrybut ramki danych definiuje specjalną, __setitem__która robi magię, jak przypuszczam.
xApple
Czy możesz to skonstruować w jednym przebiegu (tj. Z kolumnami, indeksem i y)?
Andy Hayden
5
Więc jeśli mogę generować jeden wiersz na raz, jak optymalnie skonstruować ramkę danych?
xApple
Spodziewałeś się, że jakiś wariant df = pd.DataFrame({'y': pd.Series(y)}, columns=['a','b','c','d'], index=['x','y','z'])zadziała?
Andy Hayden
@xApple prawdopodobnie najlepiej skonstruujesz listę dykt (lub listę), a następnie po prostu przekazujesz ją do konstruktora, będzie znacznie wydajniejsza
Jeff
73

Moje podejście było takie, ale nie mogę zagwarantować, że jest to najszybsze rozwiązanie.

df = pd.DataFrame(columns=["firstname", "lastname"])
df = df.append({
     "firstname": "John",
     "lastname":  "Johny"
      }, ignore_index=True)
pływ
źródło
4
To zadziałało dla mnie znakomicie i podoba mi się fakt, że appenddane są jawnie przesyłane do ramki danych.
Jonny Brooks
2
Zwróć uwagę, że ta odpowiedź wymaga, aby każdy wiersz miał dołączoną nazwę kolumny. To samo dotyczy zaakceptowanej odpowiedzi.
pashute
Działa to również, jeśli nie znasz wcześniej liczby rzędów.
Irene
34

To jest prostsza wersja

import pandas as pd
df = pd.DataFrame(columns=('col1', 'col2', 'col3'))
for i in range(5):
   df.loc[i] = ['<some value for first>','<some value for second>','<some value for third>']`
Satheesh
źródło
4
chcę tylko zapytać, czy ten procesor i pamięć są wydajne?
czxttkl
1
skąd mam znać ostatni wiersz df, więc za każdym razem doklejam go do ostatniego wiersza?
pashute
27

Jeśli wiersze wejściowe to listy, a nie słowniki, proste rozwiązanie jest następujące:

import pandas as pd
list_of_lists = []
list_of_lists.append([1,2,3])
list_of_lists.append([4,5,6])

pd.DataFrame(list_of_lists, columns=['A', 'B', 'C'])
#    A  B  C
# 0  1  2  3
# 1  4  5  6
stackoverflowuser2010
źródło
ale co mam zrobić, jeśli mam multiindeks? df1 = pd.DataFrame (list_of_lists, kolumny [„A”, „B”, „C”], index = [„A”, „B”]) nie działa. Niewłaściwy kształt. Więc jak?
pashute