자습서: ML.NET와 함께 회귀를 사용하여 가격 예측

이 자습서에서는 ML.NET을 사용하여 가격(특히, 뉴욕 시 택시 요금)을 예측하기 위한 회귀 모델을 빌드하는 방법에 대해 설명합니다.

이 자습서에서는 다음과 같은 작업을 수행하는 방법을 살펴봅니다.

  • 데이터 준비 및 이해
  • 데이터 로드 및 변환
  • 학습 알고리즘 선택
  • 모델 학습
  • 모델 평가
  • 예측에 모델 사용

사전 요구 사항

콘솔 애플리케이션 만들기

  1. "TaxiFarePrediction"이라는 C# 콘솔 애플리케이션을 만듭니다.

  2. 사용할 프레임워크로 .NET 6을 선택합니다. 만들기 단추를 클릭합니다.

  3. 프로젝트에서 Data 디렉터리를 만들어 데이터 세트와 모델 파일을 저장합니다.

  4. Microsoft.MLMicrosoft.ML.FastTree NuGet 패키지를 설치합니다.

    참고

    이 샘플에서는 별도로 지정하지 않은 한 언급된 NuGet 패키지의 최신 안정화 버전을 사용합니다.

    솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 NuGet 패키지 관리를 선택합니다. "nuget.org"를 패키지 소스로 선택하고, 찾아보기 탭을 선택하고, Microsoft.ML을 검색하고, 목록에서 해당 패키지를 선택하고, 설치 단추를 선택합니다. 변경 내용 미리 보기 대화 상자에서 확인 단추를 선택한 다음, 나열된 패키지의 사용 조건에 동의하는 경우 라이선스 승인 대화 상자에서 동의함 단추를 선택합니다. Microsoft.ML.FastTree NuGet 패키지에 대해 동일한 작업을 수행합니다.

데이터 준비 및 이해

  1. taxi-fare-train.csvtaxi-fare-test.csv 데이터 집합을 다운로드하여 이전 단계에서 만든 Data 폴더에 저장합니다. 이러한 데이터 집합을 사용하여 기계 학습 모델을 학습한 다음, 모델의 정확성을 평가합니다. 이러한 데이터 집합은 원래 NYC TLC Taxi Trip 데이터 집합에서 가져옵니다.

  2. 솔루션 탐색기에서 각 *.csv 파일을 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 고급 아래에서 출력 디렉터리에 복사 값을 변경된 내용만 복사로 변경합니다.

  3. taxi-fare-train.csv 데이터 집합을 열고 첫 번째 행에서 열 머리글을 확인합니다. 각 열을 살펴보세요. 데이터를 이해하고 기능레이블로 사용할 열을 결정합니다.

label은 예측할 열입니다. 식별된 FeaturesLabel 예측을 위해 모델에 제공하는 입력입니다.

제공된 데이터 집합에는 다음과 같은 열이 포함되어 있습니다.

  • vendor_id: 택시 공급업체의 ID가 기능입니다.
  • rate_code: 택시 이동의 요금 유형이 기능입니다.
  • passenger_count: 이동하는 승객 수가 기능입니다.
  • trip_time_in_secs: 이동에 걸린 시간입니다. 이동을 완료하기 전에 이동 요금을 예측하려고 합니다. 해당 시간에는 이동이 얼마나 길지 알지 못합니다. 따라서 이동 시간은 기능이 아니며 모델에서 이 열을 제외합니다.
  • trip_distance: 이동 거리가 기능입니다.
  • payment_type: 결제 방법(현금 또는 신용 카드)이 기능입니다.
  • fare_amount: 지급한 총 택시 요금이 레이블입니다.

데이터 클래스 만들기

입력 데이터 및 예측에 대한 클래스를 만듭니다.

  1. 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가>새 항목을 선택합니다.

  2. 새 항목 추가 대화 상자에서 클래스를 선택하고 이름 필드를 TaxiTrip.cs로 변경합니다. 그런 다음, 추가 단추를 선택합니다.

  3. 새 파일에 다음 using 지시문을 추가합니다.

    using Microsoft.ML.Data;
    

기존 클래스 정의를 제거하고 두 개의 클래스 TaxiTripTaxiTripFarePrediction가 있는 다음 코드를 TaxiTrip.cs 파일에 추가합니다.

public class TaxiTrip
{
    [LoadColumn(0)]
    public string VendorId;

    [LoadColumn(1)]
    public string RateCode;

