Konwertuj listę słowników do ramki danych pandy

Mam listę takich słowników:

[{'points': 50, 'time': '5:00', 'year': 2010}, 
{'points': 25, 'time': '6:00', 'month': "february"}, 
{'points':90, 'time': '9:00', 'month': 'january'}, 
{'points_h1':20, 'month': 'june'}]

A ja chcę zamienić to w pandy DataFrame w ten sposób:

      month  points  points_h1  time  year
0       NaN      50        NaN  5:00  2010
1  february      25        NaN  6:00   NaN
2   january      90        NaN  9:00   NaN
3      june     NaN         20   NaN   NaN

Uwaga: kolejność kolumn nie ma znaczenia.

Jak mogę przekształcić listę słowników w ramkę danych pandy, jak pokazano powyżej?

Author: cs95, 2013-12-17

7 answers

Przypuśćmy, że d to Twoja lista dictów, po prostu:

df = pd.DataFrame(d)

Uwaga: to nie działa z zagnieżdżonymi danymi.

 1150
Author: joris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-22 17:24:12

Jak przekonwertować listę słowników na ramkę danych pandy?

Inne odpowiedzi są poprawne, ale niewiele zostało wyjaśnione pod względem zalet i ograniczeń tych metod. Celem tego postu będzie pokazanie przykładów tych metod w różnych sytuacjach, omówienie, kiedy używać (a kiedy nie używać) i zaproponowanie alternatyw.


DataFrame(), DataFrame.from_records(), oraz .from_dict()

W zależności od struktura i format danych są sytuacje, w których albo wszystkie trzy metody działają, albo niektóre działają lepiej niż inne, albo niektóre nie działają w ogóle.

Rozważ bardzo wymyślny przykład.

np.random.seed(0)
data = pd.DataFrame(
    np.random.choice(10, (3, 4)), columns=list('ABCD')).to_dict('r')

print(data)
[{'A': 5, 'B': 0, 'C': 3, 'D': 3},
 {'A': 7, 'B': 9, 'C': 3, 'D': 5},
 {'A': 2, 'B': 4, 'C': 7, 'D': 6}]

Ta lista składa się z" rekordów " z każdym obecnym kluczem. To najprostszy przypadek, z jakim można się spotkać.

# The following methods all produce the same output.
pd.DataFrame(data)
pd.DataFrame.from_dict(data)
pd.DataFrame.from_records(data)

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6

Słowo w słowniku: orient='index'/'columns'

Przed kontynuacją, ważne jest, aby dokonać rozróżnienia między różnymi typami słownikowe orientacje i wsparcie z pand. Istnieją dwa podstawowe typy: "kolumny" i "indeks".

orient='columns'
Słowniki z orientacją "kolumny" będą miały swoje klucze odpowiadające kolumnom w równoważnej ramce danych.

Na przykład, data powyżej znajduje się w" kolumnach " orient.

data_c = [
 {'A': 5, 'B': 0, 'C': 3, 'D': 3},
 {'A': 7, 'B': 9, 'C': 3, 'D': 5},
 {'A': 2, 'B': 4, 'C': 7, 'D': 6}]
pd.DataFrame.from_dict(data_c, orient='columns')

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6

Uwaga: Jeśli używasz pd.DataFrame.from_records, zakłada się orientację jako "kolumny" (nie można określić inaczej), a słowniki zostaną załadowane odpowiednio.

orient='index'
Przy tym Oriencie przyjmuje się, że klucze odpowiadają wartościom indeksu. Tego rodzaju dane najlepiej nadają się do pd.DataFrame.from_dict.

data_i ={
 0: {'A': 5, 'B': 0, 'C': 3, 'D': 3},
 1: {'A': 7, 'B': 9, 'C': 3, 'D': 5},
 2: {'A': 2, 'B': 4, 'C': 7, 'D': 6}}
pd.DataFrame.from_dict(data_i, orient='index')

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6

