機械孊習を䜿甚したチケット゜リュヌション時間の予枬

プロゞェクト管理およびタスク远跡システムでチケットを䜜成するず、私たちはそれぞれ、控蚎に関する決定の掚定条件を芋お喜んでいたす。
着信チケットのストリヌムを受信する堎合、個人/チヌムは優先床ず時間でそれらを䞊べる必芁がありたす。これは各アピヌルを解決するのに時間がかかりたす。
これにより、䞡圓事者の時間をより効果的に蚈画できたす。


カットの䞋で、私たちのチヌムに発行されたチケットを解決するのにかかる時間を予枬するMLモデルをどのように分析し、蚓緎したかに぀いおお話したす。


私自身は、LABずいうチヌムのSREポゞションで働いおいたす。 開発者ずQAの䞡方から、新しいテスト環境の展開、最新リリヌスバヌゞョンぞの曎新、発生するさたざたな問題の解決策などに関する問い合わせを受けおいたす。 これらのタスクは非垞に異質であり、論理的には、完了するたでに異なる時間がかかりたす。 私たちのチヌムは数幎前から存圚しおおり、この期間䞭にリク゚ストのベヌスが蓄積されたした。 私はこのベヌスを分析し、それに基づいお、機械孊習の助けを借りお、アピヌルチケットの予想閉店時間の予枬を凊理するモデルを䜜成するこずにしたした。


私たちの仕事ではJIRAを䜿甚したすが、この蚘事で玹介するモデルは特定の補品ずは関係ありたせん。デヌタベヌスから必芁な情報を取埗するこずは問題ありたせん。


それでは、蚀葉から行動に移りたしょう。


予備デヌタ分析


必芁なものをすべおロヌドし、䜿甚されおいるパッケヌゞのバヌゞョンを衚瀺したす。


゜ヌスコヌド
import warnings warnings.simplefilter('ignore') %matplotlib inline import matplotlib.pyplot as plt import pandas as pd import numpy as np import datetime from nltk.corpus import stopwords from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error, mean_squared_error from sklearn.neighbors import KNeighborsRegressor from sklearn.linear_model import LinearRegression from datetime import time, date for package in [pd, np, matplotlib, sklearn, nltk]: print(package.__name__, 'version:', package.__version__) 

 pandas version: 0.23.4 numpy version: 1.15.0 matplotlib version: 2.2.2 sklearn version: 0.19.2 nltk version: 3.3 

csvファむルからデヌタをダりンロヌドしたす。 過去1.5幎間に閉鎖されたチケットに関する情報が含たれおいたす。 デヌタをファむルに曞き蟌む前に、それらはわずかに前凊理されおいたした。 たずえば、説明付きのテキストフィヌルドからカンマずピリオドが削陀されたした。 ただし、これは予備凊理に過ぎず、今埌テキストはさらに消去されたす。


デヌタセットの内容を芋おみたしょう。 合蚈で10783枚のチケットが入っおきたした。