    [LoadColumn(2)]
    public float PassengerCount;

    [LoadColumn(3)]
    public float TripTime;

    [LoadColumn(4)]
    public float TripDistance;

    [LoadColumn(5)]
    public string PaymentType;

    [LoadColumn(6)]
    public float FareAmount;
}

public class TaxiTripFarePrediction
{
    [ColumnName("Score")]
    public float FareAmount;
}

TaxiTrip은 입력 데이터 클래스이며 각 데이터 집합 열의 정의를 포함합니다. LoadColumnAttribute 특성을 사용하여 데이터 세트에서 소스 열의 인덱스를 지정합니다.

TaxiTripFarePrediction 클래스는 예측된 결과를 나타냅니다. 여기에는 FareAmount라는 단일 부동 필드가 있으며 ScoreColumnNameAttribute 특성이 적용되었습니다. 회귀 작업의 경우 점수 열에 예측된 레이블 값이 포함됩니다.

참고

float 유형을 사용하여 입력 및 예측 데이터 클래스에서 부동 소수점 값을 나타냅니다.

데이터 및 모델 경로 정의

Program.cs 파일 맨 위에 다음 추가 using 문을 추가합니다.

using Microsoft.ML;
using TaxiFarePrediction;

데이터 세트가 있는 파일 및 모델을 저장할 파일의 경로를 포함할 세 개의 필드를 만들어야 합니다.

  • _trainDataPath에는 모델을 학습하는 데 사용되는 데이터 집합이 있는 파일에 대한 경로가 포함됩니다.
  • _testDataPath에는 모델을 평가하는 데 사용되는 데이터 집합이 있는 파일에 대한 경로가 포함됩니다.
  • _modelPath에는 학습된 모델이 저장되는 파일에 대한 경로가 포함됩니다.

usings 섹션 바로 아래에 다음 코드를 추가하여 _textLoader 변수에 대해 해당 경로를 지정합니다.

string _trainDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "taxi-fare-train.csv");
string _testDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "taxi-fare-test.csv");
string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "Model.zip");

모든 ML.NET 작업은 MLContext 클래스에서 시작됩니다. mlContext를 초기화하면 모델 생성 워크플로 개체 간에 공유할 수 있는 새 ML.NET 환경이 생성됩니다. 개념적으로 Entity Framework의 DBContext와 유사합니다.

변수 초기화

Console.WriteLine("Hello World!") 줄을 다음 코드로 바꾸어 mlContext 변수를 선언하고 초기화합니다.

MLContext mlContext = new MLContext(seed: 0);

Train 메서드 호출 다음의 코드 줄로 다음 코드를 추가합니다.

var model = Train(mlContext, _trainDataPath);

Train() 메서드는 다음 작업을 실행합니다.

  • 데이터를 로드합니다.
  • 데이터를 추출하고 변환합니다.
  • 모델을 학습시킵니다.
  • 모델을 반환합니다.

Train 메서드는 모델을 학습시킵니다. 다음 코드를 사용하여 바로 아래에 메서드를 만듭니다.

ITransformer Train(MLContext mlContext, string dataPath)
{

}

데이터 로드 및 변환

ML.NET은 숫자 또는 텍스트 표 형식 데이터를 설명하는 효율적인 방법으로 IDataView 인터페이스를 유연하게 사용합니다. IDataView는 텍스트 파일을 또는 실시간으로 로드할 수 있습니다(예: SQL 데이터베이스 또는 로그 파일). 다음 코드를 Train() 메서드의 첫 번째 줄로 추가합니다.

IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(dataPath, hasHeader: true, separatorChar: ',');

택시 요금 예측에서 FareAmount 열은 예측할(모델의 출력) Label입니다. CopyColumnsEstimator 변환 클래스를 사용하여 FareAmount를 복사하고 다음 코드를 추가합니다.

var pipeline = mlContext.Transforms.CopyColumns(outputColumnName: "Label", inputColumnName:"FareAmount")

모델을 학습시키는 알고리즘에는 숫자 기능이 필요하므로 범주 데이터(VendorId, RateCodePaymentType) 값을 숫자(VendorIdEncoded, RateCodeEncodedPaymentTypeEncoded)로 변환해야 합니다. 이 작업을 수행하려면 각 열의 값마다 다른 숫자 키 값을 할당하는 OneHotEncodingTransformer 변환 클래스를 사용하고 다음 코드를 추가합니다.

