【问题标题】:Comparing keys of a dictionary within a dataframe column比较数据框列中字典的键
【发布时间】:2020-03-25 21:57:45
【问题描述】:

我有一个类似的数据框 -

Challenge       Points
challenge1      {'k01-001': 0.5, 'k03-015':0.3, 'k01-005': 0.2}
challenge2      {'k02-001': 0.5, 'k06-003':0.4, 'k04-001': 0.1}
challenge3      {'k04-001': 0.1, 'k06-003':0.9}
challenge4      {'k01-005': 0.2, 'k01-001':0.4, 'k03-002': 0.2, 'k01-007': 0.2}
challenge5      {'k06-003': 0.6, 'k04-001':0.4}

从这里我想创建一个字典,其中的键应该是两个点的元组,它们已经一起评估了一个挑战(例如('k01-001', 'k01-005')),值应该是他们一起评估了多少个挑战. 所以,像 -

{('k01-001', 'k01-005'): 2, ('k01-001', 'k03-015'): 1, ('k01-005', 'k03-015'): 1, ('k04-001', 'k06-003'): 3, ... }

到目前为止,我已经设法使用此代码阅读了 Points 列中的各个字典 -

for index, row in df.iterrows():
    dict_temp = json.loads(row['Points'].replace("'", '"'))    
    for key, value in dict_temp.items():
        # SOME CODE HERE

但是,我不确定如何从这里开始。

【问题讨论】:

  • 你想要每一行的字典吗?
  • 不,整个数据帧的字典。
  • 是否有重复挑战行?
  • 不,Challenge 列具有所有唯一值,但两个(或更多)挑战可以具有相同的 Points
  • 你能对你的数据框做 to_dict() 吗?

标签: python-3.x pandas dataframe dictionary


【解决方案1】:

我会使用 mapreduce 和 defaultdict 来计数:

from collections import defaultdict
from functools import reduce
from itertools import combinations

combs = reduce(lambda x, y: x + y, 
               map(lambda x: tuple(map(sorted, combinations(list(x), 2))) ,
                   df['Points']))

d = defaultdict(int)
for comb in combs:
    d[tuple(comb)] += 1
d = dict(d)
print(d)

{('k01-001', 'k03-015'): 1, ('k01-001', 'k01-005'): 2, ('k01-005', 'k03-015'): 1,
 ('k02-001', 'k06-003'): 1, ('k02-001', 'k04-001'): 1, ('k04-001', 'k06-003'): 3,
 ('k01-005', 'k03-002'): 1, ('k01-005', 'k01-007'): 1, ('k01-001', 'k03-002'): 1, 
 ('k01-001', 'k01-007'): 1,('k01-007', 'k03-002'): 1}

时间对比:

%%timeit
combs = reduce(lambda x,y: x + y, 
               map(lambda x: tuple(map(sorted, combinations(list(x), 2))) ,
                   df['Points']))

d = defaultdict(int)
for comb in combs:
    d[tuple(comb)]+=1
d = dict(d)
26.2 µs ± 439 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%%timeit
s=(df.Points.apply(lambda x: tuple(itertools.combinations(x.keys(), 2))).explode()
    .apply(lambda x : tuple(sorted(x))).value_counts()).to_dict()
1.69 ms ± 62.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

  • 它给了我每个字符的键 - 例如。 ('"', '{'): 804, ('S', '{'): 190, ('-', '{'): 402 ...
  • 我认为你的单元格类型是 str 而不是 dict,也许你需要:df['Points'] = df['Points'].apply(eval) before
  • 我以您的数据框为例。单元格必须包含字典,但我认为你的包含字符串..所以使用其他解决方案它会给你错误 str 没有属性键,键是字典的属性 ...
  • 是的,它适用于apply(eval) .. 非常感谢!! :)
【解决方案2】:

IIUC 我们需要 itertools 来获取 combination 然后我们执行 explodesorted 中的值 tuplevalue_counts

import itertools
s=df.Points.apply(lambda x: tuple(itertools.combinations(x.keys(), 2))).explode().apply(lambda x : tuple(sorted(x))).value_counts()
Out[543]: 
(k04-001, k06-003)    3
(k01-001, k01-005)    2
(k02-001, k04-001)    1
(k01-005, k03-002)    1
(k01-005, k03-015)    1
(k01-001, k03-002)    1
(k01-001, k03-015)    1
(k01-001, k01-007)    1
(k01-005, k01-007)    1
(k01-007, k03-002)    1
(k02-001, k06-003)    1
Name: Points, dtype: int64

如果你需要dict

s.to_dict()
Out[546]: 
{('k04-001', 'k06-003'): 3,
 ('k01-001', 'k01-005'): 2,
 ('k02-001', 'k04-001'): 1,
 ('k01-005', 'k03-002'): 1,
 ('k01-005', 'k03-015'): 1,
 ('k01-001', 'k03-002'): 1,
 ('k01-001', 'k03-015'): 1,
 ('k01-001', 'k01-007'): 1,
 ('k01-005', 'k01-007'): 1,
 ('k01-007', 'k03-002'): 1,
 ('k02-001', 'k06-003'): 1}

【讨论】:

  • AttributeError: 'str' object has no attribute 'keys' 我上面的代码将字符串转换为字典。我该怎么做呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
相关资源
最近更新 更多