Pandas多DataFrame使用concat(axis=0)纵向拼接失效问题
问题根因
拼接错位、横向偏移和ignore_index=True参数无关,核心原因是执行pd.concat拼接时,所有待拼接的DataFrame都未设置列名,pandas默认用数字索引作为列匹配依据,只要不同服务器返回的查询结果列顺序、列数量存在微小差异,就会按数字列名对齐,最终出现横向错位。
查看原有代码的执行顺序可以明确问题:
- 先执行
df = pd.DataFrame(cursor.fetchall())生成无列名的DataFrame,直接就和全局变量alldf做concat拼接 - 拼接完成后才单独给当前单台服务器的df设置
df.columns = field_names,这步操作完全不会影响已经拼接到alldf中的内容,且全局alldf自始至终没有设置过统一列名。
此外原有代码还存在重复导入、变量名拼写错误、资源未正常释放的问题,会进一步提升异常出现概率。
修复方案
调整代码执行顺序,先给当前查询返回的df设置统一列名,再执行拼接操作,同时统一所有df的列结构,从根源避免列错位。
修复后的核心代码段
将executor函数的逻辑替换为以下内容即可:
def executor(QUERY): alldf = None for type,info in locs.items(): fileChecker(type) for ip,locName in info.items(): cnx = None try: cnx = mysql.connector.connect(user=usr, password=passwd,host=ip, database=db) if cnx.is_connected(): print("Connection Succesfull to {}".format(locName)) logwriter(type,ip,locName,True) location = cnx.cursor(buffered=True) location.execute("SELECT loccod FROM docparameters d limit 1") loc = location.fetchone()[0] location.close() cursor = cnx.cursor() cursor.execute(QUERY) raw_data = cursor.fetchall() # 先提取列名、给当前df设置列名,再做后续操作 field_names = [ i[0] for i in cursor.description] df = pd.DataFrame(raw_data, columns=field_names) cursor.close() # 单台服务器结果单独落盘 xlswriter = pd.ExcelWriter('{}/{}.xlsx'.format(type,loc),engine='openpyxl') if not df.empty: # 拼接前保证当前df列名、列顺序和全局alldf完全一致 if alldf is not None: # 兜底对齐:补全缺失列、调整列顺序和全局df完全匹配 df = df.reindex(columns=alldf.columns) alldf = pd.concat([alldf,df],ignore_index=True,axis=0) else: # 第一台服务器的结果作为全局df的列基准 alldf = df df.to_excel(xlswriter,index=False) xlswriter.save() xlswriter.close() except mysql.connector.Error as err: if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: print("Something wrong with your username or password") elif err.errno == errorcode.ER_BAD_DB_ERROR: print("DATABASE does not exist") else: print(err) print("Connection Failed to %s"%(locName)) logwriter(type,ip,locName,False) finally: # 统一在finally块关闭连接,避免资源泄漏 if cnx and cnx.is_connected(): cnx.close() return alldf
额外避坑点
- 原有代码里写的
index=false存在问题,pandas接收的布尔值是首字母大写的False,直接写false会触发命名错误,需要改为index=False openpyxl引擎不支持.xls后缀文件,建议把输出后缀统一改成.xlsx,避免保存时报错- 所有游标、文件写入对象、数据库连接建议放到
finally块统一关闭,避免连接泄漏导致后续服务器连接失败 - 拼接前增加
df.reindex(columns=alldf.columns)是兜底逻辑,哪怕某台服务器返回的列顺序错乱、缺失个别列,也会自动对齐列顺序、给缺失列填充空值,彻底避免横向错位问题
内容的提问来源于stack exchange,提问作者devMe
相关产品推荐
相关产品推荐

