在同一循环中使用列表填充 dict
Posted
技术标签:
【中文标题】在同一循环中使用列表填充 dict【英文标题】:Populating a dict with a list in the same loop 【发布时间】:2019-04-13 09:16:46 【问题描述】:我正在尝试用 pandas sereis 中按列出现的字符来填充字典。剧集如下:
>>> jkl
1 ATGC
2 GTCA
3 CATG
Name: 0, dtype: object
我想要一个包含所有字符作为键的字典,并将它们的列出现频率列表作为字典的值,如下所示:
'A':[1,1,0,1],'C':[1,0,1,1],'G':[1,0,1,1],'T':[0,2,1,0]
我已经尝试了几个代码,这是其中之一:
mylist = ['A', 'C', 'G','T']
dict = key: None for key in mylist
for i,(a,b) in enumerate(zip_longest(jkl[1],dict.keys())):
t=str(list(jkl.str[i]))
single_occurrences = Counter(t)
kl.append(single_occurrences.get(b))
dict[b]=kl
但是这个 dict 不包含所需的输出,有解决方案吗?
【问题讨论】:
那么这里所有的字符串长度都一样? 不,它们的长度可以不同,但如果列中不存在元素,则应该为零 【参考方案1】:重新创建数据框后使用crosstab
S=pd.DataFrame(s.map(list).tolist()).melt()
pd.crosstab(S.value,S.variable)
Out[338]:
variable 0 1 2 3
value
A 1 1 0 1
C 1 0 1 1
G 1 0 1 1
T 0 2 1 0
添加to_dict
后
pd.crosstab(S.value,S.variable).T.to_dict('l')
Out[342]: 'A': [1, 1, 0, 1], 'C': [1, 0, 1, 1], 'G': [1, 0, 1, 1], 'T': [0, 2, 1, 0]
【讨论】:
【参考方案2】:我们可以在 Pandas 中进行切片和计数,然后每次构造一个字典,其计数如下:
max_len = jkl.str.len().max()
counts = [jkl.str[i].value_counts() for i in range(max_len)]
df = pd.DataFrame(counts, columns=['A', 'C', 'G', 'T'])
这给了我们一个数据框:
>>> df
A C G T
0 1.0 1.0 1.0 NaN
1 1.0 NaN NaN 2.0
2 NaN 1.0 1.0 1.0
3 1.0 1.0 1.0 NaN
然后我们可以用零填充NaN
s,并将数据转换为int
s:
>>> df.fillna(0).astype(int)
A C G T
0 1 1 1 0
1 1 0 0 2
2 0 1 1 1
3 1 1 1 0
最后我们可以将此数据框转换为列表字典:
>>> df.fillna(0).astype(int).to_dict('list')
'A': [1, 1, 0, 1], 'C': [1, 0, 1, 1], 'G': [1, 0, 1, 1], 'T': [0, 2, 1, 0]
【讨论】:
【参考方案3】:Counter
from collections import Counter
pd.Series(Counter(
(c, i) for i, C in enumerate(zip(*jkl)) for c in C)
).unstack(fill_value=0)
0 1 2 3
A 1 1 0 1
C 1 0 1 1
G 1 0 1 1
T 0 2 1 0
pd.Series(Counter(
(c, i) for i, C in enumerate(zip(*jkl)) for c in C
)).unstack(fill_value=0).T.to_dict('l')
'A': [1, 1, 0, 1], 'C': [1, 0, 1, 1], 'G': [1, 0, 1, 1], 'T': [0, 2, 1, 0]
np.add.at
完全不同的策略
r, i = np.unique([*''.join(jkl)], return_inverse=True)
n, m = len(r), len(jkl)
j = np.tile(np.arange(n), m)
a = np.zeros((n, n), int)
np.add.at(a, (i, j), 1)
DataFrame
pd.DataFrame(a, r)
0 1 2 3
A 1 1 0 1
C 1 0 1 1
G 1 0 1 1
T 0 2 1 0
Dictionary
dict(zip(r, a.tolist()))
'A': [1, 1, 0, 1], 'C': [1, 0, 1, 1], 'G': [1, 0, 1, 1], 'T': [0, 2, 1, 0]
【讨论】:
【参考方案4】:你可以这样做(不使用熊猫):
import pandas as pd
from itertools import chain
from collections import Counter
data = [[1, 'ATGC'],
[2, 'GTCA'],
[3, 'CATG']]
df = pd.DataFrame(data=data, columns=["row", "sequence"])
uniques = set(chain.from_iterable(df.sequence))
counts = list(map(Counter, zip(*df.sequence)))
result = letter: [count.get(letter, 0) for count in counts] for letter in uniques
print(result)
输出
'G': [1, 0, 1, 1], 'A': [1, 1, 0, 1], 'T': [0, 2, 1, 0], 'C': [1, 0, 1, 1]
【讨论】:
以上是关于在同一循环中使用列表填充 dict的主要内容,如果未能解决你的问题,请参考以下文章