我试图从规范化的SQLite数据库中获取网络边缘的数量,该数据库已经规范化如下:
Authors Paper Paper_Authors
| authorID | name | etc | paperID | title | etc | paperID | authorID |
| 1 | .... | ... | 1 | ..... | ... | 1 | 1 |
| 2 | .... | ... | 2 | ..... | ... | 1 | 2 |
| 3 | .... | ... | . | ..... | ... | 1 | 3 |
| 4 | .... | ... | 60,000 | ..... | ... | 2 | 1 |
| 5 | .... | ... | 2 | 4 |
| . | .... | ... | 2 | 5 |
| 120,000 | .... | ... | . | . |
| 60,000 | 120,000 |
在120,000作者和60,000篇论文的某个地方,索引表有大约250,000行。
我正在尝试将其转换为networkX以进行一些连接分析,输入节点很简单:
conn = sqlite3.connect('../input/database.sqlite')
c = conn.cursor()
g = nx.Graph()
c.execute('SELECT authorID FROM Authors;')
authors = c.fetchall()
g.add_nodes_from(authors)
我遇到的问题来自于尝试确定要提供给networkX的边缘,这需要连接两个节点的元组中的值,使用上面的数据作为示例;
[(1,1),(1,2),(1,3),(2,3),(1,4),(1,5),(4,5)]
将描述上面的数据集。
我有以下代码,它有效,但不太优雅:
def coauthors(pID):
c.execute('SELECT authorID \
FROM Paper_Authors \
WHERE paperID IS ?;', (pID,))
out = c.fetchall()
g.add_edges_from(itertools.product(out, out))
c.execute('SELECT COUNT() FROM Papers;')
papers = c.fetchall()
for i in range(1, papers[0][0]+1):
if i % 1000 == 0:
print('On record:', str(i))
coauthors(i)
这是通过循环遍历数据库中的每个论文,返回作者列表并迭代地创建作者组合元组列表并以零碎的方式将它们添加到网络中,这可行,但需要30-45分钟:
print(nx.info(g))
Name:
Type: Graph
Number of nodes: 120670
Number of edges: 697389
Average degree: 11.5586
所以我的问题是,是否有一种更优雅的方式来获得相同的结果,理想情况下使用paperID作为边缘标签,以便更容易在networkX之外导航网络。
答案 0 :(得分:2)
您可以通过自我加入获得每篇论文作者的所有组合:
SELECT paperID,
a1.authorID AS author1,
a2.authorID AS author2
FROM Paper_Authors AS a1
JOIN Paper_Authors AS a2 USING (paperID)
WHERE a1.authorID < a2.authorID; -- prevent duplicate edges
除非paperID
或更好,paperID
和authorID
都有covering index,或者更好,{{3},否则这将非常低效}}