Ta sprawa nie jest brana pod uwagę w OP, ale nadal jest przydatna do poznania.

Ustawienie Własnego Indeksu

Jeśli potrzebujesz indeksu na wynikowej ramce danych, możesz go ustawić za pomocą argumentu index=....

pd.DataFrame(data, index=['a', 'b', 'c'])
# pd.DataFrame.from_records(data, index=['a', 'b', 'c'])

   A  B  C  D
a  5  0  3  3
b  7  9  3  5
c  2  4  7  6

To nie jest obsługiwane przez pd.DataFrame.from_dict.

Radzenie sobie z zaginionymi Klucze / Kolumny

Wszystkie metody działają po wyjęciu z pudełka podczas obsługi słowników z brakującymi kluczami/wartościami kolumn. Na przykład,

data2 = [
     {'A': 5, 'C': 3, 'D': 3},
     {'A': 7, 'B': 9, 'F': 5},
     {'B': 4, 'C': 7, 'E': 6}]
# The methods below all produce the same output.
pd.DataFrame(data2)
pd.DataFrame.from_dict(data2)
pd.DataFrame.from_records(data2)

     A    B    C    D    E    F
0  5.0  NaN  3.0  3.0  NaN  NaN
1  7.0  9.0  NaN  NaN  NaN  5.0
2  NaN  4.0  7.0  NaN  6.0  NaN

Odczyt podzbioru kolumn

"co jeśli nie chcę czytać w każdej kolumnie"? Można to łatwo określić za pomocą parametru columns=....

Na przykład, z przykładowego słownika data2 powyżej, jeśli chcesz czytać tylko kolumny "A", " D " i "F", możesz to zrobić, przekazując lista:

pd.DataFrame(data2, columns=['A', 'D', 'F'])
# pd.DataFrame.from_records(data2, columns=['A', 'D', 'F'])

     A    D    F
0  5.0  3.0  NaN
1  7.0  NaN  5.0
2  NaN  NaN  NaN

To nie jest obsługiwane przez {[26] } z domyślnym orient "kolumny".

pd.DataFrame.from_dict(data2, orient='columns', columns=['A', 'B'])
ValueError: cannot use columns parameter with orient='columns'

Odczyt podzbioru wierszy

Nie wspierane przez żadną z tych metodbezpośrednio . W trakcie iteracji należy wykonać odwrotne usunięcie. Na przykład, aby wyodrębnić tylko 0th i 2ND wiersze z data2 powyżej, możesz użyć:

rows_to_select = {0, 2}
for i in reversed(range(len(data2))):
    if i not in rows_to_select:
        del data2[i]

pd.DataFrame(data2)
# pd.DataFrame.from_dict(data2)
# pd.DataFrame.from_records(data2)

     A    B  C    D    E
0  5.0  NaN  3  3.0  NaN
1  NaN  4.0  7  NaN  6.0

Panaceum: json_normalize dla danych zagnieżdżonych

Mocną, solidną alternatywą dla opisanych powyżej metod jest funkcja json_normalize, która działa z listami słowników (rekordów), a ponadto może obsługiwać również słowniki zagnieżdżone.

pd.json_normalize(data)

   A  B  C  D
0  5  0  3  3
1  7  9  3  5
2  2  4  7  6
pd.json_normalize(data2)

     A    B  C    D    E
0  5.0  NaN  3  3.0  NaN
1  NaN  4.0  7  NaN  6.0

Ponownie należy pamiętać, że dane przekazywane do json_normalize muszą znajdować się w formacie listy słowników (rekordów).

Jak wspomniano, json_normalize może również obsługiwać zagnieżdżone słowniki. Oto przykład zaczerpnięty z dokumentacja.

