本番環境で機械学習アルゴリズムを迅速に記述および展開する方法

現在、データ分析は、多くの場合ITから遠く離れたさまざまな分野でますます使用されており、プロジェクトの初期段階で専門家が直面しているタスクは、分析部門を開発した大企業が直面しているタスクとは根本的に異なります。 この記事では、有用なプロトタイプを迅速に作成し、アプリケーションプログラマーが使用する簡単なAPIを準備する方法について説明します。



例として、Kaggle競合プラットフォームに配置されたパイプの価格を予測するタスクを検討します。 説明とデータはこちらにあります 。 実際、実際には、非常に多くの場合、非常に少量のデータを使用して、または最初の実装まで実際のデータを使用せずにプロトタイプを迅速に作成する必要がある問題があります。 これらの場合、タスクで創造的であり、単純なヒューリスティックから始めて、すべてのリクエストまたはマークアップされたオブジェクトを評価する必要があります。 しかし、幸いなことに、このモデルの状況ではそのような問題はありません。そのため、データの確認、問題の定義、アルゴリズムの使用の試みからすぐに始めることができます。



そのため、データでアーカイブを解凍すると、数十個のcsvファイルが含まれていることがわかります。 コンテストページの説明によると、主なものはtrain_set.csvとtest_set.csvです。 基本的な価格情報が含まれています。 残りのファイルには補助的なデータが含まれていますが、重要性がやや劣ります。 それらをさらに詳しく見てみましょう。



プロジェクトルートディレクトリのデータサブディレクトリにアーカイブを配置し、コマンドで解凍しました



$ cd data/ $ unzip data.zip $ cd ..
      
      





関心のあるファイルの内容を確認できます。



 $ head data/competition_data/train_set.csv tube_assembly_id,supplier,quote_date,annual_usage,min_order_quantity,bracket_pricing,quantity,cost TA-00002,S-0066,2013-07-07,0,0,Yes,1,21.9059330191461 TA-00002,S-0066,2013-07-07,0,0,Yes,2,12.3412139792904 TA-00002,S-0066,2013-07-07,0,0,Yes,5,6.60182614356538 TA-00002,S-0066,2013-07-07,0,0,Yes,10,4.6877695119712 TA-00002,S-0066,2013-07-07,0,0,Yes,25,3.54156118026073 TA-00002,S-0066,2013-07-07,0,0,Yes,50,3.22440644770007 TA-00002,S-0066,2013-07-07,0,0,Yes,100,3.08252143576504 TA-00002,S-0066,2013-07-07,0,0,Yes,250,2.99905966403855 TA-00004,S-0066,2013-07-07,0,0,Yes,1,21.9727024365273
      
      





価格を予測するオブジェクト(インスタンス)に対応するデータを持つ列が表示されます。 つまり、アセンブリの識別子(それが何であるかはまだ完全に理解できませんが、特に機械学習の魔法は、データの効果的な使用のために、それらの意味を理解する必要がない場合があることです)、ベンダー番号、日付などです。 それとは別に、配信ユニットの数が記載されている最後から2番目の列に注意を払います。 最後に、最後の列はラベル、価格です。 配送される商品のユニットが多いほど、価格は低くなります。これは、現実の世界で何が起きているかについての私たちの考えと一致しています。



次に、テストデータを含むファイルを見てみましょう。



 $ head data/competition_data/test_set.csv id,tube_assembly_id,supplier,quote_date,annual_usage,min_order_quantity,bracket_pricing,quantity 1,TA-00001,S-0066,2013-06-23,0,0,Yes,1 2,TA-00001,S-0066,2013-06-23,0,0,Yes,2 3,TA-00001,S-0066,2013-06-23,0,0,Yes,5 4,TA-00001,S-0066,2013-06-23,0,0,Yes,10 5,TA-00001,S-0066,2013-06-23,0,0,Yes,25 6,TA-00001,S-0066,2013-06-23,0,0,Yes,50 7,TA-00001,S-0066,2013-06-23,0,0,Yes,100 8,TA-00001,S-0066,2013-06-23,0,0,Yes,250 9,TA-00003,S-0066,2013-07-07,0,0,Yes,1
      
      





最後の例外を除いて同じ列、すなわち、予測価格。 競争にとって論理的なもの-これらのデータに基づいて、競争Webサイトに送信して中間結果を受信するための回答を生成する必要があります。



