Mic*_*son 8 excel python-itertools python-3.x
我有一个.csv包含3列.PersonX,PersonY和PersonZ.有7000行名称和不同的组合.我的目标是看看3对和3对是最高匹配.我无法在excel中找到能够实现这一目标的公式.我确定python能够与itertools组合,但我还没那么高级.名称可以是任何顺序,只是想看看那些2或3个人在同一行中的次数.任何建议都会有很大的帮助,谢谢!
数据的小例子.
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
Run Code Online (Sandbox Code Playgroud)
启动脚本
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)
Run Code Online (Sandbox Code Playgroud)
你可以简单地使用collections.Counter你的csv.reader:
from collections import Counter
>>> cnt = Counter(frozenset(item.strip() for item in line if item.strip()) for line in csv.reader(f))
Run Code Online (Sandbox Code Playgroud)
您可以使用.most_commonCounter 的方法获取排序(降序)输出:
>>> 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)]
Run Code Online (Sandbox Code Playgroud)
同样地,你可以使用这个来获得最常见的(如果是关系,它将只返回其中一个):
>>> cnt.most_common(1)
[(frozenset({'Aaron Ekblad', 'Denis Malgin', 'Mike Matheson'}), 2)]
Run Code Online (Sandbox Code Playgroud)
如果您想要所有具有最大计数的数据,您可以使用以下方法使用自定义方法max:
>>> 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'})]
Run Code Online (Sandbox Code Playgroud)
Counter只计算元素,这应该是你想要的 - 但要计数的值必须是可清除的.这csv.reader很不方便,因为会返回列表(因为列表不可用而不方便),所以你需要另一个数据结构.
tuples会想到,但是因为你说名字可能是任何顺序你可能想要一个无序的集合.这意味着你应该使用frozenset.但有一点需要注意:它不能多次保持相同的值,所以如果你有同名的人就不能使用它.
我不知道你的csv是如何构造的,所以结果可能包含空的"列"或名称之前/之后的空格,这就是我过滤空元素并剥离名称的原因:
item.strip() for item in line if item.strip()
Run Code Online (Sandbox Code Playgroud)
在传递给它之前frozenset.
如果您不喜欢它strips两次,您可以添加另一个理解或map:
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
Run Code Online (Sandbox Code Playgroud)
顺便说外修真然后可以被替代filter的bool:
frozenset(filter(bool, map(str.strip, line)))
Run Code Online (Sandbox Code Playgroud)
哦,"功能编程"的奇迹.而我甚至没有使用过itertools.
我完全忘记了:如果你想省略单人组,你可以Counter在访问most_common组之前轻松过滤掉:
cnt = Counter({k: v for k, v in cnt.items() if len(k) > 1})
Run Code Online (Sandbox Code Playgroud)
这可以在之后应用,或者你可以尝试将其融入到内部的理解中Counter,但我会把它留作感兴趣的读者的练习.
万一你可以在一行中多次使用相同的名称而你不想丢失那些"信息",你可以计算每行中的名字,然后将该计数器转换为一个将要计算的元组.
Counter(tuple(Counter(filter(bool, map(str.strip, line))).most_common()) for line in csv.reader(f))
Run Code Online (Sandbox Code Playgroud)
我希望我没有用单线来过度.
| 归档时间: |
|
| 查看次数: |
253 次 |
| 最近记录: |