知识图谱是一种用于表示和存储知识的图形化知识库,它描述了现实世界中实体、概念、实体间的关系以及属性等信息。知识图谱的构建需要从多个来源收集数据,并使用自然语言处理、机器学习等技术进行数据清洗、实体识别、关系抽取等处理,最终形成一个结构化的知识库。
微信搜索关注《Python学研大本营》,加入读者群,分享更多精彩
E.使用Cypher查询来探索推T的数据
在本部分中,将在上一部分中定义的图形模型上运行不同的Cypher查询,以提取不同主题的信息。
1.获取推文的总数。
从检查基本语法的热身查询开始。对于此查询,只关注原始推文,即不考虑回复、转推和引用:
MATCH (:User)-[:TWEETED_ORIGINAL]->(t:Tweet)
RETURN count(t) as TotalTweets
这个查询的结果是:10043
。因此,样本中总共有10043条原始推文。
2.获得标签的总数(不区分大小写)。
为了准确回答这个查询,必须使用几个函数。首先,使用DISTINCT
关键字,以便对每条tweet计数一次,然后使用“toLower
”函数,因为想要一个不区分大小写的结果:
MATCH (h:Hashtag)
RETURN count(DISTINCT toLower(h.hashtag))'
这个查询的结果是:12613
。因此,在样本中标签的数量多于原始推文。
3.按降序获得20个最受欢迎的URL。
在这个查询中,结果不是一个单一的值,就像到目前为止一样,但这不是问题:只需在RETURN
命令旁边添加想要返回的变量。
MATCH (:User)-[r:USED_URL]->(u:URL)
WITH u.url AS url, count(r) AS uses
ORDER BY uses DESC
LIMIT 20
RETURN url, uses
查询3的结果:按降序获得20个最受欢迎的URL。
这里值得注意的是,这些链接中有大量的是推T链接,而不是指向其他网站的链接。这可能表明推T上的用户可能更喜欢使用指向社交媒体本身的链接,而不是其他一些网站。
4.获取每个用户的粉丝数。
这里也采用了与前面查询类似的逻辑:
MATCH (u:User)
RETURN u.username as username,
u.userid as user_id,
u.followers_count as followers_count
这个查询的结果相当大,在下面的图片中展示了几个最多粉丝数的用户:
查询结果4:获取每个用户的粉丝数。仅展示前几个结果。
如图所示,可以说Elon Musk拥有最多的粉丝,以及许多其他名人和公司。这里需要注意的是,这些并不是所显示的用户的当前粉丝数,而是我样本中的用户和他们的粉丝数。
另一个有趣的现象是,从下面的Zipf
图可以看出,粉丝数的分布似乎是遵循幂律分布的:
样本中用户拥有的粉丝数的Zipf
图。由此产生的曲线非常接近直线,因此可以假设粉丝数遵循幂律分布。
可以看到,得出的线相当接近于一条直线。这证实了可能已经预料到的情况:有极少数人拥有非常多的粉丝,而大多数人的粉丝非常少(如果有的话)。这最后一部分在图的右下部分特别明显,我们看到有大量用户的粉丝数为个位数。
5.获取每小时推文和转发的数量。
为了得到这个结果,我们运行了以下Cypher查询:
CALL {
OPTIONAL MATCH (u:User)-[:TWEETED_ORIGINAL]->(t:Tweet)
WITH datetime(t.created_at).hour as hour,
count(*) as tweets,
0 as retweets
RETURN hour,
sum(tweets) as tweets,
sum(retweets) as retweets
ORDER BY hour ASC
UNION ALL
OPTIONAL MATCH (u:User)-[:RETWEETED]->(t:Tweet)
WITH datetime(t.created_at).hour as hour,
0 as tweets,
count(*) as retweets
RETURN hour,
sum(tweets) as tweets,
sum(retweets) as retweets
ORDER BY hour ASC
}
WITH hour, sum(tweets) as tweets, sum(retweets) as retweets
RETURN hour, tweets, retweets
ORDER BY hour ASC
上述查询的结果如下表:
查询5的结果:获取每小时的推文和转发数。
将这个结果可视化是很有意思的:
每小时推文和转发的数量(UTC)。
可以从这个图中提取一些结论:
-
首先,似乎全天的转发量一直多于推文。
-
世界标准时间15:00有一个明显的高峰,所以看起来用户的参与度在这个时间段和前后都是最大的。这是一个有用的结果,因为知道用户何时参与度最高,可以帮助公司进行任何促销活动,甚至可以帮助知道何时发布,以便获得最多转发。
-
用户参与度(按每小时(转发)推文数量量化),似乎从凌晨2点左右到15点稳步上升,然后慢慢下降。
6.获得回复最多的用户。
对于此查询,正在寻找在推文中拥有最多回复的用户,无论他们的推文是原创的、转推的、回复的还是引用的。
MATCH (u:User)-[:TWEETED_ORIGINAL|RETWEETED|REPLIED|QUOTED]->(t:Tweet)
WITH u, SUM(t.reply_count) AS total_replies
RETURN u.userid as UserID, u.username AS Username, total_replies as Total_Replies
ORDER BY total_replies DESC
LIMIT 1
这个查询的结果是用户ID为3939574932
的用户,用户名为FightHaven
,总回复数为44611
。这里令人印象深刻的是,这个用户的回复总数是样本中原始推文数量的4倍多。
7.获取与使用最多的标签共同出现的前20个标签。
MATCH (t:Tweet)-[:HAS_HASHTAG]->(h:Hashtag)
WITH h.hashtag AS main_hashtag,
collect(DISTINCT t.tweet_id) AS main_tweet_ids
ORDER BY size(main_tweet_ids) DESC LIMIT 1
MATCH (t:Tweet)-[:HAS_HASHTAG]->(h:Hashtag)
WHERE h.hashtag <> main_hashtag AND t.tweet_id IN main_tweet_ids
WITH h.hashtag AS co_hashtag,
count(DISTINCT t.tweet_id) AS co_occurrences,
main_hashtag
ORDER BY co_occurrences DESC LIMIT 20
RETURN main_hashtag, co_hashtag, co_occurrences
这个查询的结果是:
查询7的结果:获取与使用最多的标签共同出现的前20个标签。
这里有点令人惊讶的是,javascript
标签似乎远远高于python
标签。这看起来令人惊讶的原因是,一般来说,python
是最受欢迎的编程语言之一,特别是在初学者中。
鉴于使用最多的标签是womenintech
,这可能意味着科技界的女性可能更喜欢前端开发和使用Javascript而不是python或数据科学。
8.获取数据集中“最重要”的用户(使用图算法:Pagerank
, Betweenness centrality
等)。将在提及网络(包括转推)中应用这些算法。
对于这个查询,本文将提供完整的Python代码,而不是仅仅提供Cypher查询,因为它有点复杂,所以决定使用Pagerank
算法来寻找数据集中的“最重要”用户:
create_graph_query = """
CALL gds.graph.project(
'pageRankGraph',
'User',
{
MENTIONED: {
type: 'MENTIONED',
orientation: 'NATURAL'
}
}
)
"""
pagerank_query = """
CALL gds.pageRank.stream('pageRankGraph')
YIELD nodeId, score
WITH nodeId, score
ORDER BY score DESC
MATCH (u:User)
WHERE id(u) = nodeId
WITH u.username AS username, MAX(score) AS max_score
RETURN DISTINCT username, max_score
"""
session.run(create_graph_query)
result = session.run(pagerank_query)
display(pd.DataFrame(result.data()))
查询的结果是:
查询8的结果:获取数据集中“最重要”的用户。
从这个结果中也可以看出一个有用的启示:在所使用的样本中,似乎“最重要”的用户是用户名为cryptosanthoshK
的用户。从之前的查询中看到,拥有最多粉丝的用户是Elon Musk
,但根据Pagerank
的说法,他似乎没有像上述用户那样被提及。这很有意思,因为它表明一个人拥有的粉丝数量可能并不像(例如)推文质量或喜欢在推T上谈论的话题那样,是一个强有力的预测因素。
9.对于第5个最重要的用户,获取已经发布的标签和URL列表(如果没有标签或URL——检查另一个用户,例如第6个、第7个等等)。
对于此查询,使用了第4个“最重要”的用户CatherineAdenle
,因为第5个只有2个主题标签并且没有URL。运行了以下查询:
MATCH (u1:User)-[:USED_HASHTAG]->(u1_hashtag:Hashtag)
WHERE u1.username = "CatherineAdenle"
RETURN DISTINCT u1_hashtag.hashtag AS output
UNION ALL
MATCH (u1:User)-[:USED_URL]->(u1_url:URL)
WHERE u1.username = "CatherineAdenle"
RETURN DISTINCT u1_url.url AS output
上述查询的结果是:
查询结果9:对于第5个最重要的用户,获取已经发布的标签和URL的列表(如果没有标签或URL——检查另一个用户,例如第6个,第7个等等)。
可以看到这个用户似乎对科技非常感兴趣,因为他们所有的推文都是围绕科技展开的。此外,他们似乎几乎只使用推T中的URL。
10.获取基于用户互动而创建的用户社区,并将其可视化(Louvain
算法)。
将再次展示整个Python代码:
create_graph_query = """
CALL gds.graph.project(
'louvainGraph',
['User'],
['MENTIONED', 'TWEETED_ORIGINAL', 'USED_HASHTAG', 'USED_URL']
)
"""
louvain_query = """
CALL gds.louvain.write('louvainGraph', {writeProperty: 'community'})
YIELD communityCount, modularity, modularities
"""
session.run(create_graph_query)
result = session.run(louvain_query)
communities = pd.DataFrame(result.data())
print(communities)
结果是:
查询结果10:获取基于用户互动而创建的用户社区,并将其可视化(Louvain算法)。
可以看到Louvain
的算法找到了4007个社区。可以在这里看到它们的可视化:
Louvain算法基于用户互动而创建的用户社区的可视化。
为了实现这一结果的可视化,利用了Neo4j Bloom,它可以通过Neo4j Desktop的左侧功能区的“Graph Apps”进行访问。这是一个图形可视化工具,可以用来快速探索并与Neo4j图形模型互动。更具体地说,可以根据一些属性给正在探索的图的节点着色。
在我们的案例中,我们用来给图着色的属性是Louvain
算法的结果。因此,每种颜色代表不同的社区,但值得注意的是,颜色的数量是有限制的(100种),由于已经检测到4007个社区,Neo4j Bloom对不同的社区使用相同的颜色。这在GUI中是很明显的,只是在截图中没有体现出来。
11.[EXTRA-1]获取2022年期间发布推文最多的前10名用户。为了计算一条推文,它应该至少包含所有时间内最常用的前5个标签中的一个。
MATCH (u:User)-[:TWEETED_ORIGINAL]->(t:Tweet)-[:HAS_HASHTAG]->(h:Hashtag)
WITH h, count(DISTINCT h) AS hashtag_count
ORDER BY hashtag_count DESC
LIMIT 5
WITH collect(h) AS top_hashtags
MATCH (u:User)-[:TWEETED_ORIGINAL]->(t:Tweet)-[:HAS_HASHTAG]->(h:Hashtag)
WHERE h IN top_hashtags AND datetime(t.created_at) >= datetime('2022-01-01T00:00:00.000Z') AND datetime(t.created_at) < datetime('2023-01-01T00:00:00.000Z')
WITH u, count(DISTINCT t) AS tweet_count
ORDER BY tweet_count DESC
LIMIT 10
RETURN u.username, tweet_count
该查询的结果是:
额外查询1(11)的结果:获取2022年期间发推文最多的前10名用户。为了计算一条推文,它应该至少包含所有时间内最常用的前5个标签中的一个。
可以看到,前三名和其他用户之间的推文数量(计算它们的方式)似乎有比较大的差异。此外,有趣的是,可以看到结果中主要包括来自推T的科技界女性用户,这很有意义,因为正如之前看到的,使用最多的标签是#womenintech
。
12.[EXTRA-2]获取平均每日最小推文数大于总用户平均每日推文数的用户。只有每天发 2 条以上推文的用户才会被用来计算每天的平均推文数量。
MATCH (u:User)-[:TWEETED_ORIGINAL]->(t:Tweet)
WITH u, count(t) as numTweets, date(datetime(t.created_at)) as tweetDate
WITH u, numTweets, min(tweetDate) as minTweetDate, max(tweetDate) as maxTweetDate
WITH u, numTweets, duration.between(minTweetDate, maxTweetDate).days + 1 as numDays
WITH u, numTweets / toFloat(numDays) as tweetsPerDay
WITH u, min(tweetsPerDay) as minTweetsPerDay
CALL {
MATCH (u:User)-[:TWEETED_ORIGINAL]->(t:Tweet)
WITH u, count(t) as numTweets, date(datetime(t.created_at)) as tweetDate
WITH u, numTweets, min(tweetDate) as minTweetDate, max(tweetDate) as maxTweetDate
WITH u, numTweets, duration.between(minTweetDate, maxTweetDate).days + 1 as numDays
WITH u, numTweets / toFloat(numDays) as tweetsPerDay
WHERE numTweets > 1
WITH avg(tweetsPerDay) as totalAvgTweetsPerDay
RETURN totalAvgTweetsPerDay
}
with minTweetsPerDay, totalAvgTweetsPerDay, u.username as username
WHERE minTweetsPerDay > totalAvgTweetsPerDay
RETURN username, minTweetsPerDay
ORDER BY minTweetsPerDay DESC
这个查询的结果是:
查询12的结果:获取平均每日最小推文数大于总用户平均每日推文数的用户。只有每天发 2 条以上推文的用户才会被用来计算每天的平均推文数量。
在这里注意到此查询的顶级用户与其他用户之间的巨大差异令人印象深刻!
推荐书单
《Python数据分析从入门到精通》
《Python数据分析从入门到精通》全面介绍了使用Python进行数据分析所必需的各项知识。全书共分为14章,包括了解数据分析、搭建Python数据分析环境、Pandas统计分析、Matplotlib可视化数据分析图表、Seaborn可视化数据分析图表、第三方可视化数据分析图表Pyecharts、图解数组计算模块NumPy、数据统计分析案例、机器学习库Scikit-Learn、注册用户分析(MySQL版)、电商销售数据分析与预测、二手房房价分析与预测,以及客户价值分析。
该书所有示例、案例和实战项目都提供源码,另外该书的服务网站提供了模块库、案例库、题库、素材库、答疑服务,力求为读者打造一本“基础入门+应用开发+项目实战”一体化的Python数据分析图书。
《Python数据分析从入门到精通》内容详尽,图文丰富,非常适合作为数据分析人员的学习参考用书,也可作为想拓展数据分析技能的普通职场人员和Python开发人员学习参考用书。
精彩回顾
《知识图谱并不难,用Neo4j和Python打造社交图谱(中)》
《知识图谱并不难,用Neo4j和Python打造社交图谱(上)》
微信搜索关注《Python学研大本营》,加入读者群
访问【IT今日热榜】,发现每日技术热点