上記のように、2つのメインデータファイルに加えて、追加のファイルも多数あります。 それらに含まれるデータの主なアイデアをつかむために、少なくともそれらのいくつかを見るのは理にかなっています。



 $ head data/competition_data/tube.csv tube_assembly_id,material_id,diameter,wall,length,num_bends,bend_radius,end_a_1x,end_a_2x,end_x_1x,end_x_2x,end_a,end_x,num_boss,num_bracket,other TA-00001,SP-0035,12.7,1.65,164,5,38.1,N,N,N,N,EF-003,EF-003,0,0,0 TA-00002,SP-0019,6.35,0.71,137,8,19.05,N,N,N,N,EF-008,EF-008,0,0,0 TA-00003,SP-0019,6.35,0.71,127,7,19.05,N,N,N,N,EF-008,EF-008,0,0,0 TA-00004,SP-0019,6.35,0.71,137,9,19.05,N,N,N,N,EF-008,EF-008,0,0,0 TA-00005,SP-0029,19.05,1.24,109,4,50.8,N,N,N,N,EF-003,EF-003,0,0,0 TA-00006,SP-0029,19.05,1.24,79,4,50.8,N,N,N,N,EF-003,EF-003,0,0,0 TA-00007,SP-0035,12.7,1.65,202,5,38.1,N,N,N,N,EF-003,EF-003,0,0,0 TA-00008,SP-0039,6.35,0.71,174,6,19.05,N,N,N,N,EF-008,EF-008,0,0,0 TA-00009,SP-0029,25.4,1.65,135,4,63.5,N,N,N,N,EF-003,EF-003,0,0,0
      
      





ええ、これは上記の「アセンブリ識別子」の種類と材料、直径などの間の単なる対応です。 この情報は、おそらくアルゴリズムの学習に非常に役立ちます。



最後に、パイプが作られる材料に捧げられたファイルに含まれているものを見てみましょう。



 $ head data/competition_data/bill_of_materials.csv tube_assembly_id,component_id_1,quantity_1,component_id_2,quantity_2,component_id_3,quantity_3,component_id_4,quantity_4,component_id_5,quantity_5,component_id_6,quantity_6,component_id_7,quantity_7,component_id_8,quantity_8 TA-00001,C-1622,2,C-1629,2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00002,C-1312,2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00003,C-1312,2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00004,C-1312,2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00005,C-1624,1,C-1631,1,C-1641,1,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00006,C-1624,1,C-1631,1,C-1641,1,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00007,C-1622,2,C-1629,2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00008,C-1312,2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00009,C-1625,2,C-1632,2,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA
      
      





繰り返しますが、「アセンブリID」とコンポーネント間の対応のリストのみが表示されます。 値が「NA」のフィールドが豊富にあることに注意してください。 原則として、それらはデータのギャップを示しますが、この例では、コンポーネントがヘッダーの8つの位置すべてを埋めるだけでは不十分な場合に対応します。



一般的な用語でのデータは研究されているように思えますが、今度はアルゴリズムのセットアップに直接進んでください。 そしてここにあります-アルゴリズムを設定する前に、それから何を達成しようとしているのか、2つのアルゴリズムをどのように比較するのかを理解する価値があります。 まず、ラベル付きデータの一部を残して、トレーニング済みアルゴリズムの品質をテストする必要があります。機械学習では、データのこの部分は検証サンプリングと呼ばれます。 第二に、トレーニングを行う対象からデータのこの部分を除外する必要があります。そうしないと、モデルはトレーニングオブジェクトにあり、ランダムであるラベル(この場合は価格)を正確に予測します-その他の場合、理想的な予測を提供します検証サンプルではありますが、同時に絶対にひどい-実際に使用されています。 検証サンプルを除外した後の初期データは、 トレーニングサンプルと呼ばれます 。 トレーニングサンプルでモデルをトレーニングし、検証で作業の品質を確認するプロセスは、 検証手順と呼ばれます 。 しかし、これだけではありません-検証手順(偶然、実験中に変更される可能性があります)を選択することに加えて、利用可能な実験結果で予測の質を評価する方法を選択する必要もあります。 すなわち、入力の2つの対応する配列を取り、予測が実験にどの程度対応するかの出力推定値を与える関数。 このような関数は品質メトリックと呼ばれ多くの場合、実際の状況での選択に依存し、どのアルゴリズムを選択するか、どのように構成するかに依存します。 この微妙なプロセスの詳細に入ることなく、競争の主催者によって提案された二乗平均平方根誤差(RMSLE)を使用します。



