现在有个xlsx文件,文件名是similar05.xlsx,共三列,无列名,第一列和第二列都是对象名,出自同一组对象,第三列是对象之间的jaccard相似度系数,请编写python代码,绘制相似度网络图:以对象为节点,以对象之间边的粗细为相似度,在图上显示节点名即为similar05.xlsx中第一、第二列的对象名称,显示边的粗细即为similar05.xlsx中第三列相似度的数值。
时间: 2025-07-23 10:06:47 浏览: 1
<think>我们已知用户的需求是:读取similar05.xlsx文件,该文件包含三列(对象A、对象B、Jaccard相似度),然后绘制网络图,节点为对象名称,边的粗细表示相似度大小,并正确显示节点标签。
步骤:
1. 读取Excel文件:使用pandas读取,确保列名正确(对象A、对象B、相似度)
2. 创建图:使用networkx,节点为对象A和对象B,边带有权重(即相似度)
3. 绘制网络图:使用spring_layout布局,节点显示名称(设置with_labels=True),边的粗细根据相似度调整(乘以一个缩放因子,因为原始相似度可能在0~1之间,直接作为线宽可能太细)
注意:用户特别要求显示节点标签,所以我们在绘制时一定要设置`with_labels=True`,并且可以调整字体大小等。
另外,由于相似度可能为0,但我们通常不会画0相似度的边,所以如果数据中有0,可以考虑过滤掉。不过用户数据中可能没有0,我们按原数据处理。
我们将使用以下步骤绘制:
- 创建一个无向图(因为相似度是无向的)
- 添加边(同时添加节点),边权为相似度
- 绘制时,边的宽度用相似度乘以一个放大因子(比如10或20,以便在图中清晰显示)
同时,为了美观,我们可以:
- 设置节点大小、颜色
- 设置标签字体
另外,注意中文显示问题:设置中文字体,避免乱码。
我们将使用matplotlib进行绘图,并确保中文字体正确显示。
具体代码步骤:
1. 读取Excel文件
2. 创建图并添加边
3. 设置布局
4. 绘制节点
5. 绘制边(根据权重设置宽度)
6. 绘制节点标签
7. 显示或保存图像
由于之前代码中已经有一个读取Excel和创建图的函数,我们可以在此基础上修改。
但是,为了确保清晰,我们将重新编写一个完整的代码,并添加详细注释。
注意:用户要求节点显示对象名称,所以我们在绘制节点时,必须将节点标签设置为对象名称。
我们将使用`nx.draw_networkx_labels`来绘制标签,或者更简单的方法是使用`nx.draw`中的`with_labels=True`参数。
但是,为了更灵活地控制标签,我们可能会分别绘制节点、边和标签。
以下是完整的代码:</think>我将为您创建一个基于Jaccard相似度的网络图,节点显示对象名称,边粗细表示相似度。以下是完整的解决方案:
```python
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib as mpl
# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 正确显示负号
def read_excel_data(file_path):
"""读取Excel文件中的相似度数据"""
try:
df = pd.read_excel(file_path)
# 检查并重命名列
col_mapping = {}
for col in df.columns:
lower_col = col.lower().replace(" ", "")
if "对象a" in lower_col or "节点1" in lower_col:
col_mapping[col] = "对象A"
elif "对象b" in lower_col or "节点2" in lower_col:
col_mapping[col] = "对象B"
elif "相似度" in lower_col or "系数" in lower_col or "jaccard" in lower_col:
col_mapping[col] = "相似度"
df = df.rename(columns=col_mapping)
# 验证必要列
required_cols = ["对象A", "对象B", "相似度"]
if not all(col in df.columns for col in required_cols):
missing = [col for col in required_cols if col not in df.columns]
raise ValueError(f"缺少必要列: {missing}")
return df
except Exception as e:
print(f"读取Excel文件出错: {e}")
raise
def create_similarity_network(df):
"""创建相似度网络图"""
G = nx.Graph()
# 添加节点和边
for _, row in df.iterrows():
node1 = str(row['对象A']).strip()
node2 = str(row['对象B']).strip()
similarity = float(row['相似度'])
if not node1 or not node2:
continue
G.add_node(node1)
G.add_node(node2)
G.add_edge(node1, node2, weight=similarity)
print(f"网络图创建成功: {G.number_of_nodes()}个节点, {G.number_of_edges()}条边")
return G
def draw_network(G, output_image="jaccard_network.png"):
"""绘制网络图"""
plt.figure(figsize=(14, 12))
# 计算布局 - 使用spring_layout算法
pos = nx.spring_layout(G, seed=42)
# 提取边权重并缩放
edge_weights = [G[u][v]['weight'] for u, v in G.edges()]
min_weight, max_weight = min(edge_weights), max(edge_weights)
# 缩放权重到合理线宽范围 (1-10)
if max_weight > min_weight:
scaled_weights = [1 + 9 * (w - min_weight) / (max_weight - min_weight) for w in edge_weights]
else:
scaled_weights = [5] * len(edge_weights) # 如果所有权重相同
# 创建颜色映射
cmap = plt.cm.viridis
node_colors = [cmap(i / max(1, len(G.nodes())-1)) for i in range(len(G.nodes()))]
# 绘制节点
nx.draw_networkx_nodes(
G, pos,
node_size=1200,
node_color=node_colors,
alpha=0.9
)
# 绘制边
nx.draw_networkx_edges(
G, pos,
width=scaled_weights,
edge_color='gray',
alpha=0.6
)
# 绘制节点标签 - 确保显示对象名称
nx.draw_networkx_labels(
G, pos,
font_size=10,
font_weight='bold',
font_family='SimHei'
)
# 添加图例说明
plt.title("基于Jaccard相似度的对象关系网络", fontsize=16, pad=20)
plt.text(0.05, 0.05, f"节点数: {G.number_of_nodes()}\n边数: {G.number_of_edges()}",
transform=plt.gca().transAxes, fontsize=12)
# 添加边权重图例
sm = plt.cm.ScalarMappable(cmap=plt.cm.Greys,
norm=plt.Normalize(vmin=min_weight, vmax=max_weight))
sm.set_array([])
cbar = plt.colorbar(sm, ax=plt.gca(), fraction=0.03, pad=0.01)
cbar.set_label('相似度权重', fontsize=12)
plt.axis('off')
plt.tight_layout()
# 保存图像
plt.savefig(output_image, dpi=300, bbox_inches='tight')
print(f"网络图已保存至: {output_image}")
plt.show()
# 主程序
if __name__ == "__main__":
try:
# 读取数据
df = read_excel_data("similar05.xlsx")
print("数据预览:")
print(df.head())
# 创建网络
network = create_similarity_network(df)
# 绘制网络图
draw_network(network, "jaccard_similarity_network.png")
except Exception as e:
print(f"程序执行出错: {e}")
```
### 代码说明
1. **数据读取**:
- 使用Pandas读取Excel文件
- 自动识别并重命名列(支持"对象A"、"对象B"、"相似度"等常见列名)
- 处理缺失值和数据类型转换
2. **网络图创建**:
- 使用NetworkX创建无向图
- 节点:Excel中的对象名称
- 边:对象间的关系,权重为Jaccard相似度
- 数学表达:对于节点 $u$ 和 $v$,Jaccard相似度定义为:
$$J(u,v) = \frac{|A_u \cap A_v|}{|A_u \cup A_v|}$$
其中 $A_u$ 和 $A_v$ 分别是对象 $u$ 和 $v$ 的特征集合
3. **可视化设计**:
- 节点标签:直接显示对象名称
- 边粗细:与相似度成正比(使用线性缩放)
- 颜色映射:使用viridis色谱区分不同节点
- 布局算法:使用spring_layout力导向布局,使连接紧密的节点靠近
- 图例:添加颜色条显示相似度范围
4. **中文支持**:
- 设置Matplotlib使用SimHei字体
- 确保中文标签和标题正确显示
### 使用说明
1. 确保`similar05.xlsx`文件位于同一目录
2. 文件应包含三列数据:对象A、对象B、Jaccard相似度
3. 运行后将生成`jaccard_similarity_network.png`图像文件
### 网络图特点
- 节点大小固定,便于比较
- 边粗细直观反映相似度大小
- 颜色条显示相似度范围
- 自动适应不同规模的网络
- 高质量输出(300dpi)
阅读全文