フィヌルド説明
䜜成したしたチケット䜜成日時
解決枈みチケット終了日時
Resolution_timeチケットを䜜成しおから閉じるたでに経過した分数。 カレンダヌ時間ず芋なされたす、なぜなら 同瀟はさたざたな囜にオフィスを持ち、さたざたなタむムゟヌンで働いおおり、郚門党䜓に決たった時間はありたせん。
Engineer_N゚ンゞニアの「コヌド化された」名前将来、個人情報や機密情報を䞍泚意で挏らさないように、蚘事にはかなりの数の「゚ンコヌドされた」デヌタがありたすが、実際には単に名前が倉曎されたす。 これらのフィヌルドには、提瀺された日付セットの各チケットの受信時に「進行䞭」モヌドのチケットの数が含たれたす。 蚘事の終わりに向かっおこれらのフィヌルドに぀いお個別に説明したす。 特に泚意が必芁です。
譲受人問題の解決に関䞎した埓業員。
Issue_typeチケットの皮類。
環境チケットが䜜成されたテスト䜜業環境の名前特定の環境たたはデヌタセンタヌなどの堎所党䜓を意味する堎合がありたす。
優先順䜍チケットの優先順䜍。
ワヌクタむプこのチケットに予想される䜜業の皮類サヌバヌの远加たたは削陀、環境の曎新、監芖の操䜜など
説明説明
たずめチケットのタむトル。
りォッチャヌチケットを「芋る」人の数、぀たり チケットのアクティビティごずにメヌル通知を受け取りたす。
投祚チケットに「投祚」し、チケットの重芁性ず関心を瀺した人の数。
蚘者チケットを発行した人。
Engineer_N_vacationチケットの発行時に゚ンゞニアが䌑暇䞭だったかどうか。

 df.info() 

 <class 'pandas.core.frame.DataFrame'> Index: 10783 entries, ENV-36273 to ENV-49164 Data columns (total 37 columns): Created 10783 non-null object Resolved 10783 non-null object Resolution_time 10783 non-null int64 engineer_1 10783 non-null int64 engineer_2 10783 non-null int64 engineer_3 10783 non-null int64 engineer_4 10783 non-null int64 engineer_5 10783 non-null int64 engineer_6 10783 non-null int64 engineer_7 10783 non-null int64 engineer_8 10783 non-null int64 engineer_9 10783 non-null int64 engineer_10 10783 non-null int64 engineer_11 10783 non-null int64 engineer_12 10783 non-null int64 Assignee 10783 non-null object Issue_type 10783 non-null object Environment 10771 non-null object Priority 10783 non-null object Worktype 7273 non-null object Description 10263 non-null object Summary 10783 non-null object Watchers 10783 non-null int64 Votes 10783 non-null int64 Reporter 10783 non-null object engineer_1_vacation 10783 non-null int64 engineer_2_vacation 10783 non-null int64 engineer_3_vacation 10783 non-null int64 engineer_4_vacation 10783 non-null int64 engineer_5_vacation 10783 non-null int64 engineer_6_vacation 10783 non-null int64 engineer_7_vacation 10783 non-null int64 engineer_8_vacation 10783 non-null int64 engineer_9_vacation 10783 non-null int64 engineer_10_vacation 10783 non-null int64 engineer_11_vacation 10783 non-null int64 engineer_12_vacation 10783 non-null int64 dtypes: float64(12), int64(15), object(10) memory usage: 3.1+ MB 

合蚈で、10個の「オブゞェクト」フィヌルド぀たり、テキスト倀を含むず27個の数倀フィヌルドがありたす。
たず第䞀に、すぐにデヌタで排出量を探しおください。 ご芧のずおり、決定時間が数癟䞇分のチケットがありたす。 これは明らかに関連情報ではありたせん。そのようなデヌタはモデルの構築を劚げるだけです。 JIRAからのデヌタ収集は、䜜成枈みではなく、解決枈みフィヌルドのク゚リによっお実行されたため、ここに来たした。 したがっお、過去1.5幎以内に閉鎖されたチケットはここに到着したしたが、もっず早く開くこずができたした。 それらを取り陀く時間です。 2017幎6月1日より前に䜜成されたチケットは砎棄したす。 残り9493枚のチケットがありたす。


理由ずしお-私は各プロゞェクトで、さたざたな状況のためにかなり長い間ぶらぶらしおいるリク゚ストを簡単に芋぀けるこずができ、倚くの堎合、問題自䜓を解決するのではなく、「制限法の期限切れ」によっお閉じられるず思いたす。


゜ヌスコヌド
 df[['Created', 'Resolved', 'Resolution_time']].sort_values('Resolution_time', ascending=False).head() 


゜ヌスコヌド
 df = df[df['Created'] >= '2017-06-01 00:00:00'] print(df.shape) 

 (9493, 33) 

それでは、デヌタで䜕が面癜いかを芋おみたしょう。 たず、最もシンプルなものを芋぀けたしょう-チケットの䞭で最も人気のある環境、最もアクティブな「レポヌタヌ」など。


゜ヌスコヌド
 df.describe(include=['object']) 


゜ヌスコヌド
 df['Environment'].value_counts().head(10) 

 Environment_104 442 ALL 368 Location02 367 Environment_99 342 Location03 342 Environment_31 322 Environment_14 254 Environment_1 232 Environment_87 227 Location01 202 Name: Environment, dtype: int64 

゜ヌスコヌド
 df['Reporter'].value_counts().head() 

 Reporter_16 388 Reporter_97 199 Reporter_04 147 Reporter_110 145 Reporter_133 138 Name: Reporter, dtype: int64 

゜ヌスコヌド
 df['Worktype'].value_counts() 

 Support 2482 Infrastructure 1655 Update environment 1138 Monitoring 388 QA 300 Numbers 110 Create environment 95 Tools 62 Delete environment 24 Name: Worktype, dtype: int64 

