使用python将2d字典写入数据框或制表符分隔文件

时间:2013-10-08 21:27:18

标签: python pandas

我有以下格式的二维字典:

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)。 (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 个答案:

答案 0 :(得分:6)

你可以使用鲜为人知的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值的中间步骤,它被转换为浮动,其中一个帧的索引从另一个帧中丢失了)

@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()会更快。

答案 1 :(得分:5)

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

答案 2 :(得分: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)

答案 3 :(得分:-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" )