したがって、基本的な問題は解決され、データをロードしてアルゴリズムをトレーニングするコードを書き始めることができます。 基本的なパイプラインをテストするために、サンプルをトレーニングと検証の部分に70/30の比率で分割し、2つの単純な機能と1つの最も単純なアルゴリズムである線形回帰を使用します。



データをロードし、そのパフォーマンスをチェックするための基本関数を作成します。



 def load_data(): list_of_instances = [] list_of_labels = [] with open('./data/competition_data/train_set.csv') as input_stream: header_line = input_stream.readline() columns = header_line.strip().split(',') for line in input_stream: new_instance = dict(zip(columns[:-1], line.split(',')[:-1])) new_label = float(line.split(',')[-1]) list_of_instances.append(new_instance) list_of_labels.append(new_label) return list_of_instances, list_of_labels >>> list_of_instances, list_of_labels = load_data() >>> print(len(list_of_instances), len(list_of_labels)) 30213 30213 >>> print(list_of_instances[:3]) [{'annual_usage': '0', 'quote_date': '2013-07-07', 'tube_assembly_id': 'TA-00002', 'min_order_quantity': '0', 'bracket_pricing': 'Yes', 'quantity': '1', 'supplier': 'S-0066'}, {'annual_usage': '0', 'quote_date': '2013-07-07', 'tube_assembly_id': 'TA-00002', 'min_order_quantity': '0', 'bracket_pricing': 'Yes', 'quantity': '2', 'supplier': 'S-0066'}, {'annual_usage': '0', 'quote_date': '2013-07-07', 'tube_assembly_id': 'TA-00002', 'min_order_quantity': '0', 'bracket_pricing': 'Yes', 'quantity': '5', 'supplier': 'S-0066'}] >>> print(list_of_labels[:3]) [21.9059330191461, 12.3412139792904, 6.60182614356538]
      
      





結果は予想とかなり一致しています。 次に、インスタンスをサンプラーに変換する関数のドラフトを作成します。



 def is_bracket_pricing(instance): if instance['bracket_pricing'] == 'Yes': return [1] elif instance['bracket_pricing'] == 'No': return [0] else: raise ValueError def get_quantity(instance): return [int(instance['quantity'])] def to_sample(instance): return is_bracket_pricing(instance) + get_quantity(instance) >>> print(list(map(to_sample, list_of_instances[:3]))) [[1, 1], [1, 2], [1, 5]]
      
      





後で、多くの異なる機能が存在する場合、それらはすべて、このために特別に予約されているfeatures.pyファイルに移動し、バリエーション、補助機能、およびいくつかの特に高度なケースでは単体テストで大きくなりすぎます。



現在、原則として、機械学習の最初の最も単純なモデルをトレーニングするために必要なものはすべて揃っています。 小さな(しかし重要な)ポイント-競争条件で提案されたメトリックに最適化されることに同意しました





RMSLE= sqrt frac1n sumi=1n logpi+1 logai+12





どこで pi -モデルによって予測された値、および ai -実際。 機能とモデル設定を選択する努力をこの目標とより一致させるために、関数ラベルを適用します fx= logx+1 。 事実、機械学習のほとんどの回帰方法は二乗誤差(MSE)を最小化するように設計されているため、上記の関数をマークに適用することで問題を軽減するのは、品質指標を最適化することです。



 import math def to_interim_label(label): return math.log(label + 1) def to_final_label(interim_label): return math.exp(interim_label) - 1 >>> print(to_final_label(to_interim_label(42))) 42.0
      
      





元のラベルから最適化により便利なラベルへ、またはその逆へ切り替える機能と間違えられなかったようで、これらの機能は実際には相互に逆です。 次に、モデルを初期化し、受け取った特徴ベクトルと中間ラベルでトレーニングします。



 >>> model = LinearRegression() >>> list_of_samples = list(map(to_sample, list_of_instances)) >>> TRAIN_SAMPLES_NUM = 20000 >>> train_samples = list_of_samples[:TRAIN_SAMPLES_NUM] >>> train_labels = list_of_labels[:TRAIN_SAMPLES_NUM] >>> model.fit(train_samples, train_labels)
      
      