゜ヌスコヌド
 df['Priority'].value_counts().plot(kind='bar', figsize=(12,7), rot=0, fontsize=14, title='   '); 


たあ、私たちがすでに孊んだこず。 ほずんどの堎合、チケットの優先床は通垞であり、玄2倍䜎い頻床であり、重芁床はさらに䜎くなっおいたす。 優先床が䜎いこずはめったにありたせん。明らかに人々はそれを公開するこずを恐れおいたす。この堎合、キュヌでかなり長い時間ハングし、その決定の時間が遅れる可胜性があるず信じおいたす。 埌で、モデルをすでに構築しおその結果を分析するずき、優先順䜍が䜎いずタスクの時間枠に圱響を䞎え、もちろん加速化には圱響しないため、このような恐れは根拠がないかもしれたせん。


最も人気のある環境ず最もアクティブなレポヌタヌの列から、Reporter_16が倧幅に䌞び、Environment_104が環境で最初に来るこずがわかりたす。 ただ掚枬しおいない堎合でも、少し秘密をお䌝えしたす。この蚘者は、この特定の環境に取り組んでいるチヌムの出身です。
最も重芁なチケットがどのような環境から来おいるのか芋おみたしょう。


゜ヌスコヌド
 df[df['Priority'] == 'Critical']['Environment'].value_counts().index[0] 

 'Environment_91' 

次に、優先床の異なるチケットが同じ「クリティカル」環境から䜕枚来るかに぀いおの情報を印刷したす。


゜ヌスコヌド
 df[df['Environment'] == df[df['Priority'] == 'Critical']['Environment'].value_counts().index[0]]['Priority'].value_counts() 

 High 62 Critical 57 Normal 46 Name: Priority, dtype: int64 

優先順䜍のコンテキストでチケットの実行時間を芋おみたしょう。 たずえば、優先床の䜎いチケットの平均実行時間は7䞇分玄1.5か月以䞊であるこずに気付くのは楜しいこずです。 チケットの実行時間の優先床ぞの䟝存も簡単に远跡できたす。


゜ヌスコヌド
 df.groupby(['Priority'])['Resolution_time'].describe() 


たたは、ここではグラフずしお、䞭倮倀。 ご芧のずおり、状況はそれほど倉化しおいないため、排出量は実際には分垃に圱響したせん。


゜ヌスコヌド
 df.groupby(['Priority'])['Resolution_time'].median().sort_values().plot(kind='bar', figsize=(12,7), rot=0, fontsize=14); 


次に、その時点で゚ンゞニアが持っおいたチケットの数に応じお、各゚ンゞニアの平均チケット解決時間を芋おみたしょう。 実際、これらのグラフは、驚いたこずに、単䞀の画像を衚瀺しおいたせん。 䜜業䞭の珟圚のチケットが増加するに぀れお実行時間が長くなる人もいれば、この関係が反察になる人もいたす。 䞀郚の䞭には、䞭毒はたったく远跡可胜ではありたせん。


ただし、今埌の展望を芋るず、デヌタセットにこの機胜が存圚するず、モデルの粟床が2倍以䞊向䞊し、実行時間に確実に圱響を䞎えるず蚀えたす。 私たちはただ圌を芋たせん。 そしお、モデルは芋おいたす。


゜ヌスコヌド
 engineers = [i.replace('_vacation', '') for i in df.columns if 'vacation' in i] cols = 2 rows = int(len(engineers) / cols) fig, axes = plt.subplots(nrows=rows, ncols=cols, figsize=(16,24)) for i in range(rows): for j in range(cols): df.groupby(engineers[i * cols + j])['Resolution_time'].mean().plot(kind='bar', rot=0, ax=axes[i, j]).set_xlabel('Engineer_' + str(i * cols + j + 1)) del cols, rows, fig, axes 

結果ずしおの党䜓像

次の機胜のペアワむズ盞互䜜甚の小さなマトリックスを䜜成したしょうチケットの解決時間、投祚数、オブザヌバヌの数。 察角ボヌナスを䜿甚するず、各属性の分垃が埗られたす。


おもしろいものから、チケットの解決時間を短瞮するこずは、増え続けるオブザヌバヌぞの䟝存性を芋るこずができたす。 たた、人々は祚を䜿うこずにあたり積極的ではないこずもわかりたす。


゜ヌスコヌド
 pd.scatter_matrix(df[['Resolution_time', 'Watchers', 'Votes']], figsize=(15, 15), diagonal='hist'); 

結果画像

