簡體   English   中英

如何從Python中的字典中獲取對稱矩陣

[英]How to obtain symmetrical matrix from dictionary in Python

我有一個關於 Python 中數據操作的基本問題。

我有以下字典:

mydict={('A', 'E'): 23972,
 ('A', 'D'): 10730,
 ('A', 'B'): 14748,
 ('A', 'C'): 3424,
 ('E', 'D'): 3294,
 ('E', 'B'): 16016,
 ('E', 'C'): 3373,
 ('D', 'B'): 69734,
 ('D', 'C'): 4662,
 ('B', 'C'): 159161}

如果仔細觀察,這是具有空對角線的對稱矩陣的一半(不包括 0)。 我的最終目標是編寫一個帶有完整矩陣的 Pandas 數據框。

暫定方案

我想過“解包”字典獲得 5 個列表,每個標簽一個,所有值都與其他標簽相關,在列表的自我位置上添加一個 0。 對於標簽“A”和“B”,期望的結果是:

A=[0,mydict(['A','B']),mydict(['A','C']),mydict(['A','D']),mydict(['A','E'])]
B=[mydict(['A','B']),0,mydict(['B','C']),mydict(['D','B']),mydict(['E','B'])]

依此類推 C、D、E。 請注意,在 B 中,第 4 和第 5 個元素是 mydict(['D','B']) 和 mydict(['E','B']),因為 mydict(['B','D'])而 mydict(['B','E']) 在 mydict 中根本不存在。

通過這種方式,我可以輕松地從這些列表中填充數據框:

import pandas as pd
df=pd.DataFrame(columns=['A','B','C','D','E'])
df['A']=A
df['B']=B

我不太確定如何將 mydict “解包”到這些列表中,或者可以幫助我構建矩陣的任何其他容器中。 有什么建議?

一種選擇是以完整矩陣格式重建字典,然后使用熊貓對其進行旋轉:

import pandas as pd
mydict={('A', 'E'): 23972,
 ('A', 'D'): 10730,
 ('A', 'B'): 14748,
 ('A', 'C'): 3424,
 ('E', 'D'): 3294,
 ('E', 'B'): 16016,
 ('E', 'C'): 3373,
 ('D', 'B'): 69734,
 ('D', 'C'): 4662,
 ('B', 'C'): 159161}
 
 
# construct the full dictionary
newdict = {}

for (k1, k2), v in mydict.items():
    newdict[k1, k2] = v
    newdict[k2, k1] = v
    newdict[k1, k1] = 0
    newdict[k2, k2] = 0

# pivot the result from long to wide
pd.Series(newdict).reset_index().pivot(index='level_0', columns='level_1', values=0)

#level_1      A       B       C      D      E
#level_0                                     
#A            0   14748    3424  10730  23972
#B        14748       0  159161  69734  16016
#C         3424  159161       0   4662   3373
#D        10730   69734    4662      0   3294
#E        23972   16016    3373   3294      0

或者正如@Ch3steR 所評論的那樣,您也可以只為樞軸執行pd.Series(newdict).unstack()

演示鏈接

我能想到的是首先將 dict 值填充到數組中,然后構造數據幀。

mydict={('A', 'E'): 23972,
 ('A', 'D'): 10730,
 ('A', 'B'): 14748,
 ('A', 'C'): 3424,
 ('E', 'D'): 3294,
 ('E', 'B'): 16016,
 ('E', 'C'): 3373,
 ('D', 'B'): 69734,
 ('D', 'C'): 4662,
 ('B', 'C'): 159161}
 
import numpy as np
import pandas as pd

a = np.full((5,5),0)
ss = 'ABCDE'

for k, i in mydict.items():
    f,s = k 
    fi = ss.index(f)
    si = ss.index(s)
    a[fi,si] = i
    a[si,fi] = i

# if you want to keep the diagonal
df = pd.DataFrame(a)

# if you want to remove diagonal:
no_diag = np.delete(a,range(0,a.shape[0]**2,(a.shape[0]+1))).reshape(a.shape[0],(a.shape[1]-1))

df = pd.DataFrame(no_diag)

這是一個直接的解決方案,它也不應該花費太多時間來運行 -

cols = np.unique(list(mydict.keys())).ravel()

df = pd.DataFrame(0, columns=cols, index=cols)

for i in mydict.items():
    df.loc[i[0]] = i[1] 

df = df + df.T
print(df)
       A       B       C      D      E
A      0   14748    3424  10730  23972
B  14748       0  159161  69734  16016
C   3424  159161       0   4662   3373
D  10730   69734    4662      0   3294
E  23972   16016    3373   3294      0

基准

添加基准(303 長度輸入,MacBook pro 13)-

kk = 'ABCDEFGHIJKLMNOPQURSUVWXYZ'
mydict = {i:np.random.randint(1,10000) for i in itertools.combinations(kk,2)}
len(mydict)
#303
  • 融合的方法- 每個循環 392 µs ± 16.4 µs(平均值 ± 標准偏差,7 次運行,每次 1000 次循環)
  • Psidom 的方法- 每個循環 4.95 ms ± 286 µs(平均值 ± 標准偏差,7 次運行,每次 100 次循環)
  • Akshay Sehgal 的方法- 每個循環 34.8 ms ± 884 µs(平均值 ± 標准偏差,7 次運行,每次 10 次循環)
  • Ben.T 的方法- 每個循環 4.01 ms ± 282 µs(平均值 ± 標准偏差,7 次運行,每次 100 次循環)

Fusion 的方法是最快的。

一旦創建一個系列形式的字典,然后unstack以獲取數據幀。 獲取索引和列的並union ,以便能夠使用所有可能的值重新reindex兩者。 將此數據幀的轉置添加到自身以獲取缺失值。

df_ = pd.Series(mydict).unstack(fill_value=0)
idx = df_.index.union(df_.columns)
df_ = df_.reindex(index=idx, columns=idx, fill_value=0)
df_ += df_.T

print(df_)
       A       B       C      D      E
A      0   14748    3424  10730  23972
B  14748       0  159161  69734  16016
C   3424  159161       0   4662   3373
D  10730   69734    4662      0   3294
E  23972   16016    3373   3294      0

暫無
暫無

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

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