我正在尝试为使用ExtraTrees分类器实现的机器学习模型开发一个用户界面。
下面的代码展示了我如何在训练后导出模型以便在UI中使用。预测是使用is_attributed
列完成的。
import numpy as npimport pandas as pdfrom collections import Counterimport datetimefrom sklearn.model_selection import train_test_splitfrom sklearn.model_selection import RepeatedStratifiedKFoldimport gcimport warningswarnings.simplefilter('ignore')df = pd.read_csv('../cleaned_train.csv', index_col=0)df['click_time'] = pd.to_datetime(df['click_time'])df.info()<class 'pandas.core.frame.DataFrame'>Int64Index: 10000000 entries, 0 to 9999999Data columns (total 9 columns): # Column Dtype --- ------ ----- 0 ip int64 1 app int64 2 device int64 3 os int64 4 channel int64 5 click_time datetime64[ns] 6 is_attributed int64 7 hour int64 8 day int64 dtypes: datetime64[ns](1), int64(8)memory usage: 762.9 MBX= df.drop(columns=['is_attributed', 'click_time'])y= df['is_attributed']#Undersample datafrom imblearn.under_sampling import RandomUnderSamplerrus = RandomUnderSampler() X_res, y_res = rus.fit_resample(X, y)X_train, X_test, y_train, y_test = train_test_split(X_res, y_res, test_size = 0.33, random_state = 0)from sklearn.ensemble import ExtraTreesClassifierfrom sklearn.model_selection import GridSearchCVimport pickle# ExtraTreesClassifierec = ExtraTreesClassifier(max_depth=None, n_estimators=50)ec.fit(X_train, y_train)y_predec=ec.predict(X_test)pickle.dump(gsec,open('model.pkl','wb'))
当我尝试打印这个print(gsec.predict(X_test))
时,我得到的结果是[1 1 0 ... 1 1 0]
问题出现在我尝试使用Flask开发UI时。我在Flask中导入了模型并尝试预测。下面是相关的代码。
# importing necessary libraries and functionsimport numpy as npimport pandas as pdfrom flask import Flask, request, jsonify, render_template, make_responsefrom werkzeug.utils import secure_filenamefrom werkzeug.datastructures import FileStorageimport pickleimport iofrom io import StringIOimport csvapp = Flask(__name__) #Initialize the flask App@app.route('/') # Homepagedef home():return render_template('index.html')@app.route('/predict',methods=['GET', 'POST'])def predict():'''For rendering results on HTML GUI'''# retrieving values from formif request.method == 'POST': f = request.files['data_file'] if not f: return "No file"stream = io.StringIO(f.stream.read().decode("UTF8"), newline=None)csv_input = csv.reader(stream)# print(csv_input)for row in csv_input: print(row)stream.seek(0)result = stream.read()df = pd.read_csv('newcleaned_test.csv')attribute = df['is_attributed']ip = df['ip']print (attribute)# load the model from diskloaded_model = pickle.load(open('model.pkl', 'rb'))prediction = loaded_model.predict([attribute])print (prediction)return 'prediction'if __name__ == "__main__":app.run(debug=True)
当尝试运行上述代码时,
ValueError: X has 500000 features, but ExtraTreeClassifier is expecting 7 features as input.
在我的浏览器中显示了上述错误。(我使用的文件包含500000条数据和7列)。为什么会抛出这个错误?我用一列训练了模型?
回答:
你在这里有一些误解。
首先,从代码中可以看到,模型是基于7列作为输入进行训练的,即[ip, app, device, os, channel, hour, day]
。模型被训练用于预测is_attributed
列的值。因此,输入模型一个包含7个值的列表,将会得到一个输出值。这个值似乎根据输入的7个值是0或1。
其次,我们可以继续讨论Flask部分。基本上,你在这里做的就是加载数据框并选择一列(attribute = df['is_attributed']
)。如果你有一个包含50000行的数据框,并且你选择了一列,这意味着你选择了50000个值!然后你试图将这些值发送给模型,而模型恰好需要7个值作为输入。从我的角度来看,看起来你是想在test
数据框的每一行上运行模型。
要做到这一点,你需要:
- 加载
test
数据框; - 检查数据框中只有7列(
[ip, app, device, os, channel, hour, day]
)。如果你有更多的列,删除所有其他列; - 遍历数据框中的每一行(总共50000行);
- 使用行中的7个值作为输入运行模型;
- 将模型的输出追加到Python列表中;
- 在运行50000次后,你将得到一个包含50000个值的Python列表;
- 返回这个列表。