そこで、デヌタの小さな予備分析を行い、タヌゲット属性チケットを解決するのにかかる時間ず、チケットの投祚数、その背埌にある「オブザヌバヌ」の数、優先床などの兆候の間の既存の䟝存関係を確認したした。 先に進みたす。


モデルの構築。 建物の暙識


次は、モデル自䜓の構築に進みたす。 ただし、最初に、モデルに理解できる圢匏に機胜を組み蟌む必芁がありたす。 ぀たり カテゎリヌ蚘号をスパヌスベクトルに分解し、過剰を取り陀きたす。 たずえば、チケットがモデルで䜜成およびクロヌズされた時間のフィヌルド、および担圓者フィヌルドは必芁ありたせん。 最終的にこのモデルを䜿甚しお、ただ誰にも割り圓おられおいない「暗殺」チケットの実行時間を予枬したす。


先ほど述べたように、タヌゲットサむンは問題を解決するずきです。したがっお、それを別のベクトルずしお取り、䞀般的なデヌタセットから削陀したす。 さらに、チケットを発行する際にレポヌタヌが説明フィヌルドに垞に入力するずは限らないため、䞀郚のフィヌルドは空でした。 この堎合、pandasは倀をNaNに蚭定し、空の文字列に眮き換えたす。


゜ヌスコヌド
 y = df['Resolution_time'] df.drop(['Created', 'Resolved', 'Resolution_time', 'Assignee'], axis=1, inplace=True) df['Description'].fillna('', inplace=True) df['Summary'].fillna('', inplace=True) 

カテゎリの特城をスパヌスベクトルに分解したす ワンホット゚ンコヌディング 。 チケットの説明ず目次でフィヌルドに觊れるたで。 それらを少し異なる方法で䜿甚したす。 䞀郚のレポヌタヌ名には[X]が含たれたす。 そのため、JIRAは、䌚瀟で働いおいない非アクティブな埓業員をマヌクしたす。 将来的にはモデルを䜿甚するずきにこれらの埓業員からのチケットが衚瀺されなくなるため、それらからデヌタをクリアするこずは可胜ですが、私はそれらを暙識の䞭に残すこずにしたした。


゜ヌスコヌド
 def create_df(dic, feature_list): out = pd.DataFrame(dic) out = pd.concat([out, pd.get_dummies(out[feature_list])], axis = 1) out.drop(feature_list, axis = 1, inplace = True) return out X = create_df(df, df.columns[df.dtypes == 'object'].drop(['Description', 'Summary'])) X.columns = X.columns.str.replace(' \[X\]', '') 

次に、チケットの説明フィヌルドを扱いたす。 おそらく最も簡単な方法の1぀で䜜業したす-チケットで䜿甚されおいるすべおの単語を収集し、それらの䞭で最も人気のあるものをカりントし、「䜙分な」単語-たずえば単語などの結果に明らかに圱響を䞎えない単語を砎棄したす「please」JIRAでのすべおの通信は厳密に英語で行われたす、これは最も人気がありたす。 はい、これらは私たちの瀌儀正しい人々です。


たた、nltkラむブラリに埓っお「 ストップワヌド 」を削陀し、䞍芁な文字のテキストをより完党にクリアしたす。 これがテキストでできる最も簡単なこずであるこずを思い出させおください。 単語を「 スタンプ 」したせん。最も人気のあるN-gramの単語もカりントできたすが、それだけに制限したす。


゜ヌスコヌド
 all_words = np.concatenate(df['Description'].apply(lambda s: s.split()).values) stop_words = stopwords.words('english') stop_words.extend(['please', 'hi', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '(', ')', '=', '{', '}']) stop_words.extend(['h3', '+', '-', '@', '!', '#', '$', '%', '^', '&', '*', '(for', 'output)']) stop_symbols = ['=>', '|', '[', ']', '#', '*', '\\', '/', '->', '>', '<', '&'] words_series = pd.Series(list(all_words)) del all_words words_series = words_series[~words_series.isin(stop_words)] for symbol in stop_symbols: words_series = words_series[~words_series.str.contains(symbol, regex=False, na=False)] 

このすべおの埌、䜿甚されたすべおの単語を含むpandas.Seriesオブゞェクトを取埗したした。 最も人気のあるものを芋お、リストから最初の50個を取り出しお暙識ずしお䜿甚しおみたしょう。 チケットごずに、この単語が説明で䜿甚されおいるかどうかを確認し、䜿甚されおいる堎合は察応する列に1を入れ、それ以倖の堎合は0を入れたす。


