社会网络分析《平凡的世界》-Python实现(二)

社交媒体充斥着我们生活的时代,其已经成为了人们交流、获取信息、建立关系的重要平台。无论是微信、微博、抖音等,还是其他社交媒体,都构成了庞大而复杂的社交网络。在这个网络中,我们关注着各种KOL(Key Opinion Leader,关键意见领袖),同时也有自己的粉丝,形成了一个错综复杂的社交关系网。随着时间的推移,这个关系网络不断壮大,关注和粉丝数量逐渐增加。这个网络不仅仅是我们个人的社交圈子,更是信息传播的重要渠道。通过社交网络,我们可以了解到各种新闻、热点话题、产品信息等,而且这些信息的传播速度之快常常令人惊叹。因此,分析这些社交网络对于了解我们的行为,以及做出决策来说至关重要。

一、爬取《平凡的世界》(162个文本文件)

注意:爬取分两部分,一部分是完整书格式:world1.txt;一部分为章格式:第三部 第49章.txt。

import os
import time
import requests
from bs4 import BeautifulSoup

def scrape_and_save_content(url, folder_path):
    # Make a request
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
    response = requests.get(url=url, headers=headers)
    
    # Set encoding
    response.encoding = 'utf-8'
    
    # Parse HTML
    soup = BeautifulSoup(response.text, 'lxml')
    
    # Get chapter title
    chapter_title = soup.find('h1').get_text()
    print(chapter_title)
    
    # Get paragraph content
    paragraphs = soup.find_all('p')
    content = ""
    for paragraph in paragraphs:
        if '下一章' in paragraph.get_text():
            break
        content += paragraph.get_text().replace('S*锓', '') + '\n'
    
    # Write content to file
    filename = f'{chapter_title}.txt'
    with open(os.path.join(folder_path, filename), 'w', encoding='utf-8') as f:
        f.write(content)

# Start time
starttime = time.time()
print(starttime)

# Create a new folder
folder_path = "E:/Python/Ordinary_world_1/"  #文件保存目录,可修改!!!
os.makedirs(folder_path, exist_ok=True)

# Loop through categories and chapters
categories = ['yi', 'er', 'san']
for category in categories:
    for chapter_num in range(1, 55):
        # Construct URL
        url = f'http://www.pingfandeshijie.net/di-{category}-bu-{chapter_num:02d}.html'
        
        # Scrape and save content
        scrape_and_save_content(url, folder_path)

# End time
endtime = time.time()
print(endtime)

# Total program execution time
print(round(endtime - starttime, 2))

二、获取主要人物

从网上诸如电视剧人物介绍中提取相关人物,命名为name.txt,放入Python当前工作路径里,以便后面程序使用。这里收集了69个人物,数据结构见图1。

图1 图2

三、生成词云图

import os
import random
import numpy as np
import matplotlib.pyplot as plt
from wordcloud import WordCloud

# 打开文件
def open_file(filename):
    with open(filename, encoding='utf-8') as file:
        return file.readlines()

# 提取人物信息
def extract_names(filename):
    names = []
    for name in open_file(filename):
        names.append(name.strip())
    return names

# 提取文本信息
def extract_content(filename):
    return open_file(filename)

# 统计人物出现频数
def count_frequency(names, content):
    data = []
    for name in names:
        num = sum(1 for line in content if name in line)
        data.append((name, num))
    return data

# 生成词云
def generate_wordcloud(data):
    def random_color_func(word=None, font_size=None, position=None, orientation=None, font_path=None, random_state=None):
        h, s, l = random.choice([(188, 72, 53), (253, 63, 56), (12, 78, 69)])
        return "hsl({}, {}%, {}%)".format(h, s, l)

    x, y = np.ogrid[:1500,:1500]
    mask = (x - 700) ** 2 + (y - 700) ** 2 > 700 ** 2
    mask = 255 * mask.astype(int)

    wc = WordCloud(
        background_color='white',
        mask=mask,
        font_path='simhei.ttf',  # 使用中文字体
        max_words=2000,
        max_font_size=250,
        min_font_size=15,
        color_func=random_color_func,
        prefer_horizontal=1,
        random_state=50
    )

    word_freq = {name: freq for name, freq in data}
    wc.generate_from_frequencies(word_freq)

    plt.imshow(wc)
    plt.axis('off')
    plt.show()

    wc.to_file("平凡的世界.jpg")
    print('生成词云成功!')

if __name__ == "__main__":
    # 提取人物信息
    names = extract_names('name.txt')
    # 提取文本信息
    content = extract_content('world1.txt')
    # 统计人物出现频数
    data = count_frequency(names, content)
    # 生成词云
    generate_wordcloud(data)