これでモデルがトレーニングされ、予測の結果と検証サンプルの実際の値を比較することで、モデルがどの程度機能するかを確認できます。



 >>> validation_samples = list_of_samples[TRAIN_SAMPLES_NUM:] >>> validation_labels = list(map(to_interim_label, list_of_labels[TRAIN_SAMPLES_NUM:])) >>> squared_errors = [] >>> for sample, label in zip(validation_samples, validation_labels): >>> prediction = model.predict(numpy.array(sample).reshape(1, -1))[0] >>> squared_errors.append((prediction - label) ** 2) >>> mean_squared_error = sum(squared_errors) / len(squared_errors) >>> print('Mean Squared Error: {0}'.format(mean_squared_error)) Mean Squared Error: 0.8251727558694294
      
      





エラーは大きいですか、小さいですか? ただし、2つの特徴と1つの最も単純なモデルのみを使用するという事実を考えると、アプリオリを言うことは不可能です。おそらく、予測は最適とはほど遠いでしょう。 新しい機能を追加するなどして、実験してみましょう。 たとえば、ベースデータファイルには、既に使用されている2つのフィールド(bracket_pricingとquantity)に加えて、min_order_quantityフィールドがあります(ただし、値は0とほとんど変わらない場合があります)。 アルゴリズムを学習するための新しい機能としてその値を使用してみましょう。



 def get_min_order_quantity(instance): return [int(instance['min_order_quantity'])] def to_sample(instance): return (is_bracket_pricing(instance) + get_quantity(instance) + get_min_order_quantity(instance)) Mean Squared Error: 0.8234554779286141
      
      





ご覧のとおり、エラーはわずかに減少しています。つまり、アルゴリズムが改善されています。 そこで停止するのではなく、もう1つ機能を追加します。



 def get_annual_usage(instance): return [int(instance['annual_usage'])] def to_sample(instance): return (is_bracket_pricing(instance) + get_quantity(instance) + get_min_order_quantity(instance) + get_annual_usage(instance)) Mean Squared Error: 0.8227852260998361
      
      





次の未使用のフィールドquote_dateには、数値または一連の固定長数値の形式での単純な解釈はありません。 したがって、その値をアルゴリズムの数値入力として使用する方法について少し考える必要があります。 もちろん、年と月と日の両方が新しい機能として役立ちますが、最も論理的な最初の近似値は、特定の日付から始まる日数です-たとえば、ゼロ年の1月1日から、ファイルで見つかった最も早い日付より明らかに早く到着した日として 最初の近似では、1年に365日、12か月に30日が常に存在することを計算できます。この仮定の明らかな数学的不正確さに混乱しないように-後で式をいつでも調整して、対応する機能が予測の品質を改善するかどうかを確認できます検証サンプル。



 def get_absolute_date(instance): return [365 * int(instance['quote_date'].split('-')[0]) + 12 * int(instance['quote_date'].split('-')[1]) + int(instance['quote_date'].split('-')[2])] def to_sample(instance): return (is_bracket_pricing(instance) + get_quantity(instance) + get_min_order_quantity(instance) + get_annual_usage(instance) + get_absolute_date(instance)) Mean Squared Error: 0.8216646342919645
      
      