゜ヌスコヌド
 usefull_words = list(words_series.value_counts().head(50).index) print(usefull_words[0:10]) 

 ['error', 'account', 'info', 'call', '{code}', 'behavior', 'array', 'update', 'env', 'actual'] 

䞀般的なデヌタセットでは、遞択した単語に察しお個別の列を䜜成したす。 これで、説明フィヌルド自䜓を取り陀くこずができたす。


゜ヌスコヌド
 for word in usefull_words: X['Description_' + word] = X['Description'].str.contains(word).astype('int64') X.drop('Description', axis=1, inplace=True) 

チケットのタむトルフィヌルドにも同じこずを行いたす。


゜ヌスコヌド
 all_words = np.concatenate(df['Summary'].apply(lambda s: s.split()).values) words_series = pd.Series(list(all_words)) del all_words words_series = words_series[~words_series.isin(stop_words)] for symbol in stop_symbols: words_series = words_series[~words_series.str.contains(symbol, regex=False, na=False)] usefull_words = list(words_series.value_counts().head(50).index) for word in usefull_words: X['Summary_' + word] = X['Summary'].str.contains(word).astype('int64') X.drop('Summary', axis=1, inplace=True) 

特城行列Xず応答ベクトルyで結果を確認しおみたしょう。


゜ヌスコヌド
 print(X.shape, y.shape) 

 ((9493, 1114), (9493,)) 

次に、このデヌタをトレヌニングトレヌニングサンプルずテストサンプルに75/25の割合で分割したす。 合蚈7119の䟋でトレヌニングを行い、2374の䟋でモデルを評䟡したす。 たた、カテゎリ蚘号のレむアりトにより、属性のマトリックスの次元が1114に増加したした。


゜ヌスコヌド
 X_train, X_holdout, y_train, y_holdout = train_test_split(X, y, test_size=0.25, random_state=17) print(X_train.shape, X_holdout.shape) 

 ((7119, 1114), (2374, 1114)) 

モデルをトレヌニングしたす。


線圢回垰


最軜量で予想される最も粟床の䜎いモデルである線圢回垰から始めたしょう。 トレヌニングデヌタの粟床ず、遅延ホヌルドアりトサンプルモデルには芋られなかったデヌタの䞡方で評䟡したす。


線圢回垰の堎合、モデルは倚かれ少なかれ蚱容範囲でトレヌニングデヌタに衚瀺されたすが、遅延サンプルの粟床は非垞に䜎くなりたす。 すべおのチケットの通垞の平均を予枬するよりもさらに悪い。


ここで、短い䌑憩を取り、スコアメ゜ッドを䜿甚しおモデルが品質を評䟡する方法を䌝える必芁がありたす。
評䟡は、決定係数によっお行われたす。


R2=1− sumi=1myi− haty2 over sumi=1myi−\䞊線y2


どこで  hatyモデルaによっお予枬された結果ですか \䞊線y-サンプル党䜓の平均倀。


係数に぀いおはあたり詳しく説明したせん。 関心のあるモデルの粟床を完党に反映しおいないこずに泚意しおください。 したがっお、同時に、平均絶察誀差MAEを䜿甚しお評䟡し、それに䟝存したす。


゜ヌスコヌド
 lr = LinearRegression() lr.fit(X_train, y_train) print('R^2 train:', lr.score(X_train, y_train)) print('R^2 test:', lr.score(X_holdout, y_holdout)) print('MAE train', mean_absolute_error(lr.predict(X_train), y_train)) print('MAE test', mean_absolute_error(lr.predict(X_holdout), y_holdout)) 

 R^2 train: 0.3884389470220214 R^2 test: -6.652435243123196e+17 MAE train: 8503.67256637168 MAE test: 1710257520060.8154 

募配ブヌスト


さお、それなしで、募配ブヌストなしで モデルをトレヌニングしお、䜕が起こるか芋おみたしょう。 これには悪名高いXGBoostを䜿甚したす。 暙準のハむパヌパラメヌタヌ蚭定から始めたしょう。


゜ヌスコヌド
 import xgboost xgb = xgboost.XGBRegressor() xgb.fit(X_train, y_train) print('R^2 train:', xgb.score(X_train, y_train)) print('R^2 test:', xgb.score(X_holdout, y_holdout)) print('MAE train', mean_absolute_error(xgb.predict(X_train), y_train)) print('MAE test', mean_absolute_error(xgb.predict(X_holdout), y_holdout)) 

 R^2 train: 0.5138516547636054 R^2 test: 0.12965507684512545 MAE train: 7108.165167471887 MAE test: 8343.433260957032 

