首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Itertools的Python?

用Itertools的Python?
EN

Stack Overflow用户
提问于 2018-04-12 21:29:09
回答 1查看 288关注 0票数 9

我有一个包含3列的.csv。PersonX,PersonY和PersonZ。有7000行的名字和不同的组合。我的目标是看看哪一对和三人组是最高的比赛。我一直未能在excel中找到实现这一目标的公式。我确信python能够结合迭代工具,但我还没有那么先进。名字可以按任何顺序排列,只需查看这2或3个人在同一排中的次数。任何建议都会有很大的帮助,谢谢!

数据的一个小例子。

代码语言:javascript
复制
PersonX         PersonY             PersonZ
Aaron Ekblad    Keith Yandle        Vincent Trocheck
Aaron Ekblad    Denis Malgin        Mike Matheson
Aaron Ekblad    Denis Malgin        Mike Matheson
Aaron Ekblad    Jonathan Huberdeau  Keith Yandle
Aaron Ekblad    Jonathan Huberdeau  Keith Yandle
Aaron Ekblad    Jamie McGinn        Keith Yandle
Aaron Ekblad    Aleksander Barkov   Jonathan Huberdeau
Aaron Ekblad        
Adam Erne       Andrej Sustr        Vladislav Namestnikov
Adam Erne       Anthony Cirelli 
Adam Erne       
Adam Henrique   Rickard Rakell      Ryan Getzlaf
Adam Henrique   Brandon Montour     Ryan Getzlaf
Adam Henrique   Corey Perry         Brandon Montour
Adam Henrique   Corey Perry         Brandon Montour
Adam Henrique   Brian Gibbons       Andy Greene
Adam Henrique   Ryan Getzlaf    
Adam Henrique   Ondrej Kase 
Adam Henrique   Josh Manson 
Adam Henrique   Brian Gibbons   
Adam Henrique       
Adam Henrique   

启动脚本

代码语言:javascript
复制
import csv
from itertools import combinations, product

#Header = PersonX PersonY PersonZ

#Import Game
with open('1718_All_Goals_&_Assists.csv', newline='') as f:
    next(f)
    skaters = '\n'.join(' '.join(row) for row in csv.reader(f))
    print(skaters)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-14 22:51:44

您只需在您的collections.Counter上使用csv.reader

代码语言:javascript
复制
from collections import Counter

>>> cnt = Counter(frozenset(item.strip() for item in line if item.strip()) for line in csv.reader(f))

您可以使用计数器的.most_common方法获得排序(降序)输出:

代码语言:javascript
复制
>>> cnt.most_common()
[(frozenset({'Aaron Ekblad', 'Denis Malgin', 'Mike Matheson'}), 2),
 (frozenset({'Aaron Ekblad', 'Jonathan Huberdeau', 'Keith Yandle'}), 2),
 (frozenset({'Adam Henrique', 'Brandon Montour', 'Corey Perry'}), 2),
 (frozenset({'Adam Henrique'}), 2),
 (frozenset({'Aaron Ekblad', 'Keith Yandle', 'Vincent Trocheck'}), 1),
 (frozenset({'Aaron Ekblad', 'Jamie McGinn', 'Keith Yandle'}), 1),
 (frozenset({'Aaron Ekblad', 'Aleksander Barkov', 'Jonathan Huberdeau'}), 1),
 (frozenset({'Aaron Ekblad'}), 1),
 (frozenset({'Adam Erne', 'Andrej Sustr', 'Vladislav Namestnikov'}), 1),
 (frozenset({'Adam Erne', 'Anthony Cirelli'}), 1),
 (frozenset({'Adam Erne'}), 1),
 (frozenset({'Adam Henrique', 'Rickard Rakell', 'Ryan Getzlaf'}), 1),
 (frozenset({'Adam Henrique', 'Brandon Montour', 'Ryan Getzlaf'}), 1),
 (frozenset({'Adam Henrique', 'Andy Greene', 'Brian Gibbons'}), 1),
 (frozenset({'Adam Henrique', 'Ryan Getzlaf'}), 1),
 (frozenset({'Adam Henrique', 'Ondrej Kase'}), 1),
 (frozenset({'Adam Henrique', 'Josh Manson'}), 1),
 (frozenset({'Adam Henrique', 'Brian Gibbons'}), 1)]

类似地,您可以使用以下方法获得最常见的(如果是关系,则只返回其中的一个):

代码语言:javascript
复制
>>> cnt.most_common(1)
[(frozenset({'Aaron Ekblad', 'Denis Malgin', 'Mike Matheson'}), 2)]

如果您想要拥有最大计数的所有内容,可以使用使用max的自定义方法

代码语言:javascript
复制
>>> maximum_occurences = max(cnt.values())
>>> [group for group, occurences in cnt.items() if occurences == maximum_occurences]
[frozenset({'Aaron Ekblad', 'Denis Malgin', 'Mike Matheson'}),
 frozenset({'Aaron Ekblad', 'Jonathan Huberdeau', 'Keith Yandle'}),
 frozenset({'Adam Henrique', 'Brandon Montour', 'Corey Perry'}),
 frozenset({'Adam Henrique'})]

要添加更多的解释:

Counter只对元素进行计数,这正是您想要的--但是要计数的值必须是可理解的。这是不方便的,因为csv.reader会返回列表(因为列表是不方便的),所以您需要另一个数据结构。

但是,tuples会出现在脑海中,因为您说名称可以按您可能想要的无序集合的任何顺序排列。这意味着您应该使用frozenset。但是有一个警告:它不能多次保存相同的值,所以如果您有同名的人,就不能使用它。

我不知道csv是如何构造的,因此很可能结果可能包含名称前后的空“列”或空白,这就是为什么我过滤空元素并用以下内容删除名称的原因:

代码语言:javascript
复制
item.strip() for item in line if item.strip()

在将其传递给frozenset之前。

如果您不喜欢它,strips两次,您可以添加另一个理解或map

代码语言:javascript
复制
frozenset(item for item in (item.strip() for item in line) if item)
frozenset(item for item in map(lambda x: x.strip(), line) if item)
frozenset(item for item in map(str.strip, line) if item)  # if all items are really of type str

顺便说一句,外部理解可以由filter替换为bool

代码语言:javascript
复制
frozenset(filter(bool, map(str.strip, line)))

哦,“函数式编程”的奇妙之处。我甚至还没用过itertools

我完全忘记了:如果您想省略单人组,那么在访问Counter组之前,您可以很容易地过滤most_common

代码语言:javascript
复制
cnt = Counter({k: v for k, v in cnt.items() if len(k) > 1})

这可以在后面应用,或者您可以尝试将其放入Counter内部的理解中,但我将把它作为一个练习留给感兴趣的读者。

如果您可以在一行中多次使用相同的名称,并且您不想丢失该“信息”,您可以在每一行中计数名称,然后将计数器转换为要计数的元组。

代码语言:javascript
复制
Counter(tuple(Counter(filter(bool, map(str.strip, line))).most_common()) for line in csv.reader(f))

我希望我没有对单线犯过头。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49806165

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档