ご覧のとおり、数学的にも天文学的にも正確な機能ではなくても、モデルの予測の質を向上させるのに役立ちました。 次に、tube_assembly_idフィールドとsupplierフィールドに含まれる、まだ新しい機能のタイプに進みましょう。 これらの各フィールドには、メーカーとベンダーの識別子が含まれています。 これらはバイナリまたは定量的な性質のものではありませんが、固定リストからオブジェクトのタイプを記述します。 機械学習では、オブジェクトのそのようなプロパティとそれに対応する機能はcategoricalと呼ばれます 。 ただし、製造元のカテゴリ自体は、test_set.csvファイルで繰り返されないため、役に立たない可能性が高く、トレーニング部分と検証部分の間に(実際に)対応する交点がないように、マークされたサンプルを正しく分割しました。 ただし、サプライヤーフィールドの値から有用なものを抽出してみましょう。 まず、マークされたデータを含むファイルで一般的に関連するコードが何であるかを見てみましょう。



 >>> with open('./data/competition_data/train_set.csv') as input_stream: ... header_line = input_stream.readline() ... suppliers = set() ... for line in input_stream: ... new_supplier = line.split(',')[1] ... suppliers.add(new_supplier) ... >>> print(len(suppliers)) 57 >>> print(suppliers) {'S-0058', 'S-0013', 'S-0050', 'S-0011', 'S-0070', 'S-0104', 'S-0012', 'S-0068', 'S-0041', 'S-0023', 'S-0092', 'S-0095', 'S-0029', 'S-0051', 'S-0111', 'S-0064', 'S-0005', 'S-0096', 'S-0062', 'S-0004', 'S-0059', 'S-0031', 'S-0078', 'S-0106', 'S-0060', 'S-0090', 'S-0072', 'S-0105', 'S-0087', 'S-0080', 'S-0061', 'S-0108', 'S-0042', 'S-0027', 'S-0074', 'S-0081', 'S-0025', 'S-0024', 'S-0030', 'S-0022', 'S-0014', 'S-0054', 'S-0015', 'S-0008', 'S-0007', 'S-0009', 'S-0056', 'S-0026', 'S-0107', 'S-0066', 'S-0018', 'S-0109', 'S-0043', 'S-0046', 'S-0003', 'S-0006', 'S-0097'}
      
      





ご覧のとおり、それほど多くはありません。 そもそも、そのような場合に最も簡単な標準的な方法、つまり、対応する識別子と0に等しい他のすべての値の代わりに、フィールドの1つの値を持つ配列を1つのユニットに関連付ける方法を試すことができます。



 SUPPLIERS_LIST = ['S-0058', 'S-0013', 'S-0050', 'S-0011', 'S-0070', 'S-0104', 'S-0012', 'S-0068', 'S-0041', 'S-0023', 'S-0092', 'S-0095', 'S-0029', 'S-0051', 'S-0111', 'S-0064', 'S-0005', 'S-0096', 'S-0062', 'S-0004', 'S-0059', 'S-0031', 'S-0078', 'S-0106', 'S-0060', 'S-0090', 'S-0072', 'S-0105', 'S-0087', 'S-0080', 'S-0061', 'S-0108', 'S-0042', 'S-0027', 'S-0074', 'S-0081', 'S-0025', 'S-0024', 'S-0030', 'S-0022', 'S-0014', 'S-0054', 'S-0015', 'S-0008', 'S-0007', 'S-0009', 'S-0056', 'S-0026', 'S-0107', 'S-0066', 'S-0018', 'S-0109', 'S-0043', 'S-0046', 'S-0003', 'S-0006', 'S-0097'] def get_supplier(instance): if instance['supplier'] in SUPPLIERS_LIST: supplier_index = SUPPLIERS_LIST.index(instance['supplier']) result = [0] * supplier_index + [1] + [0] * (len(SUPPLIERS_LIST) - supplier_index - 1) else: result = [0] * len(SUPPLIERS_LIST) return result def to_sample(instance): return (is_bracket_pricing(instance) + get_quantity(instance) + get_min_order_quantity(instance) + get_annual_usage(instance) + get_absolute_date(instance) + get_supplier(instance)) Mean Squared Error: 0.7992338454746866
      
      





ご覧のとおり、平均誤差が大幅に減少しました。 ほとんどの場合、これは、追加したフィールドの値にアルゴリズムの貴重な情報が含まれていることを意味し、後で数回使用する価値がありますが、多少平凡ではありません。 tube_assemblyフィールドが直接私たちを助ける可能性は低いことを既に説明しましたが、これを実験的にテストしてみてください。



 def get_assembly(instance): assembly_id = int(instance['tube_assembly_id'].split('-')[1]) result = [0] * assembly_id + [1] + [0] * (25000 - assembly_id - 1) return result def to_sample(instance): return (is_bracket_pricing(instance) + get_quantity(instance) + get_min_order_quantity(instance) + get_annual_usage(instance) + get_absolute_date(instance) + get_supplier(instance) + get_assembly(instance))
      
      