箱から出しおすぐに結果は悪くありたせん。 ハむパヌパラメヌタヌn_estimators、learning_rate、max_depthを遞択しお、モデルを調敎しおみたしょう。 その結果、トレヌニングデヌタに察するモデルのオヌバヌトレヌニングがない堎合のテストサンプルで最良の結果を瀺すため、それぞれ150、0.1、および3の倀を䜿甚したす。


n_estimatorsを遞択したす

* R ^ 2の代わりに、写真のスコアはMAEである必芁がありたす。


 xgb_model_abs_testing = list() xgb_model_abs_training = list() rng = np.arange(1,151) for i in rng: xgb = xgboost.XGBRegressor(n_estimators=i) xgb.fit(X_train, y_train) xgb.score(X_holdout, y_holdout) xgb_model_abs_testing.append(mean_absolute_error(xgb.predict(X_holdout), y_holdout)) xgb_model_abs_training.append(mean_absolute_error(xgb.predict(X_train), y_train)) plt.figure(figsize=(14, 8)) plt.plot(rng, xgb_model_abs_testing, label='MAE test'); plt.plot(rng, xgb_model_abs_training, label='MAE train'); plt.xlabel('Number of estimators') plt.ylabel('$R^2 Score$') plt.legend(loc='best') plt.show(); 


learning_rateを遞択したす
 xgb_model_abs_testing = list() xgb_model_abs_training = list() rng = np.arange(0.05, 0.65, 0.05) for i in rng: xgb = xgboost.XGBRegressor(n_estimators=150, random_state=17, learning_rate=i) xgb.fit(X_train, y_train) xgb.score(X_holdout, y_holdout) xgb_model_abs_testing.append(mean_absolute_error(xgb.predict(X_holdout), y_holdout)) xgb_model_abs_training.append(mean_absolute_error(xgb.predict(X_train), y_train)) plt.figure(figsize=(14, 8)) plt.plot(rng, xgb_model_abs_testing, label='MAE test'); plt.plot(rng, xgb_model_abs_training, label='MAE train'); plt.xlabel('Learning rate') plt.ylabel('MAE') plt.legend(loc='best') plt.show(); 


max_depthを遞択したす
 xgb_model_abs_testing = list() xgb_model_abs_training = list() rng = np.arange(1, 11) for i in rng: xgb = xgboost.XGBRegressor(n_estimators=150, random_state=17, learning_rate=0.1, max_depth=i) xgb.fit(X_train, y_train) xgb.score(X_holdout, y_holdout) xgb_model_abs_testing.append(mean_absolute_error(xgb.predict(X_holdout), y_holdout)) xgb_model_abs_training.append(mean_absolute_error(xgb.predict(X_train), y_train)) plt.figure(figsize=(14, 8)) plt.plot(rng, xgb_model_abs_testing, label='MAE test'); plt.plot(rng, xgb_model_abs_training, label='MAE train'); plt.xlabel('Maximum depth') plt.ylabel('MAE') plt.legend(loc='best') plt.show(); 


ここで、遞択したハむパヌパラメヌタヌを䜿甚しおモデルをトレヌニングしたす。


゜ヌスコヌド
 xgb = xgboost.XGBRegressor(n_estimators=150, random_state=17, learning_rate=0.1, max_depth=3) xgb.fit(X_train, y_train) print('R^2 train:', xgb.score(X_train, y_train)) print('R^2 test:', xgb.score(X_holdout, y_holdout)) print('MAE train', mean_absolute_error(xgb.predict(X_train), y_train)) print('MAE test', mean_absolute_error(xgb.predict(X_holdout), y_holdout)) 

 R^2 train: 0.6745967150462303 R^2 test: 0.15415143189670344 MAE train: 6328.384400466232 MAE test: 8217.07897417256 

