将项目数据转换为关系矩阵

时间:2012-09-29 18:37:48

标签: python matrix social-networking stata

我的数据设置了一起工作或单独工作的人员列表。

每个项目都有一行,列中包含所有参与该项目的人员的姓名。如果第2列是给定行的第一个空列,那么它是一个独奏作业,如果第4列是给定行的第一个空列,则有3个人一起工作。

我的目标是找到哪些人一起工作,多少次,所以我想要数据集中的所有对,处理A与B一起使用与使用A的B相同。

由此创建一个正方形N x N,每个参与者标记列和行,并且单元格(A,B)和(B,A)将具有该对一起工作的次数,这将完成对于每一对。

我知道在Excel中使用“漂亮”的快捷方式,但我希望它能自动化,希望在Stata或Python中,以防万一添加或删除项目我只需单击重新运行即可每次都要重新做。

以逗号分隔方式的数据示例:

A
A,B
B,C,E
B,F
D,F
A,B,C
D,B
E,C,B
X,D,A

希望有所帮助!

布莱斯。     楼d     乙     F     F,X,C     C,F,d

4 个答案:

答案 0 :(得分:1)

也许这样的事情会让你开始?

import csv
import collections
import itertools

grid = collections.Counter()

with open("connect.csv", "r", newline="") as fp:
    reader = csv.reader(fp)
    for line in reader:
        # clean empty names
        line = [name.strip() for name in line if name.strip()]
        # count single works
        if len(line) == 1:
            grid[line[0], line[0]] += 1
        # do pairwise counts
        for pair in itertools.combinations(line, 2):
            grid[pair] += 1
            grid[pair[::-1]] += 1

actors = sorted(set(pair[0] for pair in grid))

with open("connection_grid.csv", "w", newline="") as fp:
    writer = csv.writer(fp)
    writer.writerow([''] + actors)
    for actor in actors:
        line = [actor,] + [grid[actor, other] for other in actors]
        writer.writerow(line)

[编辑:修改为在Python 3.2下工作]

关键模块是(1)csv,这使得读写csv文件更加简单; (2)collections,它提供了一个名为Counter的对象 - 就像defaultdict(int)一样,如果你的Python没有Counter就可以使用它,它是一个字典它会自动生成默认值,因此您不需要,默认计数为0;和(3)itertools,它具有combinations函数来获取所有对。

产生

,A,B,C,D,E,F,X
A,1,2,1,1,0,0,1
B,2,1,3,1,2,1,0
C,1,3,0,1,2,2,1
D,1,1,1,0,0,3,1
E,0,2,2,0,0,0,0
F,0,1,2,3,0,1,1
X,1,0,1,1,0,1,0

您可以使用itertools.product使阵列构建更紧凑,但由于它只有一两行,我认为手动操作非常简单。

答案 1 :(得分:0)

如果我要保持这个项目一段时间,我会实现一个数据库,然后根据对该数据库的查询创建你正在谈论的矩阵。

你有一个Project表(比方说),每个项目有一个记录,一个Actor表,每人一行,一个Participant表,每个项目有一个记录那个项目中的演员。 (每条记录都有IDProjectIDActorID。)

在您的示例中,您将拥有14条Project条记录,7条Actor条记录(A至F和X)以及31条Participant条记录。

现在,通过此设置,每个单元格都是对此数据库的查询。

要重建矩阵,首先要在数据库中添加/更新/删除相应的记录,然后重新运行查询。

答案 2 :(得分:0)

我建议使用Python Pandas。它可以为您的邻接矩阵格式化提供灵活的解决方案,它也可以使任何统计计算更容易。您还可以直接将值矩阵提取到NumPy数组中,以便稍后在需要时对组群进行特征值分解或其他图论理论过程。

我假设你列出的示例数据被保存到一个名为projects_data.csv的文件中(虽然它不需要实际上是.csv文件)。我还假设每个观察结果之间没有空行,但这只是文件组织的详细信息。

这是我的代码:

# File I/O part
import itertools, pandas, numpy as np
with open("projects_data.csv") as tmp:
    lines = tmp.readlines()
lines = [line.split('\n')[0].split(',') for line in lines]
# Unique letters
s = set(list(itertools.chain(*lines)))


# Actual work.
df = pandas.DataFrame(
                      np.zeros((len(s),len(s))), 
                      columns=sorted(list(s)), 
                      index=sorted(list(s))
                     )

for line in lines:
    if len(line) == 1:
        df.ix[line[0],line[0]] += 1 # Single-person projects
    elif len(line) > 1:
        # Get all pairs in multi-person project.
        tmp_pairs = list(itertools.combinations(line, 2))

        # Append pair reversals to update (i,j) and (j,i) for each pair.
        tmp_pairs = tmp_pairs + [pair[::-1] for pair in tmp_pairs]
        for pair in tmp_pairs:
            df.ix[pair[0], pair[1]] +=1
            # Uncomment below if you don't want the list
            # comprehension method for getting the reverals.
            #df.ix[pair[1], pair[0]] +=1 

# Final product
print df.to_string()

   A  B  C  D  E  F  X
A  1  2  1  1  0  0  1
B  2  1  3  1  2  1  0
C  1  3  0  1  2  2  1
D  1  1  1  0  0  3  1
E  0  2  2  0  0  0  0
F  0  1  2  3  0  1  1
X  1  0  1  1  0  1  0

现在你可以免费做很多事情,比如查看每个参与者的项目合作伙伴总数(包括重复项):

>>> df.sum()
A     6
B    10
C    10
D     7
E     4
F     8
X     4

答案 3 :(得分:0)

我猜你在这些项目中没有成千上万的人在一起工作。这个实现非常简单。

fp = open('projects.cvs')

# counts how many times each pair worked together
pairs = {}

# each element of `project` is a person
for project in (p[:-1].split(',') for p in fp):
    project.sort()

    # someone is alone here
    if len(project) == 1:
        continue

    # iterate over each pair 
    for i in range(len(project)):
        for j in range(i+1, len(project)):
            pair = (project[i], project[j])
            # increase `pairs` counter
            pairs[pair] = pairs.get(pair, 0) + 1

from pprint import pprint
pprint(pairs)

输出:

{('A', 'B'): 1,
 ('B', 'C'): 2,
 ('B', 'D'): 1,
 ('B', 'E'): 1,
 ('B', 'F'): 2,
 ('C', 'E'): 1,
 ('C', 'F'): 1,
 ('D', 'F'): 1}