You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用NetworkX从DataFrame邻接矩阵生成图时出现邻接矩阵非方阵错误的问题排查

NetworkX从DataFrame邻接矩阵生成图时出现邻接矩阵非方阵错误的问题排查

看到你遇到的这个问题我挺有共鸣的——明明自己确认了邻接矩阵是方阵,结果NetworkX偏偏报错说不是,这种“眼见不为实”的情况确实很头疼。我帮你分析一下可能的原因,以及对应的排查和解决方法:

核心原因:NetworkX的检查不止看shape,还要看index和columns的匹配度

你可能以为只要am.shape是(n,n)就没问题,但NetworkX的from_pandas_adjacency函数会严格检查列名和行索引是否完全一致(包括元素内容和顺序),哪怕shape是方阵,只要两者不匹配,就会抛出这个错误。

第一步:先做基础排查

在调用nx.from_pandas_adjacency之前,先添加这些检查代码,快速定位问题:

# 打印矩阵形状,确认是不是真的方阵
print("邻接矩阵形状:", am.shape)

# 检查列名和行索引是否完全一致
print("列名与索引匹配:", am.columns.equals(am.index))

# 检查是否有重复的列名或索引
print("唯一列名数量:", len(am.columns.unique()))
print("唯一索引数量:", len(am.index.unique()))

# 如果形状不一致,找出差异项
if am.shape[0] != am.shape[1]:
    if am.shape[1] > am.shape[0]:
        extra_cols = am.columns[~am.columns.isin(am.index)]
        print("索引中不存在的额外列:", extra_cols)
    else:
        extra_rows = am.index[~am.index.isin(am.columns)]
        print("列中不存在的额外行:", extra_rows)

常见问题及解决方法

1. 存在不在Worker列表中的Manager(或空值NaN)

你的代码中,邻接矩阵的行索引是df["Worker"],但如果某个Manager不在Worker列表里,执行am.at[row["manager"], row["Worker"]] = 1时会抛出KeyError;但如果Manager是NaN(空值),Pandas会允许将NaN作为索引值添加,这就会导致行索引长度增加,列数不变,矩阵不再是方阵。

解决方法

  • 先找出无效的Manager:
    invalid_managers = df[~df["manager"].isin(df["Worker"])]["manager"].unique()
    print("不在Worker列表中的Manager:", invalid_managers)
    
  • 处理方式二选一:
    • 过滤掉这些无效行(如果这些Worker不需要纳入图中):
      df = df[df["manager"].isin(df["Worker"])]
      
    • 将这些Manager添加到Worker列表中(如果他们是组织的一部分):
      new_workers = pd.DataFrame({"Worker": invalid_managers, "manager": None})
      df = pd.concat([df, new_workers], ignore_index=True)
      
  • 重新创建邻接矩阵时,记得判断Manager是否为空:
    am = pd.DataFrame(0, columns=df["Worker"], index=df["Worker"])
    for ix, row in df.iterrows():
        if pd.notna(row["manager"]):
            am.at[row["manager"], row["Worker"]] = 1
    

2. Worker列存在重复值

如果df["Worker"]中有重复的名字,邻接矩阵的列名和索引会出现重复条目。虽然Pandas允许重复标签,但NetworkX在检查columns.equals(index)时,会因为重复项的顺序或位置问题判定不匹配,甚至会把唯一节点数当成矩阵维度,导致报错。

解决方法

  • 先找出重复的Worker:
    duplicate_workers = df[df["Worker"].duplicated(keep=False)]["Worker"].unique()
    print("重复的Worker名称:", duplicate_workers)
    
  • 给重复名称添加后缀,确保唯一性:
    # 给重复的Worker名字添加数字后缀
    df["Worker"] = df.groupby("Worker").cumcount().apply(lambda x: f"{df['Worker'].iloc[x]}_{x+1}" if x>0 else df['Worker'].iloc[x])
    

3. 列名和索引顺序不一致

有时候即使元素完全相同,只要顺序不一样,columns.equals(index)也会返回False,导致NetworkX报错。

解决方法
重新排序索引和列名,确保两者顺序一致:

am = am.reindex(index=sorted(am.index), columns=sorted(am.columns))

更简洁的邻接矩阵创建方式

其实你可以用pd.crosstab来替代手动循环,自动处理节点匹配问题,避免手动填充的疏漏:

# 用交叉表创建邻接矩阵,自动对齐节点
am = pd.crosstab(df["manager"], df["Worker"], dropna=False)
# 重新索引,确保行和列都是所有Worker
am = am.reindex(index=df["Worker"], columns=df["Worker"], fill_value=0)

备注:内容来源于stack exchange,提问作者mrgou

火山引擎 最新活动