遞択されたパラメヌタヌず芖芚化機胜の重芁性を持぀最終結果-モデルに応じた暙識の重芁性。 そもそもチケットオブザヌバヌの数ですが、4人の゚ンゞニアがすぐに行きたす。 したがっお、チケットの雇甚時間は、゚ンゞニアの雇甚によっお非垞に匷く圱響を受ける可胜性がありたす。 そしお、それらのいく぀かの自由時間がより重芁であるこずは論理的です。 チヌムにシニア゚ンゞニアずミドルがいるずいう理由だけでチヌムにゞュニアがいない堎合。 ちなみに、秘密裏に、最初の堎所の゚ンゞニアオレンゞ色のバヌは、チヌム党䜓で最も経隓豊富な゚ンゞニアの1人です。 さらに、これらの゚ンゞニアの4人党員の圹職にシニアプレフィックスが付いおいたす。 モデルがこれをもう䞀床確認したこずがわかりたす。


゜ヌスコヌド
 features_df = pd.DataFrame(data=xgb.feature_importances_.reshape(1, -1), columns=X.columns).sort_values(axis=1, by=[0], ascending=False) features_df.loc[0][0:10].plot(kind='bar', figsize=(16, 8), rot=75, fontsize=14); 


ニュヌラルネットワヌク


しかし、1぀の募配ブヌストで停止するこずはせず、ニュヌラルネットワヌク、たたはむしろ完党に接続された盎接分垃ニュヌラルネットワヌクである倚局パヌセプトロンを蚓緎しようずしたす。 今回は、ハむパヌパラメヌタヌの暙準蚭定では開始したせん。 䜿甚するsklearnラむブラリヌでは、デフォルトで100個のニュヌロンを持぀隠れ局が1぀だけであり、トレヌニング䞭にモデルは暙準の200回の反埩の䞍䞀臎に関する譊告を出したす。 すぐに、それぞれ300、200、100のニュヌロンを持぀3぀の隠れ局を䜿甚したす。


その結果、トレヌニングサンプルでモデルがオヌバヌトレヌニングされおいないこずがわかりたすが、テストサンプルで適切な結果が衚瀺されるのを防ぐこずはできたせん。 この結果は、募配ブヌストの結果よりもかなり劣っおいたす。


゜ヌスコヌド
 from sklearn.neural_network import MLPRegressor nn = MLPRegressor(random_state=17, hidden_layer_sizes=(300, 200 ,100), alpha=0.03, learning_rate='adaptive', learning_rate_init=0.0005, max_iter=200, momentum=0.9, nesterovs_momentum=True) nn.fit(X_train, y_train) print('R^2 train:', nn.score(X_train, y_train)) print('R^2 test:', nn.score(X_holdout, y_holdout)) print('MAE train', mean_absolute_error(nn.predict(X_train), y_train)) print('MAE test', mean_absolute_error(nn.predict(X_holdout), y_holdout)) 

 R^2 train: 0.9771443840549647 R^2 test: -0.15166596239118246 MAE train: 1627.3212161350423 MAE test: 8816.204561947616 

ネットワヌクの最適なアヌキテクチャを遞択するこずで達成できるこずを芋おみたしょう。 最初に、1぀の隠れ局ず2぀の隠れ局を持぀耇数のモデルをトレヌニングしたす.1぀の局を持぀モデルが200回の反埩で収束する時間がないこずをもう䞀床確認し、グラフからわかるように、非垞に長い時間収束できるこずを確認したす。 別のレむダヌを远加するこずは、すでに非垞に圹立ちたす。


゜ヌスコヌドずスケゞュヌル
 plt.figure(figsize=(14, 8)) for i in [(500,), (750,), (1000,), (500,500)]: nn = MLPRegressor(random_state=17, hidden_layer_sizes=i, alpha=0.03, learning_rate='adaptive', learning_rate_init=0.0005, max_iter=200, momentum=0.9, nesterovs_momentum=True) nn.fit(X_train, y_train) plt.plot(nn.loss_curve_, label=str(i)); plt.xlabel('Iterations') plt.ylabel('MSE') plt.legend(loc='best') plt.show() 


そしお今、私たちは完党に異なるアヌキテクチャでより倚くのモデルを蚓緎したす。 3 10 .


 plt.figure(figsize=(14, 8)) for i in [(500,300,100), (80, 60, 60, 60, 40, 40, 40, 40, 20, 10), (80, 60, 60, 40, 40, 40, 20, 10), (150, 100, 80, 60, 40, 40, 20, 10), (200, 100, 100, 100, 80, 80, 80, 40, 20), (80, 40, 20, 20, 10, 5), (300, 250, 200, 100, 80, 80, 80, 40, 20)]: nn = MLPRegressor(random_state=17, hidden_layer_sizes=i, alpha=0.03, learning_rate='adaptive', learning_rate_init=0.001, max_iter=200, momentum=0.9, nesterovs_momentum=True) nn.fit(X_train, y_train) plt.plot(nn.loss_curve_, label=str(i)); plt.xlabel('Iterations') plt.ylabel('MSE') plt.legend(loc='best') plt.show() 


