(五)PythonでBaggingアルゴリズムを最初から実現する方法

55890 ワード

作者:chen_hマイクロ信号&QQ:862251340マイクロ信号公衆番号:coderpai
(一)機械学習における統合学習の入門
(二)bagging方法
(三)Pythonを用いた取引のランダム森林アルゴリズム
(四)Pythonにおけるランダム森林の実現と解釈
(五)PythonでBaggingアルゴリズムを最初から実現する方法
決定ツリーは単純で強力な予測モデリング技術であるが,それらには高方差がある.これは、異なるトレーニングデータが与えられた場合、ツリーが非常に異なる結果を得ることができることを意味する.意思決定ツリーをより丈夫にし、パフォーマンスを向上させるために、Baggingメソッドの1つである統合学習メソッドを採用します.
このチュートリアルでは、Pythonを使用して意思決定ツリーを最初から使用するbaggingプロセスについて説明します.このチュートリアルを終了すると、次のことがわかります.
  • は、データセットの自挙プロセスをどのように作成するか.
  • はどのように自挙モデルを使用して予測するか.
  • baggingアルゴリズムを予測モデルにどのように適用するか.

  • Bootstrap Aggregationアルゴリズム
    Bootstrapは、戻されたデータ収集方式です.これはまた、新しいデータセットが元のデータからランダムに採用され、データが戻され、次のサンプリングが行われることを意味する.
    非常に膨大なデータセットを推定するとき,この推定方式は非常によい.有限集合の平均値を計算することによって,データセット全体の平均値を得ることができる.この方法は一般的に,決定ツリーのような高い分散を持つアルゴリズムとともに用いられる.各自作サンプルについて個別モデル計算を行い,次いで複数のモデル結果の平均値を出力した.この技術をbootstrapまたはbaggingと呼ぶ.
    分散はアルゴリズムの性能が訓練データに敏感であることを意味し,高分散は訓練データの変化が多ければ多いほどアルゴリズムの性能が悪くなることを示した.多くのツリーを訓練し,その予測の平均値をとることで,剪定されていない決定ツリーのような高分散機械学習アルゴリズムの性能を改善することができる.モデルで得られた結果は、通常、単一の決定ツリーの表現よりも優れている.
    パフォーマンスの向上に加えて、baggingのもう一つの利点は、問題に過度にフィットしないことです.樹木を追加し続けることで、最適なパフォーマンスを達成できることを知ることができます.
    Sonarデータセット
    このチュートリアルでは、Sonarデータセットを使用しています.これはオーディオ信号が異なる表面から反発することを記述するデータセットである.入力データは60個の特徴データからなり,出力データは物体表面が岩石であるか金属円柱であるかを判断する二分類である.データは全部で208件です.これは非常に簡単なデータセットです.すべての入力変数は連続しており、値は0~1です.出力変数はM(金属円柱)とR(岩石)であり,この分類結果を1と0に変換する必要がある.データはUCI Machine Learingでダウンロードします.ダウンロードリンク:https://archive.ics.uci.edu/ml/datasets/Connectionist+Bench+(Sonar,+Mines+vs.+Rocks)
    実戦例
    このチュートリアルは、次の2つのセクションに分かれています.
  • Bootstrapサンプリング;
  • オーディオデータ分析;

  • これらのステップはデータサンプリングとアルゴリズム作成の基本機能を提供し,baggingアルゴリズムがどのように基礎的な仕事を行うかを学ぶことができる.
    1.Bootstrapサンプリング
    まずbootstrap法の動作原理を深く理解しましょう.
    データセットからローデータをランダムに選択し、新しいリストに追加することで、データセットを新しいサンプルとして作成できます.固定数のローに対してこの操作を繰り返すか、新しいデータセットのサイズと元のデータセットのサイズの比率が私たちの要件に達していることを知ることができます.私たちはデータを採集するたびに、戻して、再び採集します.
    次はsubsample()という関数で、このプロセスを実現します.ランダムモジュールのrandrange()関数は、ループの反復ごとにサンプルに追加するためにランダムラインインデックスを選択するために使用されます.サンプルのデフォルトのサイズは、元のデータセットのサイズです.
    def subsample(dataset, ratio=1.0):
    	sample = list()
    	n_sample = round(len(dataset) * ratio)
    	while len(sample) < n_sample:
    		index = randrange(len(dataset))
    		sample.append(dataset[index])
    	return sample
    

    この関数を用いて,一人で作成したデータセットの平均値を評価することができる.
    まず,20行を含み,中の数字は0から9の間のランダム値を作成し,彼らの平均値を計算した.
    その後、元のデータセットの自挙サンプルセットを作成することができ、平均リストがあるまでこのプロセスを繰り返し、平均値を計算します.この平均値は私たちのサンプル全体の平均値に非常に近い.
    以下に、完全な例を示します.
    各自挙サンプルは、元のサンプルの10%、すなわち2つのサンプルである.次に,元のデータセットの1個,10個,100個の自挙サンプルを作成し,それらの平均値を計算し,これらの推定されたすべての平均値を平均することによって実験を行った.
    from random import seed
    from random import random
    from random import randrange
     
     
    # Create a random subsample from the dataset with replacement
    def subsample(dataset, ratio=1.0):
    	sample = list()
    	n_sample = round(len(dataset) * ratio)
    	while len(sample) < n_sample:
    		index = randrange(len(dataset))
    		sample.append(dataset[index])
    	return sample
     
     
    # Calculate the mean of a list of numbers
    def mean(numbers):
    	return sum(numbers) / float(len(numbers))
     
     
    seed(1)
    # True mean
    dataset = [[randrange(10)] for i in range(20)]
    print('True Mean: %.3f' % mean([row[0] for row in dataset]))
    # Estimated means
    ratio = 0.10
    for size in [1, 10, 100]:
    	sample_means = list()
    	for i in range(size):
    		sample = subsample(dataset, ratio)
    		sample_mean = mean([row[0] for row in sample])
    		sample_means.append(sample_mean)
    	print('Samples=%d, Estimated Mean: %.3f' % (size, mean(sample_means)))
    

    この例を実行すると、推定する元のデータの平均値が印刷されます.
    次いで,推定平均値を種々の異なる数の自挙試料から見ることができる.100個の試料を通して平均値を良く推定できることが分かった.
    True Mean: 4.450
    Samples=1, Estimated Mean: 4.500
    Samples=10, Estimated Mean: 3.300
    Samples=100, Estimated Mean: 4.480
    

    単純な計算平均値ではなく、サブサンプルごとにモデルを作成できます.
    次に、複数のbootstrapモデルの予測を組み合わせる方法を見てみましょう.
    2.オーディオデータセットのケーススタディ
    この節では,ランダム森林アルゴリズムをオーディオデータセットに適用する.
    まず、データセットをインポートし、文字列値を数値型に変換し、出力列を文字列から0と1の整数値に変換する必要があります.これは補助関数load_によってcsv() ,str_column_to_float()とstr_column_to_int()は、データセットを前処理するために実装される.
    k−foldクロス検証を用いて,未知データ上の学習モデルの性能を推定する.これは,k個のモデルを構築し評価し,性能を平均モデル誤差と推定することを意味する.分類精度は各モデルを評価し、これらのアルゴリズムはcross_validation_split() ,accuracy_Metric()とevaluate_Algoritm()関数で解決されます.
    CARTアルゴリズムを用いてbaggingプロセスを実装し,実装の過程でいくつかの補助関数を設計した:test_split()関数はデータセットをグループに分割しgini_index()は、分割点を評価するために使用され、get_split()は、最適な分割点を検索するために使用され、to_terminal()、split()およびbuild_tree()は単一の決定ツリーを作成し、predict()は決定ツリーを使用して予測し、前のステップで説明したsubsample()関数を使用して訓練のサブサンプル訓練セットを作成するために使用される.
    baggingも開発しました各決定ツリーを使用して予測を行い、予測を単一の戻り値に組み合わせるpredict()関数.これはbagging法でよく使われるモードです.
    最後に,訓練データセットのサンプルを作成し,各サンプルに決定ツリーを訓練し,bagging()リストを用いて試験データセットを予測する新しいbagging()関数を設計した.
    完全なコードは次のとおりです.
    # Bagging Algorithm on the Sonar dataset
    from random import seed
    from random import randrange
    from csv import reader
     
    # Load a CSV file
    def load_csv(filename):
    	dataset = list()
    	with open(filename, 'r') as file:
    		csv_reader = reader(file)
    		for row in csv_reader:
    			if not row:
    				continue
    			dataset.append(row)
    	return dataset
     
    # Convert string column to float
    def str_column_to_float(dataset, column):
    	for row in dataset:
    		row[column] = float(row[column].strip())
     
    # Convert string column to integer
    def str_column_to_int(dataset, column):
    	class_values = [row[column] for row in dataset]
    	unique = set(class_values)
    	lookup = dict()
    	for i, value in enumerate(unique):
    		lookup[value] = i
    	for row in dataset:
    		row[column] = lookup[row[column]]
    	return lookup
     
    # Split a dataset into k folds
    def cross_validation_split(dataset, n_folds):
    	dataset_split = list()
    	dataset_copy = list(dataset)
    	fold_size = int(len(dataset) / n_folds)
    	for i in range(n_folds):
    		fold = list()
    		while len(fold) < fold_size:
    			index = randrange(len(dataset_copy))
    			fold.append(dataset_copy.pop(index))
    		dataset_split.append(fold)
    	return dataset_split
     
    # Calculate accuracy percentage
    def accuracy_metric(actual, predicted):
    	correct = 0
    	for i in range(len(actual)):
    		if actual[i] == predicted[i]:
    			correct += 1
    	return correct / float(len(actual)) * 100.0
     
    # Evaluate an algorithm using a cross validation split
    def evaluate_algorithm(dataset, algorithm, n_folds, *args):
    	folds = cross_validation_split(dataset, n_folds)
    	scores = list()
    	for fold in folds:
    		train_set = list(folds)
    		train_set.remove(fold)
    		train_set = sum(train_set, [])
    		test_set = list()
    		for row in fold:
    			row_copy = list(row)
    			test_set.append(row_copy)
    			row_copy[-1] = None
    		predicted = algorithm(train_set, test_set, *args)
    		actual = [row[-1] for row in fold]
    		accuracy = accuracy_metric(actual, predicted)
    		scores.append(accuracy)
    	return scores
     
    # Split a dataset based on an attribute and an attribute value
    def test_split(index, value, dataset):
    	left, right = list(), list()
    	for row in dataset:
    		if row[index] < value:
    			left.append(row)
    		else:
    			right.append(row)
    	return left, right
     
    # Calculate the Gini index for a split dataset
    def gini_index(groups, classes):
    	# count all samples at split point
    	n_instances = float(sum([len(group) for group in groups]))
    	# sum weighted Gini index for each group
    	gini = 0.0
    	for group in groups:
    		size = float(len(group))
    		# avoid divide by zero
    		if size == 0:
    			continue
    		score = 0.0
    		# score the group based on the score for each class
    		for class_val in classes:
    			p = [row[-1] for row in group].count(class_val) / size
    			score += p * p
    		# weight the group score by its relative size
    		gini += (1.0 - score) * (size / n_instances)
    	return gini
     
    # Select the best split point for a dataset
    def get_split(dataset):
    	class_values = list(set(row[-1] for row in dataset))
    	b_index, b_value, b_score, b_groups = 999, 999, 999, None
    	for index in range(len(dataset[0])-1):
    		for row in dataset:
    		# for i in range(len(dataset)):
    		# 	row = dataset[randrange(len(dataset))]
    			groups = test_split(index, row[index], dataset)
    			gini = gini_index(groups, class_values)
    			if gini < b_score:
    				b_index, b_value, b_score, b_groups = index, row[index], gini, groups
    	return {'index':b_index, 'value':b_value, 'groups':b_groups}
     
    # Create a terminal node value
    def to_terminal(group):
    	outcomes = [row[-1] for row in group]
    	return max(set(outcomes), key=outcomes.count)
     
    # Create child splits for a node or make terminal
    def split(node, max_depth, min_size, depth):
    	left, right = node['groups']
    	del(node['groups'])
    	# check for a no split
    	if not left or not right:
    		node['left'] = node['right'] = to_terminal(left + right)
    		return
    	# check for max depth
    	if depth >= max_depth:
    		node['left'], node['right'] = to_terminal(left), to_terminal(right)
    		return
    	# process left child
    	if len(left) <= min_size:
    		node['left'] = to_terminal(left)
    	else:
    		node['left'] = get_split(left)
    		split(node['left'], max_depth, min_size, depth+1)
    	# process right child
    	if len(right) <= min_size:
    		node['right'] = to_terminal(right)
    	else:
    		node['right'] = get_split(right)
    		split(node['right'], max_depth, min_size, depth+1)
     
    # Build a decision tree
    def build_tree(train, max_depth, min_size):
    	root = get_split(train)
    	split(root, max_depth, min_size, 1)
    	return root
     
    # Make a prediction with a decision tree
    def predict(node, row):
    	if row[node['index']] < node['value']:
    		if isinstance(node['left'], dict):
    			return predict(node['left'], row)
    		else:
    			return node['left']
    	else:
    		if isinstance(node['right'], dict):
    			return predict(node['right'], row)
    		else:
    			return node['right']
     
    # Create a random subsample from the dataset with replacement
    def subsample(dataset, ratio):
    	sample = list()
    	n_sample = round(len(dataset) * ratio)
    	while len(sample) < n_sample:
    		index = randrange(len(dataset))
    		sample.append(dataset[index])
    	return sample
     
    # Make a prediction with a list of bagged trees
    def bagging_predict(trees, row):
    	predictions = [predict(tree, row) for tree in trees]
    	return max(set(predictions), key=predictions.count)
     
    # Bootstrap Aggregation Algorithm
    def bagging(train, test, max_depth, min_size, sample_size, n_trees):
    	trees = list()
    	for i in range(n_trees):
    		sample = subsample(train, sample_size)
    		tree = build_tree(sample, max_depth, min_size)
    		trees.append(tree)
    	predictions = [bagging_predict(trees, row) for row in test]
    	return(predictions)
     
    # Test bagging on the sonar dataset
    seed(1)
    # load and prepare data
    filename = 'sonar.all-data.csv'
    dataset = load_csv(filename)
    # convert string attributes to integers
    for i in range(len(dataset[0])-1):
    	str_column_to_float(dataset, i)
    # convert class column to integers
    str_column_to_int(dataset, len(dataset[0])-1)
    # evaluate algorithm
    n_folds = 5
    max_depth = 6
    min_size = 2
    sample_size = 0.50
    for n_trees in [1, 5, 10, 50]:
    	scores = evaluate_algorithm(dataset, bagging, n_folds, max_depth, min_size, sample_size, n_trees)
    	print('Trees: %d' % n_trees)
    	print('Scores: %s' % scores)
    	print('Mean Accuracy: %.3f%%' % (sum(scores)/float(len(scores))))
    

    k値が5の場合、クロス検証に使用され、各反復評価のデータ量は208/5=41.6または40個を直接使用して反復されます.
    構築ツリーの最大深さは、ノードごとに2の最小トレーニングライン数を6に設定します.トレーニングデータセットのサンプルは、元のデータセットサイズの50%として作成されます.これは、各木を訓練するための訓練セットサンプルのいくつかの変異体を強制するためである.baggingのデフォルト設定は、サンプルデータセットのサイズを元のトレーニングデータセットのサイズと一致させることです.
    次に、各カテゴリの結果を印刷します.
    Trees: 1
    Scores: [87.8048780487805, 65.85365853658537, 65.85365853658537, 65.85365853658537, 73.17073170731707]
    Mean Accuracy: 71.707%
     
    Trees: 5
    Scores: [60.97560975609756, 80.48780487804879, 78.04878048780488, 82.92682926829268, 63.41463414634146]
    Mean Accuracy: 73.171%
     
    Trees: 10
    Scores: [60.97560975609756, 73.17073170731707, 82.92682926829268, 80.48780487804879, 68.29268292682927]
    Mean Accuracy: 73.171%
     
    Trees: 50
    Scores: [63.41463414634146, 75.60975609756098, 80.48780487804879, 75.60975609756098, 85.36585365853658]
    Mean Accuracy: 76.098%
    

    この方法の1つの難点は,一定の深さのツリーを構築してもbaggingツリーで得られた結果は非常に類似していることである.しかし、私たちは訓練の過程で高方差を下げることができることを望んでいます.これは,構造の過程で同じまたは類似の分裂ノードを選択したためであり,これは貪欲なアルゴリズムである.
    このチュートリアルでは、各ツリーを訓練するためのサンプルサイズを制約することで、分散を再計算します.より強力なテクノロジーは、各分割ポイントを作成するときにフィーチャーの評価を制約することです.これはランダムな森で使われる方法です.
    拡張
  • ツリーの調整:ツリーのサイズ、深さ、および単一のツリーの構成を調整します.
  • baggingでは異なるツリー構造を構築します.ベイズ、決定ツリー、ニューラルネットワークなど、異なるアルゴリズムを使用して平均予測することができます.