.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "VendorIdEncoded", inputColumnName:"VendorId"))
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "RateCodeEncoded", inputColumnName: "RateCode"))
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "PaymentTypeEncoded", inputColumnName: "PaymentType"))

데이터 준비의 마지막 단계에서는 mlContext.Transforms.Concatenate 변환 클래스를 사용하여 모든 기능 열을 Features 열에 결합합니다. 기본적으로, 학습 알고리즘은 Features 열의 기능만 처리합니다. 다음 코드를 추가합니다.

.Append(mlContext.Transforms.Concatenate("Features", "VendorIdEncoded", "RateCodeEncoded", "PassengerCount", "TripDistance", "PaymentTypeEncoded"))

학습 알고리즘 선택

이 문제는 뉴욕 시의 택시 요금 예측에 관한 것입니다. 처음에는 요금이 단순히 주행 거리에 따라 결정되는 것처럼 보일 수 있습니다. 그러나 뉴욕 택시 업체는 추가 승객 또는 현금 대신 신용 카드 결제 등의 다른 요소를 고려하여 다양한 금액을 청구합니다. 데이터 세트의 기타 요인에 따라 실제 값인 가격 값을 예측하려고 합니다. 이렇게 하려면 회귀 기계 학습 작업을 선택합니다.

Train()에서 다음 코드 줄에 다음을 추가하여 FastTreeRegressionTrainer 기계 학습 작업을 데이터 변환 정의에 추가합니다.

.Append(mlContext.Regression.Trainers.FastTree());

모델 학습

모델을 dataview 학습에 맞추고 Train() 메서드에서 다음 줄의 코드를 추가하여 학습된 모델을 반환합니다.

var model = pipeline.Fit(dataView);

Fit() 메서드는 데이터 세트를 변환하고 학습을 적용하여 모델을 학습합니다.

Train() 메서드에서 다음 코드 줄을 사용하여 학습된 모델을 반환합니다.

return model;

모델 평가

다음으로, 품질 보증 및 유효성 검사를 위해 테스트 데이터로 모델 성능을 평가합니다. 다음 코드로 Train() 바로 뒤에 Evaluate() 메서드를 만듭니다.

void Evaluate(MLContext mlContext, ITransformer model)
{

}

Evaluate 메서드는 다음 작업을 실행합니다.

  • 테스트 데이터 세트를 로드합니다.
  • 회귀 평가자를 만듭니다.
  • 모델을 평가하고 메트릭을 만듭니다.
  • 메트릭을 표시합니다.

다음 코드를 사용하여 Train 메서드 호출 바로 아래에 새 메서드 호출을 추가합니다.

Evaluate(mlContext, model);

LoadFromTextFile() 메서드를 사용하여 테스트 데이터 세트를 로드합니다. 이 데이터 세트를 품질 검사로 사용하여 Evaluate 메서드에 다음 코드를 추가하여 모델을 평가합니다.

IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(_testDataPath, hasHeader: true, separatorChar: ',');

이제 Evaluate()에 다음 코드를 추가하여 Test 데이터를 변환합니다.

var predictions = model.Transform(dataView);

Transform() 메서드는 테스트 데이터 세트 입력 행에 대한 예측을 수행합니다.

RegressionContext.Evaluate 메서드는 지정된 데이터 세트를 사용하여 PredictionModel에 대한 품질 메트릭을 계산합니다. 회귀 평가자가 계산한 전체 메트릭이 포함된 RegressionMetrics 개체를 반환합니다.

모델의 품질을 확인하기 위해 이러한 메트릭을 표시하려면 먼저 메트릭을 가져와야 합니다. Evaluate 메서드에 아래 코드를 다음 줄로 추가합니다.

var metrics = mlContext.Regression.Evaluate(predictions, "Label", "Score");

예측 집합이 있으면 Evaluate() 메서드는 모델을 평가하여 예측된 값을 테스트 데이터 세트의 실제 Labels와 비교하고, 모델 수행 방법에 대한 메트릭을 반환합니다.

다음 코드를 추가하여 모델을 평가하고 평가 메트릭을 생성합니다.

Console.WriteLine();
Console.WriteLine($"*************************************************");
Console.WriteLine($"*       Model quality metrics evaluation         ");
Console.WriteLine($"*------------------------------------------------");

RSquared는 회귀 모델의 다른 평가 메트릭입니다. RSquared에서는 0과 1 사이의 값을 사용합니다. 해당 값이 1에 가까울수록 더 나은 모델입니다. RSquared 값을 표시하려면 Evaluate 메서드에 다음 코드를 추가합니다.