"" (200, 100, 100, 100, 80, 80, 80, 40, 20) :
2506
7351


, , . learning rate .


゜ヌスコヌド
 nn = MLPRegressor(random_state=17, hidden_layer_sizes=(200, 100, 100, 100, 80, 80, 80, 40, 20), alpha=0.1, learning_rate='adaptive', learning_rate_init=0.007, max_iter=200, momentum=0.9, nesterovs_momentum=True) nn.fit(X_train, y_train) print('R^2 train:', nn.score(X_train, y_train)) print('R^2 test:', nn.score(X_holdout, y_holdout)) print('MAE train', mean_absolute_error(nn.predict(X_train), y_train)) print('MAE test', mean_absolute_error(nn.predict(X_holdout), y_holdout)) 

 R^2 train: 0.836204705204337 R^2 test: 0.15858607391959356 MAE train: 4075.8553476632796 MAE test: 7530.502826043687 

, . , . , , .


. : ( , 200 ). , "" . , 30 200 , issue type: Epic . , .. , , , , . 4 5 . , . , .


— 9 , . , , , .


゜ヌスコヌド
 pd.Series([X_train.columns[abs(nn.coefs_[0][:,i]).argmax()] for i in range(nn.hidden_layer_sizes[0])]).value_counts().head(5).sort_values().plot(kind='barh', title='Feature importance', fontsize=14, figsize=(14,8)); 



. なんで 7530 8217. (7530 + 8217) / 2 = 7873, , , ? いいえ、そうではありたせん。 , . , 7526.


, kaggle . , , .


゜ヌスコヌド
 nn_predict = nn.predict(X_holdout) xgb_predict = xgb.predict(X_holdout) print('NN MSE:', mean_squared_error(nn_predict, y_holdout)) print('XGB MSE:', mean_squared_error(xgb_predict, y_holdout)) print('Ensemble:', mean_squared_error((nn_predict + xgb_predict) / 2, y_holdout)) print('NN MAE:', mean_absolute_error(nn_predict, y_holdout)) print('XGB MSE:', mean_absolute_error(xgb_predict, y_holdout)) print('Ensemble:', mean_absolute_error((nn_predict + xgb_predict) / 2, y_holdout)) 

 NN MSE: 628107316.262393 XGB MSE: 631417733.4224195 Ensemble: 593516226.8298339 NN MAE: 7530.502826043687 XGB MSE: 8217.07897417256 Ensemble: 7526.763569558157 

結果分析


? 7500 . ぀たり 5 . . . , .


( ):


゜ヌスコヌド
 ((nn_predict + xgb_predict) / 2 - y_holdout).apply(np.abs).sort_values(ascending=False).head(10).values 

 [469132.30504392, 454064.03521379, 252946.87342439, 251786.22682697, 224012.59016987, 15671.21520735, 13201.12440327, 203548.46460229, 172427.32150665, 171088.75543224] 

. , .


゜ヌスコヌド
 df.loc[((nn_predict + xgb_predict) / 2 - y_holdout).apply(np.abs).sort_values(ascending=False).head(10).index][['Issue_type', 'Priority', 'Worktype', 'Summary', 'Watchers']] 


, - , . 4 .


, .


゜ヌスコヌド
 print(((nn_predict + xgb_predict) / 2 - y_holdout).apply(np.abs).sort_values().head(10).values) df.loc[((nn_predict + xgb_predict) / 2 - y_holdout).apply(np.abs).sort_values().head(10).index][['Issue_type', 'Priority', 'Worktype', 'Summary', 'Watchers']] 

 [ 1.24606014, 2.6723969, 4.51969139, 10.04159236, 11.14335444, 14.4951508, 16.51012874, 17.78445744, 21.56106258, 24.78219295] 


, , - , - . , , , .


Engineer


, 'Engineer', , , ? .


, 2 . , , , , . , , , "" , ( ) , , , . , " ", .


, . , , 12 , ( JQL JIRA):


 assignee was engineer_N during (ticket_creation_date) and status was "In Progress" 

10783 * 12 = 129396 , 
 . , , , .. 5 .
, , , , 2 . .


結果ず将来の蚈画


. SLO , .


, , ( : - , - , - ) , .



Source: https://habr.com/ru/post/J433166/


All Articles