data_nested = [
  {'counties': [{'name': 'Dade', 'population': 12345},
                {'name': 'Broward', 'population': 40000},
                {'name': 'Palm Beach', 'population': 60000}],
   'info': {'governor': 'Rick Scott'},
   'shortname': 'FL',
   'state': 'Florida'},
  {'counties': [{'name': 'Summit', 'population': 1234},
                {'name': 'Cuyahoga', 'population': 1337}],
   'info': {'governor': 'John Kasich'},
   'shortname': 'OH',
   'state': 'Ohio'}
]
pd.json_normalize(data_nested, 
                          record_path='counties', 
                          meta=['state', 'shortname', ['info', 'governor']])

         name  population    state shortname info.governor
0        Dade       12345  Florida        FL    Rick Scott
1     Broward       40000  Florida        FL    Rick Scott
2  Palm Beach       60000  Florida        FL    Rick Scott
3      Summit        1234     Ohio        OH   John Kasich
4    Cuyahoga        1337     Ohio        OH   John Kasich

Aby uzyskać więcej informacji na temat argumentów meta i record_path, zajrzyj do dokumentacji.


Podsumowanie

Oto tabela wszystkich metod omówionych powyżej, wraz z obsługiwanymi funkcjami / funkcjami.

Tutaj wpisz opis obrazka

* użyj orient='columns', a następnie TRANSPONUJ, aby uzyskać taki sam efekt jak orient='index'.

 209
Author: cs95,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-08 11:42:24

W pandach 16.2, musiałem zrobić pd.DataFrame.from_records(d), żeby to zadziałało.

 84
Author: szeitlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-14 13:12:38

Możesz również użyć pd.DataFrame.from_dict(d) jako:

In [8]: d = [{'points': 50, 'time': '5:00', 'year': 2010}, 
   ...: {'points': 25, 'time': '6:00', 'month': "february"}, 
   ...: {'points':90, 'time': '9:00', 'month': 'january'}, 
   ...: {'points_h1':20, 'month': 'june'}]

In [12]: pd.DataFrame.from_dict(d)
Out[12]: 
      month  points  points_h1  time    year
0       NaN    50.0        NaN  5:00  2010.0
1  february    25.0        NaN  6:00     NaN
2   january    90.0        NaN  9:00     NaN
3      june     NaN       20.0   NaN     NaN
 24
Author: shivsn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-07 06:03:08

Pyhton3: {]} Większość wymienionych wcześniej rozwiązań działa. Są jednak przypadki, gdy numer wiersza ramki danych nie jest wymagany i każdy wiersz (rekord) musi być zapisywany indywidualnie.

W takim przypadku użyteczna jest następująca metoda.

import csv

my file= 'C:\Users\John\Desktop\export_dataframe.csv'

records_to_save = data2 #used as in the thread. 


colnames = list[records_to_save[0].keys()] 
# remember colnames is a list of all keys. All values are written corresponding
# to the keys and "None" is specified in case of missing value 

with open(myfile, 'w', newline="",encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(colnames)
    for d in records_to_save:
        writer.writerow([d.get(r, "None") for r in colnames])
 0
Author: Soum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Do konwersji listy słowników na ramkę danych pandy można użyć "append":

Mamy Słownik o nazwie dic i dic ma 30 pozycji listy(list1, list2,..., list30)

  1. Krok 1: zdefiniuj zmienną dla zachowania wyniku (ex: total_df)
  2. Krok 2: zainicjalizuj total_df za pomocą list1
  3. Krok 3: użyj pętli for, aby dodać wszystkie listy do total_df
total_df=list1
nums=Series(np.arange(start=2, stop=31))
for num in nums:
    total_df=total_df.append(dic['list'+str(num)])
 0
Author: Armin Ahmadi Nasab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-19 07:52:25

Najłatwiejszy sposób, jaki znalazłem, to tak:

dict_count = len(dict_list)
df = pd.DataFrame(dict_list[0], index=[0])
for i in range(1,dict_count-1):
    df = df.append(dict_list[i], ignore_index=True)
 -1
Author: scottapotamus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-01 11:04:58