我正在使用pickle和zlib库,使用pyodbc将3个对象序列化并压缩为nvarchar(MAX)存储在TSQL中。当从另一端的SQL检索这些对象时,2成功地转换回了它们的原始形式(2d numpy数组和sklearn.StandardScaler)。第三个对象(sklearn.GradientBoostingRegressor)没有转换回。以下是所使用代码的摘要。还应该注意,我正在使用Pandas进行一些SQL工作。
以下是酸洗、压缩并上传到SQL的代码:
model_pickle = zlib.compress(pickle.dumps(est))
scaler_pickle = zlib.compress(pickle.dumps(scaler),1)
boundary_pickle = zlib.compress(pickle.dumps(bounds),1)
cnxn = pyodbc.connect('driver={SQL Server};server=XXX;database=XYZ;trusted_connection=true')
cursor = cnxn.cursor()
cursor.execute("""INSERT INTO AD_RLGNMNT_MDL_PICKLE (CHAIN_NUM,AD_LENGTH,GL_CODE,AD_TYPE,MODEL_PICKLE,SCALER_PICKLE,WFA_TEST,BOUNDS_PICKLE) VALUES (?,?,?,?,?,?,?,?);""",
(chain_num.astype(np.int32),ad_length.astype(np.int32),gl_code.astype(np.int32),ad_type,model_pickle,scaler_pickle,WFA,boundary_pickle))
cursor.commit()
cursor.close()
cnxn.close()
以下是从SQL中提取、解压缩和取消拾取对象的代码:
model_pickle = pd.read_sql("""SELECT A.MODEL_PICKLE from AD_RLGNMNT_MDL_PICKLE A WHERE A.CHAIN_NUM = %s and A.ad_length = %s and A.GL_CODE = %s and A.AD_TYPE in ('%s');"""
% (Current_chain_num, Current_ad_length, Current_GL, Current_ad_type),cnxn)
scaler_pickle = pd.read_sql("""SELECT A.SCALER_PICKLE from AD_RLGNMNT_MDL_PICKLE A WHERE A.CHAIN_NUM = %s and A.ad_length = %s and A.GL_CODE = %s and A.AD_TYPE in ('%s');"""
% (Current_chain_num, Current_ad_length, Current_GL, Current_ad_type),cnxn)
bounds_pickle = pd.read_sql("""SELECT A.BOUNDS_PICKLE from AD_RLGNMNT_MDL_PICKLE A WHERE A.CHAIN_NUM = %s and A.ad_length = %s and A.GL_CODE = %s and A.AD_TYPE in ('%s');"""
% (Current_chain_num, Current_ad_length, Current_GL, Current_ad_type),cnxn)
combos_list.set_value(i, 'model', model_pickle[['MODEL_PICKLE']].iloc[0].values[0])
combos_list.set_value(i, 'scaler', scaler_pickle[['SCALER_PICKLE']].iloc[0].values[0])
combos_list.set_value(i, 'bounds', bounds_pickle[['BOUNDS_PICKLE']].iloc[0].values[0])
model = pickle.loads(zlib.decompress(model_pickle[['MODEL_PICKLE']].iloc[0].values[0]))
scaler = pickle.loads(zlib.decompress(scaler_pickle[['SCALER_PICKLE']].iloc[0].values[0]))
bounds = pickle.loads(zlib.decompress(bounds_pickle[['BOUNDS_PICKLE']].iloc[0].values[0]))
当我运行"model=pickle.loads"行时,我收到以下错误(同样,最后两行工作正常):
错误:解压缩数据时出现错误-5:不完整或截断的流
我在SO和web上搜索过解决方案,并尝试过上述代码的无数变体。我比较了原始ASCI输入和输出,输入长度为203663个字符,而输出长度为203649个字符。输出在结尾缺少一个"\xb3",以及中间的一个"xaa\\\"和一个"\\n"在中间。
GradientBoostingRegressor对象有什么独特之处吗?把我的头发拔出来。
您需要使用二进制BLOB将数据存储在数据库中(实现起来更复杂)
或
在制作了base64
编码后,只需使用Character CLOB即可存储数据
import base64
model_pickle=base64.b64encode(zlib.compress(pickle.dumps(est)))
model=pickle.loads(zlib.decompress(base64.b64decode(model_pickle[['MODEL_PICKLE']].iloc[0].values[0])))
注意:base64增加了数据量(+33%),但我认为这不是很重要
**更新:这只适用于一个示例。上面用户缩进选择的答案解决了我的问题。
想明白了!将第一行代码修改为以下内容,其中包括选择更新的pickle协议。
model_pickle = zlib.compress(pickle.dumps(est,protocol = 2))