四、获得社交网络数据

为可视化《平凡的世界》为例的人物关系,定义​​两两人物关系采用以下两种方式:两个人名同时出现在同一段落,则联系+1;​②两个人名同时出现在同一章节,则联系+1。​​接下来利用前面爬取的文本文件,生成社交网络数据包。

import os
import pandas as pd

# 打开文本
file_text = open('world1.txt', encoding='utf-8')
file_name = open('name.txt', encoding='utf-8')

# 人物信息
names = []
for name in file_name:
    names.append(name.replace('\n', ''))

# 文本信息
content = []
for line in file_text:
    content.append(line)

# 生成下标
flags = [x * 0 for x in range(len(names))]

# 生成人物联系
data = []
for a in range(len(names)):
    flags[a] = 1
    name_1 = names[a]
    for b in range(len(names)):
        if flags[b] == 0:
            name_2 = names[b]
            # 为三个字符时,取名字
            if len(name_1) == 3:
                name_1 = name_1[1:]
            if len(name_2) == 3:
                name_2 = name_2[1:]
            # 遍历章节及段落
            num1, num2 = 0, 0
            for i in os.listdir('E:\Python\Ordinary_world_1'):
                with open('E:\Python\Ordinary_world_1\\' + i, encoding='utf-8') as worldFile:
                    worldContent = worldFile.read()
                    if (name_1 in worldContent) and (name_2 in worldContent):
                        num1 += 1
            for j in content:
                if (name_1 in j) and (name_2 in j):
                    num2 += 1
            if num1 != 0 and num1 >= 3 and num2 >= 2:
                data.append([names[a], names[b], num1, num2])

# 将数据转换为DataFrame
df = pd.DataFrame(data, columns=['姓名1', '姓名2', '章中出现次数', '段落中出现次数'])

# 将DataFrame写入Excel文件
df.to_excel('weight.xlsx', index=False)

五、可视化社交网络

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt

# 显示中文,及字体设置
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['font.size'] = 10
plt.rcParams['axes.unicode_minus'] = False

# 读取文件
df = pd.read_excel('weight.xlsx', header=None, names=['First', 'Second', 'chapweight', 'duanweight'])
print(df.head())

# 将 'chapweight' 列中的字符串转换为数值型数据
df['chapweight'] = pd.to_numeric(df['chapweight'], errors='coerce')

# 计算段落人物关系权重
df['weight'] = df['chapweight'] / 162  #书总计162章

# 获取联系大于4的数据,重新生成索引
df2 = df[df.weight > 0.025].reset_index(drop=True)
plt.figure(figsize=(12, 12))

# 生成社交网络图
G = nx.Graph()

# 添加边
for ii in df2.index:
    G.add_edge(df2.First[ii], df2.Second[ii], weight=df2.weight[ii])

# 定义3种边,大于32,16-32,小于16
elarge = [(u, v) for (u, v, d) in G.edges(data=True) if (d['weight'] > 0.2)]
emidle = [(u, v) for (u, v, d) in G.edges(data=True) if (d['weight'] > 0.1) & (d['weight'] <= 0.2)]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if (d['weight'] <= 0.1)]

# 图的布局
# 节点在一个圆环上均匀分布
pos = nx.circular_layout(G)

# 点
nx.draw_networkx_nodes(G, pos, alpha=0.6, node_size=350)

# 边
nx.draw_networkx_edges(G, pos, edgelist=elarge, width=2, alpha=0.9, edge_color='g')
nx.draw_networkx_edges(G, pos, edgelist=esmall, width=1, alpha=0.3, edge_color='b', style='dashed')

# 标签
nx.draw_networkx_labels(G, pos, font_size=10)

# 生成结果
plt.axis('off')
plt.title('平凡的世界')
plt.show()

# 计算每个节点的重要程度
Gdegree = nx.degree(G)
Gdegree = dict(Gdegree)
Gdegree = pd.DataFrame({'name': list(Gdegree.keys()), 'degree': list(Gdegree.values())})
# 第一张图,所有人物
#Gdegree.sort_values(by='degree', ascending=False).plot(x='name', y='degree', kind='bar', color=(136/255, 43/255, 48/255), figsize=(12, 6), legend=False)
# 第二张图,前20人物
Gdegree.sort_values(by='degree', ascending=True)[-20:].plot(x='name', y='degree', kind='barh', color=(16/255, 152/255, 168/255), figsize=(12, 6), legend=False)
plt.xticks(size=8)
# 第一张图标签
# plt.ylabel('degree')
# 第二张图标签
plt.ylabel('name')
plt.show()
图3 图4
20个最大的度人物

总结

