簡體   English   中英

用每個字典的唯一鍵展平嵌套字典?

[英]Flattening a nested dictionary with unique keys for each dictionary?

我有一本具有以下格式的字典:

´´´{'7453': 
      {'2H': 
         {'1155': 
            {'in': [{'playerId': 281253}, {'playerId': 169212}], 
            'out': [{'playerId': 449240}, {'playerId': 257943}]},
          '2011': 
            {'in': [{'playerId': 449089}], 
            'out': [{'playerId': 69374}]}, 
          '2568': 
            {'in': [{'playerId': 481900}], 
            'out': [{'playerId': 1735}]}}}, 
    '7454': 
       {'1H': 
          {'2833': 
             {'in': [{'playerId': 56390}], 
             'out': [{'playerId': 208089}]}}, 
        '2H': 
          {'687': 
             {'in': [{'playerId': 574}], 
             'out': [{'playerId': 578855}]}, 
          '1627': 
             {'in': [{'playerId': 477400}], 
             'out': [{'playerId': 56386}]}, 
          '2725': 
             {'in': [{'playerId': 56108}], 
             'out': [{'playerId': 56383}]}}}}
´´´

我需要以下格式的數據(df): https://i.stack.imgur.com/GltRb.png

這意味着我想展平我的數據,以便我有 id:“7453”,一半:“H2”,分鍾:“2011”,類型:“out”,playerId:“281253”。 另外,我需要每個玩家一個記錄,但仍然包含所有其他數據(id、half 等)

我已經為此苦苦掙扎了好幾天,似乎無法為這個特定問題找到任何解決方案。 到目前為止,我已經能夠使用 pd.json_normalize() 或 flatten_json() 來解決它。 但在這種情況下,它不適合我。 如果有人能指出我正確的方向或編寫一些可以解決此問題的代碼,將不勝感激!

僅供參考:我最大的困難是我實際上需要一個標題/列來存放我的鍵。

pandas 已經explode展開列表,但我不知道字典的方法。

由於您的字典結構非常好,您可以嘗試

[28]: pd.Series(d).apply(pd.Series).stack().apply(pd.Series).stack().apply(pd
    ...: .Series).stack().explode().apply(pd.Series).reset_index().rename(column
    ...: s={'level_0': 'teamId', 'level_1': 'matchPeriod', 'level_2': 'eventSec'
    ...: , 'level_3': 'type'})                                                  
Out[28]: 
   teamId matchPeriod eventSec type  playerId
0    7453          2H     1155   in    281253
1    7453          2H     1155   in    169212
2    7453          2H     1155  out    449240
3    7453          2H     1155  out    257943
4    7453          2H     2011   in    449089
..    ...         ...      ...  ...       ...
11   7454          2H     1627  out     56386
12   7454          2H     2725   in     56108
13   7454          2H     2725  out     56383
14   7454          1H     2833   in     56390
15   7454          1H     2833  out    208089

盡管將Series構造函數和stack鏈接起來非常難看,但會逐級構建 DataFrame。

更新:原則上,您可以將字典傳遞給DataFrameSeries構造函數

In [2]: d                                                                                                                                                                                                  
Out[2]: 
{'7453': {'2H': {'1155': {'in': [{'playerId': 281253}, {'playerId': 169212}],
    'out': [{'playerId': 449240}, {'playerId': 257943}]},
   '2011': {'in': [{'playerId': 449089}], 'out': [{'playerId': 69374}]},
   '2568': {'in': [{'playerId': 481900}], 'out': [{'playerId': 1735}]}}},
 '7454': {'1H': {'2833': {'in': [{'playerId': 56390}],
    'out': [{'playerId': 208089}]}},
  '2H': {'687': {'in': [{'playerId': 574}], 'out': [{'playerId': 578855}]},
   '1627': {'in': [{'playerId': 477400}], 'out': [{'playerId': 56386}]},
   '2725': {'in': [{'playerId': 56108}], 'out': [{'playerId': 56383}]}}}}

In [3]: pd.DataFrame(d)                                                                                                                                                                                    
Out[3]: 
                        7453                      7454