もちろん、メーカーの識別子を機能ベクトルに変換する特定の方法は、特に可能な値の数を考えると、やや不自然に見えますが、読者がこのフィールドを直接、追加データを使用せずに使用するより建設的なオプションを持っている場合は、コメントで議論して適用することさえできます現在利用可能なコード。 そして、トレーニングサンプルのメインファイルに加えて、補助データを含むいくつかのファイルを自由に使用して、それらの関与を実験しようとしています。 たとえば、tube_assembly_idフィールドの値を直接使用した場合の相対的な(予測は可能ですが)失敗によってそれほど気分を害さないように、specs.csvファイルに含まれるデータを使用して復theseを試み、これらの値に対応する修飾子を匿名形式で記述できます。



 head data/competition_data/specs.csv -n 20 tube_assembly_id,spec1,spec2,spec3,spec4,spec5,spec6,spec7,spec8,spec9,spec10 TA-00001,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00002,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00003,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00004,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00005,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00006,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00007,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00008,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00009,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00010,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00011,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00012,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00013,SP-0004,SP-0069,SP-0080,NA,NA,NA,NA,NA,NA,NA TA-00014,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00015,SP-0063,SP-0069,SP-0080,NA,NA,NA,NA,NA,NA,NA TA-00016,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00017,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA TA-00018,SP-0007,SP-0058,SP-0070,SP-0080,NA,NA,NA,NA,NA,NA TA-00019,SP-0080,NA,NA,NA,NA,NA,NA,NA,NA,NA
      
      





各値に対応する修飾子の簡単なリストがあるようです。 したがって、1と0の配列を特徴ベクトルとして選択するのが妥当と思われます。この場合、ユニットは既存の修飾子に対応する位置にあり、残りはゼロになります。 追加ファイルのデータを使用するには、コードの構造を少し変更する必要があります。



 def get_assembly_specs(instance, assembly_to_specs): result = [0] * 100 for spec in assembly_to_specs[instance['tube_assembly_id']]: result[int(spec.split('-')[1])] = 1 return result def to_sample(instance, additional_data): return (is_bracket_pricing(instance) + get_quantity(instance) + get_min_order_quantity(instance) + get_annual_usage(instance) + get_absolute_date(instance) + get_supplier(instance) + get_assembly_specs(instance, additional_data['assembly_to_specs'])) def load_additional_data(): result = dict() assembly_to_specs = dict() with open('data/competition_data/specs.csv') as input_stream: header_line = input_stream.readline() for line in input_stream: tube_assembly_id = line.split(',')[0] specs = [] for spec in line.strip().split(',')[1:]: if spec != 'NA': specs.append(spec) assembly_to_specs[tube_assembly_id] = specs result['assembly_to_specs'] = assembly_to_specs return result additional_data = load_additional_data() list_of_samples = list(map(lambda x:to_sample(x, additional_data), list_of_instances)) Mean Squared Error: 0.7754770419953809
      
      





私たちの仕事は無駄ではありませんでしたし、目標メトリックは0.024向上しました。これは現在の段階ではすでに非常に良好です。 おそらく、アルゴリズムの最適化で今のところこれをやめて、アプリケーションプログラマ向けに訓練されたアルゴリズムに便利なAPIを提供するだけの問題を議論することができます。



まず、訓練されたモデルをディスクに保存します。



 with open('./data/model.mdl', 'wb') as output_stream: output_stream.write(pickle.dumps(model))
      
      





次に、先ほど受け取った結果を使用するgenerate_response.pyスクリプトを作成します。



 import pickle import numpy import research class FinalModel(object): def __init__(self, model, to_sample, additional_data): self._model = model self._to_sample = to_sample self._additional_data = additional_data def process(self, instance): return self._model.predict(numpy.array(self._to_sample( instance, self._additional_data)).reshape(1, -1))[0] if __name__ == '__main__': with open('./data/model.mdl', 'rb') as input_stream: model = pickle.loads(input_stream.read()) additional_data = research.load_additional_data() final_model = FinalModel(model, research.to_sample, additional_data) print(final_model.process({'tube_assembly_id':'TA-00001', 'supplier':'S-0066', 'quote_date':'2013-06-23', 'annual_usage':'0', 'min_order_quantity':'0', 'bracket_pricing':'Yes', 'quantity':'1'})) 2.357692493326624
      
      





これで、同様の方法で、アプリケーションプログラマは任意のスクリプトでモデルと関連変数をロードし、新しい入力データの値を使用して予測できます。



次のシリーズでは、モデルのさらなる最適化、より多くの機能、より複雑なアルゴリズム、および必要に応じてハイパーパラメーターの調整-高度な検証手順。



All Articles