Misalkan saya memiliki kamus bersarang 'user_dict' dengan struktur:
- Level 1: UserId (Long Integer)
- Level 2: Kategori (String)
- Level 3: Atribut Aneka (float, int, dll ..)
Misalnya, entri kamus ini adalah:
user_dict[12] = {
"Category 1": {"att_1": 1,
"att_2": "whatever"},
"Category 2": {"att_1": 23,
"att_2": "another"}}
setiap item user_dict
memiliki struktur yang sama dan user_dict
berisi sejumlah besar item yang ingin saya beri makan ke DataFrame pandas, membuat rangkaian dari atributnya. Dalam hal ini indeks hierarki akan berguna untuk tujuan tersebut.
Secara khusus, pertanyaan saya adalah apakah ada cara untuk membantu konstruktor DataFrame memahami bahwa rangkaian tersebut harus dibangun dari nilai "level 3" dalam kamus?
Jika saya mencoba sesuatu seperti:
df = pandas.DataFrame(users_summary)
Item di "level 1" (UserId) diambil sebagai kolom, yang merupakan kebalikan dari apa yang ingin saya capai (memiliki UserId sebagai indeks).
Saya tahu saya dapat membuat rangkaian setelah mengulang entri kamus, tetapi jika ada cara yang lebih langsung, ini akan sangat berguna. Pertanyaan serupa akan menanyakan apakah mungkin untuk membuat DataFrame pandas dari objek json yang terdaftar dalam sebuah file.
sumber
Jawaban:
MultiIndex pandas terdiri dari daftar tupel. Jadi pendekatan yang paling alami adalah dengan membentuk kembali dikt input Anda sehingga kuncinya adalah tupel yang sesuai dengan nilai multi-indeks yang Anda butuhkan. Kemudian Anda dapat membuat kerangka data Anda menggunakan
pd.DataFrame.from_dict
, menggunakan opsiorient='index'
:user_dict = {12: {'Category 1': {'att_1': 1, 'att_2': 'whatever'}, 'Category 2': {'att_1': 23, 'att_2': 'another'}}, 15: {'Category 1': {'att_1': 10, 'att_2': 'foo'}, 'Category 2': {'att_1': 30, 'att_2': 'bar'}}} pd.DataFrame.from_dict({(i,j): user_dict[i][j] for i in user_dict.keys() for j in user_dict[i].keys()}, orient='index') att_1 att_2 12 Category 1 1 whatever Category 2 23 another 15 Category 1 10 foo Category 2 30 bar
Pendekatan alternatifnya adalah membangun kerangka data Anda dengan menggabungkan kerangka data komponen:
user_ids = [] frames = [] for user_id, d in user_dict.iteritems(): user_ids.append(user_id) frames.append(pd.DataFrame.from_dict(d, orient='index')) pd.concat(frames, keys=user_ids) att_1 att_2 12 Category 1 1 whatever Category 2 23 another 15 Category 1 10 foo Category 2 30 bar
sumber
pd.concat
menerima kamus. Dengan pemikiran ini, adalah mungkin untuk memperbaiki jawaban yang diterima saat ini dalam hal kesederhanaan dan kinerja dengan menggunakan pemahaman kamus untuk membangun kunci pemetaan kamus ke sub-bingkai.pd.concat({k: pd.DataFrame(v).T for k, v in user_dict.items()}, axis=0)
Atau,
pd.concat({ k: pd.DataFrame.from_dict(v, 'index') for k, v in user_dict.items() }, axis=0)
att_1 att_2 12 Category 1 1 whatever Category 2 23 another 15 Category 1 10 foo Category 2 30 bar
sumber
12:{cat1:{cat11:{att1:val1,att2:val2}}}
. Dengan kata lain: bagaimana seseorang akan menggeneralisasi solusi untuk sejumlah kategori yang tidak relevan?json_normalize
. Saya punya jawaban lain yang menunjukkan cara kerjanya.v
berupa bilangan bulat tunggal misalnya. Apakah Anda mengetahui alternatif dalam kasus seperti itu?Jadi saya dulu menggunakan for loop untuk iterasi melalui kamus juga, tapi satu hal yang saya temukan yang bekerja lebih cepat adalah mengonversi ke panel dan kemudian ke dataframe. Katakanlah Anda memiliki kamus d
import pandas as pd d {'RAY Index': {datetime.date(2014, 11, 3): {'PX_LAST': 1199.46, 'PX_OPEN': 1200.14}, datetime.date(2014, 11, 4): {'PX_LAST': 1195.323, 'PX_OPEN': 1197.69}, datetime.date(2014, 11, 5): {'PX_LAST': 1200.936, 'PX_OPEN': 1195.32}, datetime.date(2014, 11, 6): {'PX_LAST': 1206.061, 'PX_OPEN': 1200.62}}, 'SPX Index': {datetime.date(2014, 11, 3): {'PX_LAST': 2017.81, 'PX_OPEN': 2018.21}, datetime.date(2014, 11, 4): {'PX_LAST': 2012.1, 'PX_OPEN': 2015.81}, datetime.date(2014, 11, 5): {'PX_LAST': 2023.57, 'PX_OPEN': 2015.29}, datetime.date(2014, 11, 6): {'PX_LAST': 2031.21, 'PX_OPEN': 2023.33}}}
Perintah
pd.Panel(d) <class 'pandas.core.panel.Panel'> Dimensions: 2 (items) x 2 (major_axis) x 4 (minor_axis) Items axis: RAY Index to SPX Index Major_axis axis: PX_LAST to PX_OPEN Minor_axis axis: 2014-11-03 to 2014-11-06
dimana pd.Panel (d) [item] menghasilkan dataframe
pd.Panel(d)['SPX Index'] 2014-11-03 2014-11-04 2014-11-05 2014-11-06 PX_LAST 2017.81 2012.10 2023.57 2031.21 PX_OPEN 2018.21 2015.81 2015.29 2023.33
Anda kemudian dapat menekan perintah to_frame () untuk mengubahnya menjadi dataframe. Saya menggunakan reset_index juga untuk mengubah sumbu mayor dan minor menjadi kolom daripada menjadikannya sebagai indeks.
pd.Panel(d).to_frame().reset_index() major minor RAY Index SPX Index PX_LAST 2014-11-03 1199.460 2017.81 PX_LAST 2014-11-04 1195.323 2012.10 PX_LAST 2014-11-05 1200.936 2023.57 PX_LAST 2014-11-06 1206.061 2031.21 PX_OPEN 2014-11-03 1200.140 2018.21 PX_OPEN 2014-11-04 1197.690 2015.81 PX_OPEN 2014-11-05 1195.320 2015.29 PX_OPEN 2014-11-06 1200.620 2023.33
Terakhir, jika Anda tidak menyukai tampilan bingkai, Anda dapat menggunakan fungsi transpose panel untuk mengubah tampilan sebelum memanggil to_frame () lihat dokumentasi di sini http://pandas.pydata.org/pandas-docs/dev/generated /pandas.Panel.transpose.html
Sekadar contoh
pd.Panel(d).transpose(2,0,1).to_frame().reset_index() major minor 2014-11-03 2014-11-04 2014-11-05 2014-11-06 RAY Index PX_LAST 1199.46 1195.323 1200.936 1206.061 RAY Index PX_OPEN 1200.14 1197.690 1195.320 1200.620 SPX Index PX_LAST 2017.81 2012.100 2023.570 2031.210 SPX Index PX_OPEN 2018.21 2015.810 2015.290 2023.330
Semoga ini membantu.
sumber
Jika seseorang ingin mendapatkan bingkai data dalam "format panjang" (nilai daun memiliki jenis yang sama) tanpa multiindeks, Anda dapat melakukan ini:
pd.DataFrame.from_records( [ (level1, level2, level3, leaf) for level1, level2_dict in user_dict.items() for level2, level3_dict in level2_dict.items() for level3, leaf in level3_dict.items() ], columns=['UserId', 'Category', 'Attribute', 'value'] ) UserId Category Attribute value 0 12 Category 1 att_1 1 1 12 Category 1 att_2 whatever 2 12 Category 2 att_1 23 3 12 Category 2 att_2 another 4 15 Category 1 att_1 10 5 15 Category 1 att_2 foo 6 15 Category 2 att_1 30 7 15 Category 2 att_2 bar
(Saya tahu pertanyaan awal mungkin ingin (I.) memiliki Level 1 dan 2 sebagai multiindex dan Level 3 sebagai kolom dan (II.) Menanyakan tentang cara lain selain iterasi atas nilai dalam dikt. Tapi saya harap jawaban ini masih relevan dan berguna (I.): untuk orang-orang seperti saya yang telah mencoba menemukan cara untuk mendapatkan dikt bersarang ke dalam bentuk ini dan google hanya mengembalikan pertanyaan ini dan (II.): karena jawaban lain juga melibatkan beberapa iterasi dan saya menemukan ini pendekatan fleksibel dan mudah dibaca; meskipun tidak yakin dengan kinerja.)
sumber
Berdasarkan jawaban terverifikasi, bagi saya ini bekerja paling baik:
ab = pd.concat({k: pd.DataFrame(v).T for k, v in data.items()}, axis=0) ab.T
sumber