2016-08-17 7 views
2

私は奇妙な距離メトリックを持つものに対してペアワイズ距離を行っています。私は{(key_A, key_B):distance_value}のような辞書を持っており、私は距離行列のように対称のpd.DataFrameを作りたいと思っています。パンダの辞書を対称/距離行列に変換する最も効率的な方法

これを行う最も効率的な方法は何ですか?私は1つの方法を見つけましたが、これを実行する最良の方法のようには見えません。このタイプの操作を行うNumPyまたはPandasに何かがありますか?またはちょうどより速い方法?私の方法は、あなたが探している距離行列に、1.46 ms per loop

np.random.seed(0) 
D_pair_value = dict() 
for pair in itertools.combinations(list("ABCD"),2): 
    D_pair_value[pair] = np.random.randint(0,5) 
D_pair_value 
# {('A', 'B'): 4, 
# ('A', 'C'): 0, 
# ('A', 'D'): 3, 
# ('B', 'C'): 3, 
# ('B', 'D'): 3, 
# ('C', 'D'): 1} 
D_nested_dict = defaultdict(dict) 
for (p,q), value in D_pair_value.items(): 
    D_nested_dict[p][q] = value 
    D_nested_dict[q][p] = value 

# Fill diagonal with zeros 
DF = pd.DataFrame(D_nested_dict) 
np.fill_diagonal(DF.values, 0) 
DF 

enter image description here

答えて

8

あなたは距離計算のベクトルを変換scipy.spatial.distance.squareformを、使用することができ、すなわち[d(A,B), d(A,C), ..., d(C,D)]です。

方法1:リストに格納距離が

、あなたのコード例では、私の例距離ベクトルのように、順番にあなたの距離を計算している場合、私は辞書とちょうどストアの使用を避けるだろうリスト内の結果、およびような何か:

from scipy.spatial.distance import squareform 

df = pd.DataFrame(squareform(dist_list), index=list('ABCD'), columns=list('ABCD')) 

方法2:あなたがTHIを計算している場合は辞書

に格納されている距離

from scipy.spatial.distance import squareform 

dist_list = [dist[1] for dist in sorted(D_pair_value.items())] 
df = pd.DataFrame(squareform(dist_list), index=list('ABCD'), columns=list('ABCD')) 

方法3:順序や辞書のうちNGSが必要とされて、あなただけの距離を適切にソートだベクトルを取得する必要がある辞書が必要な場合はソートされた辞書

に保存されている距離を、 sortedcontainersというパッケージがあり、それは本質的にソートの問題を解決するSortedDictというパッケージがあることに注意してください。それを使用するには、D_pair_valuedictの代わりにSortedDict()として初期化するだけです。あなたの例の設定を使用:

from scipy.spatial.distance import squareform 
from sortedcontainers import SortedDict 

np.random.seed(0) 
D_pair_value = SortedDict() 
for pair in itertools.combinations(list("ABCD"),2): 
    D_pair_value[pair] = np.random.randint(0,5) 

df = pd.DataFrame(squareform(D_pair_value.values()), index=list('ABCD'), columns=list('ABCD')) 

どれ上記の方法のための出力結果を:

 A B C D 
A 0.0 4.0 0.0 3.0 
B 4.0 0.0 3.0 3.0 
C 0.0 3.0 0.0 1.0 
D 3.0 3.0 1.0 0.0 
+3

ありがとうございました!私は今日何か新しいことを学んだ: 'scipy.spatial.distance.squareform' – MaxU

+0

方法2:それは!ニース、おかげで 'ルート' –

1

(単一文字の)キーの辞書との距離を考えると、ここでnumpyのベースのアプローチだ -

def dict2frame(D_pair_value): 
    # Extract keys and values 
    k = np.array(D_pair_value.keys()) 
    v = np.array(D_pair_value.values()) 

    # Get row, col indices from keys 
    idx = (np.fromstring(k.tobytes(),dtype=np.uint8)-65).reshape(-1,2) 

    # Setup output array and using row,col indices set values from v 
    N = idx.max()+1 
    out = np.zeros((N,N),dtype=v.dtype) 
    out[idx[:,0],idx[:,1]] = v 
    out[idx[:,1],idx[:,0]] = v 

    header = list("".join([chr(item) for item in np.arange(N)+65])) 
    return pd.DataFrame(out,index=header, columns=header) 

サンプル実行 -

In [166]: D_pair_value 
Out[166]: 
{('A', 'B'): 4, 
('A', 'C'): 0, 
('A', 'D'): 3, 
('B', 'C'): 3, 
('B', 'D'): 3, 
('C', 'D'): 1} 

In [167]: dict2frame(D_pair_value) 
Out[167]: 
    A B C D 
A 0 4 0 3 
B 4 0 3 3 
C 0 3 0 1 
D 3 3 1 0 
関連する問題