我有一个带有项目列表的CSV,每个项目都附加了一系列属性:
"5","coffee|peaty|sweet|cereal|cream|barley|malt|creosote|sherry|sherry|manuka|honey|peaty|peppercorn|chipotle|chilli|salt|caramel|coffee|demerara|sugar|molasses|spicy|peaty"
"6","oil|lemon|apple|butter|toffee|treacle|sweet|cola|oak|cereal|cinnamon|salt|toffee"
"5"answers"6"都是项目id,在文件中是唯一的。
最后,我想创建一个矩阵,演示文档中每个属性与其他属性在同一行中被提及的次数。例如:
peaty sweet cereal cream barley ...
coffee 1 2 2 1 1
oil 0 1 0 0 0
请注意,我更喜欢减少重复:即,"peaty"既不是列又不是行。
原始数据库本质上是一个键值存储(一个列为"itemId"answers"value"的表)——如果有帮助,我可以重新格式化数据。
任何想法我如何做到这一点与Python, PHP或Ruby(无论哪个是最简单的)?我觉得Python可能是最简单的,但我错过了一些相当基本和/或关键的东西(我刚刚开始用Python做数据分析)。
谢谢!
Edit:"What have you tried"注释,这是我目前正在使用的(不要笑,我的Python很糟糕):
#!/usr/bin/python
import csv
matrix = {}
with open("field.csv", "rb") as csvfile:
csvreader = csv.reader(csvfile)
for row in csvreader:
attribs = row[1].split("|")
for attrib in attribs:
if attrib not in matrix:
matrix[attrib] = {}
for attrib2 in attribs:
if attrib2 in matrix[attrib]:
matrix[attrib][attrib2] = matrix[attrib][attrib2] + 1
else:
matrix[attrib][attrib2] = 1
print matrix
输出是一个大的、未排序的术语字典,可能在行和列之间有很多重复。如果我使用pandas并将"print matrix"行替换为以下行…
from pandas import *
df = DataFrame(matrix).T.fillna(0)
print df
我:
<class 'pandas.core.frame.DataFrame'>
Index: 195 entries, acacia to zesty
Columns: 195 entries, acacia to zesty
dtypes: float64(195)
…这让我觉得我做错了什么。
我将使用由2个字符串组成的元组作为键的计数器。当然,你会有两个组合,但到目前为止,我不知道如何避免这种情况:
from collections import Counter
from itertools import combinations
counter = Counter()
with open("field.csv", "rb") as csvfile:
csvreader = csv.reader(csvfile)
for row in csvreader:
attribs = row[1].split("|")
for cmb in itertools.combinations(attribs, 2):
counter[cmb] += 1
我会在无向图中这样做,其中频率是边的权重。然后,通过循环遍历每个顶点,可以很容易地生成矩阵,其中每个边的权重表示每个元素与另一个元素一起出现的次数。
图形文档:http://networkx.github.io/documentation/latest/reference/classes.graph.html
起动器代码:
import csv
import itertools
import networkx as nx
G = nx.Graph()
reader = csv.reader(open('field.csv', "rb"))
for row in reader:
row_elements = row[1].split("|")
combinations = itertools.combinations(row_elements, 2)
for (a, b) in combinations:
if G.has_edge(a, b):
G[a][b]['weight'] += 1
else:
G.add_edge(a, b, weight=1)
print(G.edges(data=True))
编辑:哇,看看这是否为你做了一切http://networkx.github.io/documentation/latest/reference/linalg.html#module-networkx.linalg.graphmatrix