Console.WriteLine($"*       RSquared Score:      {metrics.RSquared:0.##}");

RMS는 회귀 모델의 평가 메트릭 중 하나입니다. RMS가 낮을수록 더 나은 모델입니다. RMS 값을 표시하려면 Evaluate 메서드에 다음 코드를 추가합니다.

Console.WriteLine($"*       Root Mean Squared Error:      {metrics.RootMeanSquaredError:#.##}");

예측에 모델 사용

다음 코드를 사용하여 Evaluate 메서드 바로 뒤에 TestSinglePrediction 메서드를 만듭니다.

void TestSinglePrediction(MLContext mlContext, ITransformer model)
{

}

TestSinglePrediction 메서드는 다음 작업을 실행합니다.

  • 테스트 데이터의 단일 댓글을 만듭니다.
  • 테스트 데이터를 기준으로 요금 금액을 예측합니다.
  • 보고를 위해 테스트 데이터 및 예측을 결합합니다.
  • 예측 결과를 표시합니다.

다음 코드를 사용하여 Evaluate 메서드 호출 바로 아래에 새 메서드 호출을 추가합니다.

TestSinglePrediction(mlContext, model);

TestSinglePrediction()에 다음 코드를 추가하여 요금을 예측하기 위해 PredictionEngine을 사용합니다.

var predictionFunction = mlContext.Model.CreatePredictionEngine<TaxiTrip, TaxiTripFarePrediction>(model);

PredictionEngine은 데이터의 단일 인스턴스에 대한 예측을 수행할 수 있는 편리한 API입니다. PredictionEngine는 스레드로부터 안전하지 않습니다. 단일 스레드 또는 프로토타입 환경에서 사용할 수 있습니다. 프로덕션 환경에서 성능 및 스레드 보안을 개선하려면 PredictionEnginePool 서비스를 사용합니다. 이 서비스는 애플리케이션 전체에서 사용할 PredictionEngine 개체의 ObjectPool을 만듭니다. ASP.NET Core Web API에서 PredictionEnginePool을 사용하는 방법에 대한 이 가이드를 참조하세요.

참고

PredictionEnginePool 서비스 확장은 현재 미리 보기 상태입니다.

이 자습서에서는 이 클래스 내에서 하나의 테스트 이동을 사용합니다. 나중에 이 모델로 실험할 다른 시나리오를 추가할 수 있습니다. TaxiTrip 인스턴스를 만들어 주행을 추가하여 TestSinglePrediction() 메서드에서 학습된 모델의 비용 예측을 테스트합니다.

var taxiTripSample = new TaxiTrip()
{
    VendorId = "VTS",
    RateCode = "1",
    PassengerCount = 1,
    TripTime = 1140,
    TripDistance = 3.75f,
    PaymentType = "CRD",
    FareAmount = 0 // To predict. Actual/Observed = 15.5
};

이제 택시 이동 데이터의 단일 인스턴스를 기준으로 요금을 예측하고 TestSinglePrediction() 메서드에 다음 코드 줄로 다음을 추가하여 PredictionEngine에 전달합니다.

var prediction = predictionFunction.Predict(taxiTripSample);

Predict() 함수는 단일 데이터 인스턴스에 대한 예측을 수행합니다.

지정한 주행의 예상 운임을 표시하려면 TestSinglePrediction 메서드에 다음 코드를 추가합니다.

Console.WriteLine($"**********************************************************************");
Console.WriteLine($"Predicted fare: {prediction.FareAmount:0.####}, actual fare: 15.5");
Console.WriteLine($"**********************************************************************");

프로그램을 실행하여 테스트 사례에 대해 예측된 택시 요금을 확인합니다.

지금까지 택시 요금 예측을 위한 기계 학습 모델을 성공적으로 빌드하고, 정확도를 평가하고, 예측하는 데 사용했습니다. dotnet/samples GitHub 리포지토리에서 이 자습서의 소스 코드를 찾을 수 있습니다.

다음 단계

본 자습서에서는 다음 작업에 관한 방법을 학습했습니다.

  • 데이터 준비 및 이해
  • 학습 파이프라인 만들기
  • 데이터 로드 및 변환
  • 학습 알고리즘 선택
  • 모델 학습
  • 모델 평가
  • 예측에 모델 사용

다음 자습서로 이동하여 자세히 알아보세요.