scikit-learn KNN.predict报错ndarray is not C-contiguous
问题描述
调用预测函数实现评分预测功能时,编写初始代码如下:
def convert_to_df(obj): obj_dic = obj.dict() df = pd.DataFrame(obj_dic.values(), index=obj_dic.keys()) df.reset_index(drop=True, inplace=True) return df @app.get("/get_rating") def get_rating(features: Features): features = convert_to_df(features).T # shape (1, 26) return {'rating': Predictor().predict(features)}
运行代码时触发如下报错:
File "stringsource", line 658, in View.MemoryView.memoryview_cwrapper File "stringsource", line 349, in View.MemoryView.memoryview.cinit ValueError: ndarray is not C-contiguous
代码中使用的Predictor是基于scikit-learn实现的KNN模型训练封装类,其predict方法初始实现如下:
def predict(self, features) -> int: return self.model.predict(features)
报错原因
- 对DataFrame执行
.T转置操作时,pandas不会重新分配连续内存,仅修改数组的步长规则,转置后底层numpy数组会变为Fortran(列优先)内存布局,不再满足C-contiguous(行优先连续内存)要求。 - scikit-learn的KNN模型底层基于Cython实现,预测阶段强制要求输入数组为C-contiguous内存布局,直接传入转置后的DataFrame就会触发该值错误。
- 初始的
convert_to_df逻辑冗余,先构建竖表再转置的写法完全不必要,是触发内存布局问题的直接诱因。
修复方案
优先从根源避免不必要的转置操作,再做内存格式兼容即可解决问题:
- 优化
convert_to_df逻辑,直接构造单行DataFrame,省略转置步骤
import pandas as pd import numpy as np def convert_to_df(obj): obj_dic = obj.dict() # 直接传入字典列表构造单行DataFrame,不需要额外转置 return pd.DataFrame([obj_dic])
- 传入模型前统一将特征转换为C连续内存格式,既可以在接口层处理,也可以在Predictor的predict方法中做兼容,后者对所有调用场景生效,更稳妥:
- 接口层调整示例:
@app.get("/get_rating") def get_rating(features: Features): features_df = convert_to_df(features) # 转换为C连续数组再传入预测 features_arr = np.ascontiguousarray(features_df.values) return {'rating': Predictor().predict(features_arr)}
- Predictor层兼容示例:
import numpy as np def predict(self, features) -> int: # 无论传入的是DataFrame还是非连续数组,都统一转换为C连续格式 features = np.ascontiguousarray(features) return self.model.predict(features)
内容的提问来源于stack exchange,提问作者Tlaloc-ES
相关产品推荐
相关产品推荐

