import xlrd
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib as mpl
# 读取数据
df = pd.read_excel("site_information.xlsx")
# 用pandas的操作去重 得到每条线路的名称
loc = df['线路名称'].drop_duplicates()
# 得到每一条线路名称的列表 按照Excel表里以次下去的顺序
line_list = list(loc)
# print(line_list)
# 打开Excel表格
data = xlrd.open_workbook("site_information.xlsx")
# print(data) # <xlrd.book.Book object at 0x000001F1111C38D0> 在内存中
# 获取特定Sheet 索引为0 也就是第一个表
table = data.sheets()[0] # 从零开始
# 每条线路对应有哪些站点 字典推导式
site_dic = {k: [] for k in line_list}
site_list = []
for i in range(1, table.nrows):
# 每一行的数据 返回的是一个列表
x = table.row_values(i)
if x[1] == "0":
# 只取上行站点数据 每条线路对应有哪些站点 添加进列表
site_dic[x[0]].append(x[3])
site_list.append(x[3])
else:
continue
# print(len(site_dic)) # 618条线路
# print(len(site_list)) # 15248条站点数据
# 先初始化一个统计每个节点的度的列表 与线路名称列表里的索引一一对应
node_count = [m * 0 for m in range(len(line_list))]
# 以每条线路为一个节点 线路名称为键 值为一个列表 里面包含每条路线上行经过的所有站点
sites = [site for site in site_dic.values()]
# print(sites)
# 统计各节点的度
for j in range(len(sites) - 1): # 类似冒泡法排序 比较多少趟
for k in range(j, len(sites) - 1): # 每趟比较后 往后推一个 直到比较完 和防止越界
if len(sites[j]) > len(sites[k + 1]):
for x in sites[j]:
if x in sites[j] and x in sites[k + 1]: # 只要这两条线路有公共站点 节点度数加1
node_count[j], node_count[k + 1] = node_count[j] + 1, node_count[k + 1] + 1
break # 两条线路对应在列表索引的值加1 这两条线的比较结束
else:
for x in sites[k + 1]:
if x in sites[j] and x in sites[k + 1]: # 只要这两条线路有公共站点 节点度数加1
node_count[j], node_count[k + 1] = node_count[j] + 1, node_count[k + 1] + 1
break # 两条线路对应在列表索引的值加1 这两条线的比较结束
# 找到该节点的邻居节点 邻居节点间实际的边数
Ei = []
# 对每条线路进行找邻接节点 并统计其邻接节点点实际的边数
for a in range(len(sites)):
neighbor = []
if node_count[a] == 0:
Ei.append(0)
continue
if node_count[a] == 1:
Ei.append(0)
continue
for b in range(len(sites)):
if a == b: # 自身 不比
continue
if len(sites[a]) > len(sites[b]): # 从站点多的线路里选取站点 看是否有公共站点
for x in sites[a]:
if x in sites[a] and x in sites[b]: # 找到邻居节点
neighbor.append(sites[b])
break
else:
for x in sites[b]:
if x in sites[a] and x in sites[b]: # 找到邻居节点
neighbor.append(sites[b])
break
# 在邻居节点中判断这些节点的实际边数 又类似前面的方法 判断两两是否相连
count = 0
for c in range(len(neighbor) - 1):
for d in range(c, len(neighbor) - 1): # 每趟比较后 往后推一个 直到比较完 和防止越界
try:
if len(sites[c]) > len(sites[d + 1]):
for y in sites[c]:
if y in sites[c] and y in sites[d + 1]: # 邻居节点这两个也相连
count += 1
break
else:
continue
else:
for y in sites[d + 1]:
if y in sites[c] and y in sites[d + 1]: # 邻居节点这两个也相连
count += 1
break
else:
continue
except IndexError:
break
Ei.append(count)
# 每个节点的邻居节点间实际相连的边数
# print(Ei)
# 节点编号 与 节点的度数索引对应
node_number = [y for y in range(len(node_count))]
# 设置字体 matplotlib 不支持显示中文 自己本地设置
mpl.rcParams['font.family'] = 'SimHei'
# 设置大小 图的像素
plt.figure(figsize=(10, 6), dpi=150)
# 公交线路网络的聚类系数分布图像 相邻节点的连通程度
Ci = []
for m in range(len(node_number)):
if node_count[m] == 0:
Ci.append(0)
elif node_count[m] == 1:
Ci.append(0)
else: # 2 * 该节点邻居节点实际连接边数 / 最大边数
Ci.append(2 * Ei[m] / (node_count[m] * (node_count[m] - 1)))
# 计算天津市线路网络聚类系数为 0.3167 保留4位小数
# 各节点邻居节点的连通程度
print("天津市公交线路网络平均聚类系数为{:.4f}".format(sum(Ci) / len(Ci)))
plt.bar(node_number, Ci, color="blue")
# 添加描述信息
plt.xlabel("节点编号n")
plt.ylabel("节点的聚类系数")
plt.title("线路网络中各节点的聚类系数分布", fontsize=15)
plt.savefig("聚类系数分布.png")
plt.show()
- 1
- 2
- 3
前往页