2H  {'1155': {'in': [{'pl...  {'687': {'in': [{'pla...
1H                       NaN  {'2833': {'in': [{'pl...

In [4]: pd.Series(d)                                                                                                                                                                                       
Out[4]: 
7453    {'2H': {'1155': {'in'...
7454    {'1H': {'2833': {'in'...
dtype: object

由於它們分別是二維和一維數據結構,因此它們還期望字典分別具有 2 級和 1 級深度嵌套。 DataFrame將您的“teamId”解釋為索引,將“matchPeriod”解釋為列,值是字典的值,如

In [5]: d['7453']['2H']                                                                                                                                                                                    
Out[5]: 
{'1155': {'in': [{'playerId': 281253}, {'playerId': 169212}],
  'out': [{'playerId': 449240}, {'playerId': 257943}]},
 '2011': {'in': [{'playerId': 449089}], 'out': [{'playerId': 69374}]},
 '2568': {'in': [{'playerId': 481900}], 'out': [{'playerId': 1735}]}}

Series的行為方式相同,但只有一個級別。

In [6]: d['7453']                                                                                                                                                                                          
Out[6]: 
{'2H': {'1155': {'in': [{'playerId': 281253}, {'playerId': 169212}],
   'out': [{'playerId': 449240}, {'playerId': 257943}]},
  '2011': {'in': [{'playerId': 449089}], 'out': [{'playerId': 69374}]},
  '2568': {'in': [{'playerId': 481900}], 'out': [{'playerId': 1735}]}}}

是你的第一級。 現在這又是一個字典,所以你也可以將它傳遞給Series構造函數

In [7]: pd.Series(d['7453'])                                                                                                                                                                               
Out[7]: 
2H    {'1155': {'in': [{'pl...
dtype: object

apply function 允許您對Series的每一行執行此操作

In [8]: pd.Series(d).apply(pd.Series)                                                                                                                                                                      
Out[8]: 
                            2H                        1H
7453  {'1155': {'in': [{'pl...                       NaN
7454  {'687': {'in': [{'pla...  {'2833': {'in': [{'pl...

現在您得到與DataFrame構造函數相同的結果。 這稱為廣播。 原始Series no 的每個值都成為其自己的Series ,並且索引用作列標簽。 通過調用stack你 intead 告訴 pandas 給你一個系列 intead 並在需要時將所有標簽堆疊到MultiIndex

In [9]: pd.Series(d).apply(pd.Series).stack()                                                                                                                                                              
Out[9]: 
7453  2H    {'1155': {'in': [{'pl...
7454  2H    {'687': {'in': [{'pla...
      1H    {'2833': {'in': [{'pl...
dtype: object

現在您再次擁有一個 Series(帶有 2d 索引),其中每個值都是一個字典,可以再次將其傳遞給Series構造函數。 所以如果你重復這個apply(pd.Series).stack()鏈,你會得到

In [10]: pd.Series(d).apply(pd.Series).stack().apply(pd.Series).stack()                                                                                                                                    
Out[10]: 
7453  2H  1155    {'in': [{'playerId': ...
          2011    {'in': [{'playerId': ...
          2568    {'in': [{'playerId': ...
7454  2H  687     {'in': [{'playerId': ...
          1627    {'in': [{'playerId': ...
          2725    {'in': [{'playerId': ...
      1H  2833    {'in': [{'playerId': ...
dtype: object

現在您又擁有了一個 Series(帶有 3d 索引),其中每個值都是一個字典,可以再次將其傳遞給Series構造函數。

In [11]: pd.Series(d).apply(pd.Series).stack().apply(pd.Series).stack().apply(pd.Series).stack()                                                                                                           
Out[11]: 
7453  2H  1155  in     [{'playerId': 281253}...
                out    [{'playerId': 449240}...
          2011  in       [{'playerId': 449089}]
                out       [{'playerId': 69374}]
          2568  in       [{'playerId': 481900}]
                out        [{'playerId': 1735}]
7454  2H  687   in          [{'playerId': 574}]
                out      [{'playerId': 578855}]
          1627  in       [{'playerId': 477400}]
                out       [{'playerId': 56386}]
          2725  in        [{'playerId': 56108}]
                out       [{'playerId': 56383}]
      1H  2833  in        [{'playerId': 56390}]
                out      [{'playerId': 208089}]
dtype: object

這是一種特殊情況,因為現在您的值不再是字典而是列表(每個都有一個元素)。 對於列表(不幸的是,不是字典),pandas 中的explode()方法可以為每個列表元素創建一個新行。

In [13]: pd.Series(d).apply(pd.Series).stack().apply(pd.Series).stack().apply(pd.Series).stack().explode()                                                                                                 
Out[13]: 
7453  2H  1155  in     {'playerId': 281253}
                in     {'playerId': 169212}
                out    {'playerId': 449240}
                out    {'playerId': 257943}
          2011  in     {'playerId': 449089}
                               ...         
7454  2H  1627  out     {'playerId': 56386}
          2725  in      {'playerId': 56108}
                out     {'playerId': 56383}
      1H  2833  in      {'playerId': 56390}
                out    {'playerId': 208089}
dtype: object

解壓每個列表。 現在您再次擁有一個 Series(帶有 4d 索引),其中每個值都是一個字典,可以再次將其傳遞給Series構造函數。

In [14]: pd.Series(d).apply(pd.Series).stack().apply(pd.Series).stack().apply(pd.Series).stack().explode().apply(pd.Series).stack()                                                                        
Out[14]: 
7453  2H  1155  in   playerId    281253
                     playerId    169212
                out  playerId    449240
                     playerId    257943
          2011  in   playerId    449089
                                  ...  
7454  2H  1627  out  playerId     56386
          2725  in   playerId     56108
                out  playerId     56383
      1H  2833  in   playerId     56390
                out  playerId    208089
dtype: int64

通過將Series構造函數應用於您的字典並重塑數據直到您可以再次應用它的這五次迭代,您的字典已完全解包。

為了匹配您想要的結果,您可以使用reset_index將所有級別的索引設置為列。

In [15]: pd.Series(d).apply(pd.Series).stack().apply(pd.Series).stack().apply(pd.Series).stack().explode().apply(pd.Series).stack().reset_index()                                                          
Out[15]: 
   level_0 level_1 level_2 level_3   level_4       0
0     7453      2H    1155      in  playerId  281253
1     7453      2H    1155      in  playerId  169212
2     7453      2H    1155     out  playerId  449240
3     7453      2H    1155     out  playerId  257943
4     7453      2H    2011      in  playerId  449089
..     ...     ...     ...     ...       ...     ...
11    7454      2H    1627     out  playerId   56386
12    7454      2H    2725      in  playerId   56108
13    7454      2H    2725     out  playerId   56383
14    7454      1H    2833      in  playerId   56390
15    7454      1H    2833     out  playerId  208089

系列和索引級別都沒有名稱。 默認情況下,它使用列號 ( 0 ) 作為值(應該是“playerId”), level_0level_4作為索引級別。 為了適當地設置這些,一種方法是在調用reset_index之前重命名Series ,然后使用rename重命名levels

我希望這會有所幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM