3

次の形式の 2 次元辞書があります。

myDict = {('a','b'):10, ('a','c'):20, ('a','d'):30, ('b','c'):40, ('b','d'):50,('c','d'):60}

これをタブ区切りファイルに書き込んで、ファイルに次のものが含まれるようにするにはどうすればよいですか。タプル (x, y) を埋めると、(x,y) と (y,x) の 2 つの場所が埋められます。(x,x) は常に 0 です。

出力は次のようになります。

    a   b   c   d
a   0   10  20  30
b   10  0   40  50
c   20  40  0   60
d   30  50  60  0 

PS: 何らかの方法で辞書を (pandas を使用して) データフレームに変換できる場合は、pandas 関数を使用して簡単にファイルに書き込むことができます。

4

4 に答える 4

7

あまり知られていないalign方法とちょっとしたunstack魔法でこれを行うことができます。

In [122]: s = Series(myDict, index=MultiIndex.from_tuples(myDict))

In [123]: df = s.unstack()

In [124]: lhs, rhs = df.align(df.T)

In [125]: res = lhs.add(rhs, fill_value=0).fillna(0)

In [126]: res
Out[126]:
    a   b   c   d
a   0  10  20  30
b  10   0  40  50
c  20  40   0  60
d  30  50  60   0

最後に、これを CSV ファイルに書き込むには、次のto_csvメソッドを使用します。

In [128]: res.to_csv('res.csv', sep='\t')

In [129]: !cat res.csv
        a       b       c       d
a       0.0     10.0    20.0    30.0
b       10.0    0.0     40.0    50.0
c       20.0    40.0    0.0     60.0
d       30.0    50.0    60.0    0.0

整数として保持したい場合は、次DataFrame.astype()のようにを使用してキャストします。

In [137]: res.astype(int).to_csv('res.csv', sep='\t')

In [138]: !cat res.csv
        a       b       c       d
a       0       10      20      30
b       10      0       40      50
c       20      40      0       60
d       30      50      60      0

nan(一方のフレームのインデックスが他方のフレームから欠落している値を埋める中間ステップのため、float にキャストされました)

を使用した@Dan Allanの答えcombine_firstはいいです:

In [130]: df.combine_first(df.T).fillna(0)
Out[130]:
    a   b   c   d
a   0  10  20  30
b  10   0  40  50
c  20  40   0  60
d  30  50  60   0

タイミング:

In [134]: timeit df.combine_first(df.T).fillna(0)
100 loops, best of 3: 2.01 ms per loop

In [135]: timeit lhs, rhs = df.align(df.T); res = lhs.add(rhs, fill_value=0).fillna(0)
1000 loops, best of 3: 1.27 ms per loop

これらのタイミングはおそらく建設コストによって少し汚染されているので、本当に巨大なフレームではどのように見えるでしょうか?

In [143]: df = DataFrame({i: randn(1e7) for i in range(1, 11)})

In [144]: df2 = DataFrame({i: randn(1e7) for i in range(10)})

In [145]: timeit lhs, rhs = df.align(df2); res = lhs.add(rhs, fill_value=0).fillna(0)
1 loops, best of 3: 4.41 s per loop

In [146]: timeit df.combine_first(df2).fillna(0)
1 loops, best of 3: 2.95 s per loop

DataFrame.combine_first()フレームが大きいほど高速です。

于 2013-10-08T22:05:03.530 に答える
6
In [49]: data = map(list, zip(*myDict.keys())) + [myDict.values()]

In [50]: df = DataFrame(zip(*data)).set_index([0, 1])[2].unstack()

In [52]: df.combine_first(df.T).fillna(0)
Out[52]: 
    a   b   c   d
a   0  10  20  30
b  10   0  40  50
c  20  40   0  60
d  30  50  60   0

後世のために:あなたがただチューニングしているのであれば、以下のPhillip Cloudの回答をチェックして、df.

于 2013-10-08T22:04:00.730 に答える
1

私が望むほどエレガントではありません(パンダを使用していません)が、より良いものを見つけるまで:

adj = dict()
for ((u, v), w) in myDict.items():
  if u not in adj: adj[u] = dict()
  if v not in adj: adj[v] = dict()
  adj[u][v] = adj[v][u] = w
keys = adj.keys()

print '\t' + '\t'.join(keys)
for u in keys:
  def f(v):
    try:
      return str(adj[u][v])
    except KeyError:
      return "0"
  print u + '\t' + '\t'.join(f(v) for v in keys)

または同等に(隣接行列を構築したくない場合):

k = dict()
for ((u, v), w) in myDict.items():
  k[u] = k[v] = True
keys = k.keys()

print '\t' + '\t'.join(keys)
for u in keys:
  def f(v):
    if (u, v) in myDict:
      return str(myDict[(u, v)])
    elif (v, u) in myDict:
      return str(myDict[(v, u)])
    else:
      return "0"
  print u + '\t' + '\t'.join(f(v) for v in keys)
于 2013-10-08T21:47:42.320 に答える
-2

pandasパッケージ を使用して動作しました。

#Find all column names 
z = []
[z.extend(x) for x in myDict.keys()]
colnames = sorted(set(z))

#Create an empty DataFrame  using pandas 
myDF  =  DataFrame(index= colnames, columns = colnames )
myDF  =  myDF.fillna(0) #Initialize with zeros
#Fill each item one by one 
for val in myDict:
    myDF[val[0]][val[1]] = myDict[val]
    myDF[val[1]][val[0]] = myDict[val]

#Write to a file 
outfilename = "matrixCooccurence.txt"
myDF.to_csv(outfilename, sep="\t", index=True, header=True, index_label = "features" )
于 2013-10-08T22:08:14.160 に答える