社交网络不仅是我们日常生活中的重要组成部分,也是我们获取信息、建立关系、进行互动的重要平台。通过对社交网络的分析,我们可以更好地了解社交关系、把握信息传播规律、满足用户需求,从而更好地做出各项决策,提升我们的社交体验和生活质量。
首先,通过分析社交网络中的关系,我们可以更好地了解自己的社交圈子,找到我们最感兴趣的内容和人群。比如,通过分析我们的关注列表和粉丝列表,我们可以发现哪些KOL拥有更大的影响力,哪些朋友更可能成为我们的忠实支持者,从而更有针对性地选择我们关注的内容,提升我们的社交体验。其次,社交网络也是一个信息传播的重要平台。通过社交网络,我们可以迅速了解到各种热点事件、新闻资讯和产品推广。而且,这些信息常常是通过我们的朋友或者KOL传播给我们的,具有更高的可信度和影响力。因此,对社交网络中信息的传播规律进行分析,可以帮助我们更好地了解信息的来源、传播路径和影响范围,从而更准确地判断信息的真实性和重要性。最后,社交网络也是一个互动的平台。通过社交网络,我们可以和朋友、KOL以及其他用户进行实时的交流和互动。通过分析社交网络中的互动行为,我们可以更好地了解用户的需求和偏好,从而更有针对性地制定营销策略、推广产品和服务。

参考文献

  1. 利用Python将社交网络进行可视化
  2. Python数据可视化:平凡的世界
  3. Python人物社交网络分析—平凡的世界

自我中心网络(Ego Network)

1.1 网络虚假数据生成

鉴于社交数据涉及个人隐私信息,数据需要脱敏,所以采用Python库Faker虚构了下面的社交数据,描述个人社交关系,数据结构如下图所示。

import csv
from faker import Faker

# 初始化Faker
fake = Faker()

# 打开一个文件以写入数据
with open('Connections.csv', 'w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)

    # 写入标题行
    writer.writerow(['first Name', 'last Name', 'company', 'position', 'connected on'])

    # 生成500行数据
    for _ in range(500):
        # 使用Faker生成假数据
        first_name = fake.first_name()
        last_name = fake.last_name()
        company = fake.company()
        position = fake.job()
        connected_on = fake.date_between(start_date='-5y', end_date='today').isoformat()

        # 写入生成的行数据
        writer.writerow([first_name, last_name, company, position, connected_on])

1.2 自我中心网络展示

import pandas as pd
from pyvis import network as net
import networkx as nx

# 读取数据集
df_ori = pd.read_csv("Connections.csv")

# 查看数据框的列名和前几行数据
print(df_ori.columns)
print(df_ori.head())

# 数据清洗和预处理
df = (
    pd.DataFrame(df_ori)  # 将df_ori转换为DataFrame对象
    .dropna()  # 去除掉空值
)

# 统计公司和职位信息
df_company = df['company'].value_counts().reset_index()
df_company.columns = ['company', 'count']
df_company = df_company.sort_values(by="count", ascending=False)

# 实例化网络
g_company = nx.Graph()

# 遍历公司数据集
for _, row in df_company.iterrows():
    company = row['company']
    count = row['count']
    positions = set(df[df['company'] == company]['position'])
    hover_info = f"<b>{company}</b> – {count}<ul>{''.join(f'<li>{x}</li>' for x in positions)}</ul>"
    g_company.add_node(company, size=count * 2, title=hover_info, color='#3449eb')
    g_company.add_edge('myself', company, color='grey')  # 使用 "myself" 作为中心节点

# 生成公司网络图表
nt_company = net.Network(height='700px', width='700px', bgcolor="black", font_color='white')
nt_company.from_nx(g_company)
nt_company.hrepulsion()

# 保存公司网络图表为HTML文件
nt_company.save_graph('company_graph.html')

# 实例化网络
g_position = nx.Graph()

# 统计职位信息
df_position = df['position'].value_counts().reset_index()
df_position.columns = ['position', 'count']

# 遍历职位数据集
for _, row in df_position.iterrows():
    position = row['position']
    count = row['count']
    companies = set(df[df['position'] == position]['company'])
    hover_info = f"<b>{position}</b> – {count}<ul>{''.join(f'<li>{x}</li>' for x in companies)}</ul>"
    g_position.add_node(position, size=count * 2, title=hover_info, color='#3449eb')
    g_position.add_edge('myself', position, color='grey')  # 使用 "myself" 作为中心节点

# 生成职位网络图表
nt_position = net.Network(height='700px', width='700px', bgcolor="black", font_color='white')
nt_position.from_nx(g_position)
nt_position.hrepulsion()

# 保存职位网络图表为HTML文件
nt_position.save_graph('position_graph.html')

posted @   郝hai  阅读(410)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示