자습서: ML.NET에서 이진 분류를 사용하여 웹 사이트 주석의 감정 분석

이 자습서에서는 웹 사이트 주석에서 감정을 분류하고 적절한 조치를 취하는 .NET Core 콘솔 애플리케이션을 만드는 방법을 보여 줍니다. 감정 이진 분류자는 Visual Studio 2022에서 C#을 사용합니다.

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

  • 콘솔 애플리케이션 만들기
  • 데이터 준비
  • 데이터 로드
  • 모델 빌드 및 학습
  • 모델 평가
  • 모델로 예측 수행
  • 결과 보기

dotnet/samples 리포지토리에서 이 자습서의 소스 코드를 찾을 수 있습니다.

사전 요구 사항

콘솔 애플리케이션 만들기

  1. "SentimentAnalysis"라는 C# 콘솔 애플리케이션을 만듭니다. 다음 단추를 클릭합니다.

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

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

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

    참고

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

    솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 NuGet 패키지 관리를 선택합니다. 패키지 소스로 "nuget.org"를 선택하고 찾아보기 탭을 선택합니다. Microsoft.ML을 검색하고 원하는 패키지를 선택한 다음, 설치 단추를 선택합니다. 선택한 패키지의 사용 조건에 동의하여 설치를 진행합니다.

데이터 준비

참고

이 자습서의 데이터 세트는 '심층 기능을 사용하는 그룹에서 개별 레이블로', Kotzias 등입니다. 알. KDD 2015)에서 제공되고 UCI Machine Learning Repository(Dua, D. 및 Karra Taniskidou, E. (2017))에서 호스트됩니다. UCI Machine Learning Repository[http://archive.ics.uci.edu/ml ]. Irvine, CA: University of California, School of Information and Computer Science.

  1. UCI Sentiment Labeled Sentences 데이터 세트 ZIP 파일을 다운로드하여 압축을 풉니다.

  2. 만든 Data 디렉터리에 yelp_labelled.txt 파일을 복사합니다.

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

클래스 만들기 및 경로 정의

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

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using SentimentAnalysis;
    using static Microsoft.ML.DataOperationsCatalog;
    
  2. using 문 바로 아래 줄에 다음 코드를 추가하여 최근에 다운로드한 데이터 세트 파일 경로를 유지할 필드를 만듭니다.

    string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "yelp_labelled.txt");
    
  3. 이제 입력 데이터 및 예측에 대한 클래스를 만듭니다. 새 클래스를 프로젝트에 추가합니다.

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

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

  4. SentimentData.cs 파일이 코드 편집기에서 열립니다. 다음 using 문을 SentimentData.cs의 맨 위에 추가합니다.

    using Microsoft.ML.Data;
    
  5. 기존 클래스 정의를 제거하고 두 개의 클래스 SentimentDataSentimentPrediction가 있는 다음 코드를 SentimentData.cs 파일에 추가합니다.

    public class SentimentData
    {
        [LoadColumn(0)]
        public string? SentimentText;
    
        [LoadColumn(1), ColumnName("Label")]
        public bool Sentiment;
    }
    
    public class SentimentPrediction : SentimentData
    {
    
        [ColumnName("PredictedLabel")]
        public bool Prediction { get; set; }
    
        public float Probability { get; set; }
    
        public float Score { get; set; }
    }
    

데이터를 준비하는 방법

입력 데이터 세트 클래스 SentimentData는 사용자 주석에 대한 string(SentimentText) 및 감정에 대해 1(긍정) 또는 0(부정) 값을 갖는 bool(Sentiment) 값을 갖습니다. 두 필드에는 각 필드의 데이터 파일 순서를 설명하는 LoadColumn 특성이 연결되어 있습니다. 또한 Sentiment 속성에는 Label 필드로 지정하는 ColumnName 특성이 있습니다. 다음 예제 파일에는 머리글 행이 없고 다음과 같이 표시됩니다.

SentimentText 감정(레이블)
웨이트리스의 서비스가 좀 느렸습니다. 0
모양이 별로 였습니다. 0
우와... 여기가 좋았습니다. 1
서비스가 매우 신속합니다. 1

SentimentPrediction은 모델 학습 후에 사용되는 예측 클래스입니다. 출력 예측과 함께 입력 SentimentText를 표시할 수 있도록 SentimentData에서 상속됩니다. Prediction 부울은 새 입력 SentimentText와 함께 제공될 때 모델이 예측하는 값입니다.

출력 클래스 SentimentPrediction에는 Score(모델에서 계산한 원시 점수) 및 Probability(긍정적인 감정이 있는 텍스트의 가능성에 따라 조정된 점수)가 포함되어 있습니다.

이 자습서에서 가장 중요한 속성은 Prediction입니다.

데이터 로드

ML.NET의 데이터는 IDataView 인터페이스로 표시됩니다. IDataView는 표 형식 데이터(숫자 및 텍스트)를 유연하고 효율적으로 설명하는 방법입니다. 데이터를 텍스트 파일 또는 실시간(예: SQL 데이터베이스 또는 로그 파일)에서 IDataView 개체로 로드할 수 있습니다.

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

앱을 준비한 다음, 데이터를 로드합니다.

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

    MLContext mlContext = new MLContext();
    
  2. 다음 코드 줄로 다음을 추가합니다.

    TrainTestData splitDataView = LoadData(mlContext);
    
  3. 다음 코드를 사용하여 Program.cs 파일 하단에 LoadData() 메서드를 만듭니다.

    TrainTestData LoadData(MLContext mlContext)
    {
    
    }
    

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

    • 데이터를 로드합니다.
    • 로드된 데이터 세트를 학습 및 테스트 세트로 분할합니다.
    • 분할된 학습 및 테스트 데이터 세트를 반환합니다.
  4. 다음 코드를 LoadData() 메서드의 첫 번째 줄로 추가합니다.

    IDataView dataView = mlContext.Data.LoadFromTextFile<SentimentData>(_dataPath, hasHeader: false);
    

    LoadFromTextFile() 메서드는 데이터 스키마를 정의하고 파일에서 읽습니다. 데이터 경로 변수를 가져와서 IDataView를 반환합니다.

데이터 세트를 모델 학습 및 테스트용으로 분할

모델을 준비할 때는 일부 데이터 세트는 학습에, 일부 데이터 세트는 모델 정확도 테스트에 사용합니다.

  1. 로드된 데이터를 필요한 데이터 세트로 분할하려면 LoadData() 메서드에 아래 코드를 다음 줄로 추가합니다.

    TrainTestData splitDataView = mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2);
    

    이전 코드는 TrainTestSplit() 메서드를 사용하여 로드된 데이터 세트를 학습으로 분할하고 데이터 세트를 테스트하며 DataOperationsCatalog.TrainTestData 클래스에 반환합니다. testFraction 매개 변수로 데이터의 테스트 집합 백분율을 지정합니다. 기본값은 10%이며, 여기서는 20%를 사용하여 데이터를 더 평가합니다.

  2. splitDataView 메서드의 끝에 LoadData()를 반환합니다.

    return splitDataView;
    

모델 빌드 및 학습

  1. LoadData 메서드에 대한 호출 아래 BuildAndTrainModel 메서드에 다음 호출을 추가합니다.

    ITransformer model = BuildAndTrainModel(mlContext, splitDataView.TrainSet);
    

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

    • 데이터를 추출하고 변환합니다.
    • 모델을 학습시킵니다.
    • 테스트 데이터를 기반으로 감정을 예측합니다.
    • 모델을 반환합니다.
  2. 다음 코드를 사용하여 LoadData() 메서드 아래에 BuildAndTrainModel() 메서드를 만듭니다.

    ITransformer BuildAndTrainModel(MLContext mlContext, IDataView splitTrainSet)
    {
    
    }
    

데이터 추출 및 변환

  1. FeaturizeText를 다음 코드 줄로 추가합니다.

    var estimator = mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: nameof(SentimentData.SentimentText))
    

    이전 코드의 FeaturizeText() 메서드는 텍스트 열(SentimentText)을 기계 학습 알고리즘에서 사용하는 숫자 키 형식 Features 열로 변환하여 새 데이터 세트 열로 추가합니다.

    SentimentText 감정 기능
    웨이트리스의 서비스가 좀 느렸습니다. 0 [0.76, 0.65, 0.44, …]
    모양이 별로 였습니다. 0 [0.98, 0.43, 0.54, …]
    우와... 여기가 좋았습니다. 1 [0.35, 0.73, 0.46, …]
    서비스가 매우 신속합니다. 1 [0.39, 0, 0.75, …]

학습 알고리즘 추가

이 앱은 항목 또는 데이터 행을 분류하는 분류 알고리즘을 사용합니다. 앱은 웹 사이트 주석을 긍정 또는 부정으로 분류하므로 이진 분류 작업을 사용합니다.

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

.Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features"));

SdcaLogisticRegressionBinaryTrainer는 분류 학습 알고리즘입니다. 이것은 estimator에 추가되며, 기록 데이터에서 학습할 기능화된 SentimentText(Features) 및 Label 입력 매개 변수를 수락합니다.

모델 학습

모델을 splitTrainSet 데이터에 맞추고 BuildAndTrainModel() 메서드에서 다음 줄의 코드로 다음 항목을 추가하여 학습된 모델을 반환합니다.

Console.WriteLine("=============== Create and Train the Model ===============");
var model = estimator.Fit(splitTrainSet);
Console.WriteLine("=============== End of training ===============");
Console.WriteLine();

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

평가에 사용하기 위해 학습된 모델 반환

BuildAndTrainModel() 메서드의 끝에 모델을 반환합니다.

return model;

모델 평가

모델을 학습한 후 테스트 데이터를 사용하여 모델의 성능 유효성을 검사합니다.

  1. 다음 코드로 BuildAndTrainModel() 바로 뒤에 Evaluate() 메서드를 만듭니다.

    void Evaluate(MLContext mlContext, ITransformer model, IDataView splitTestSet)
    {
    
    }
    

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

    • 테스트 데이터 세트를 로드합니다.
    • BinaryClassification 평가자를 만듭니다.
    • 모델을 평가하고 메트릭을 만듭니다.
    • 메트릭을 표시합니다.
  2. 다음 코드를 사용하여 BuildAndTrainModel 메서드 호출 아래에 새 메서드 호출을 추가합니다.

    Evaluate(mlContext, model, splitDataView.TestSet);
    
  3. Evaluate()에 다음 코드를 추가하여 splitTestSet데이터를 변환합니다.

    Console.WriteLine("=============== Evaluating Model accuracy with Test data===============");
    IDataView predictions = model.Transform(splitTestSet);
    

    이전 코드는 Transform() 메서드를 사용하여 여러 제공된 테스트 데이터 세트 입력 행에 대한 예측을 합니다.

  4. Evaluate() 메서드에서 다음 코드 줄로 다음 항목을 추가하여 모델을 평가합니다.

    CalibratedBinaryClassificationMetrics metrics = mlContext.BinaryClassification.Evaluate(predictions, "Label");
    

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

모델 유효성 검사를 위해 메트릭 표시

다음 코드를 사용하여 메트릭을 표시합니다.

Console.WriteLine();
Console.WriteLine("Model quality metrics evaluation");
Console.WriteLine("--------------------------------");
Console.WriteLine($"Accuracy: {metrics.Accuracy:P2}");
Console.WriteLine($"Auc: {metrics.AreaUnderRocCurve:P2}");
Console.WriteLine($"F1Score: {metrics.F1Score:P2}");
Console.WriteLine("=============== End of model evaluation ===============");
  • Accuracy 메트릭은 테스트 세트에서 정확한 예측의 비율인 모델 정확도를 가져옵니다.

  • AreaUnderRocCurve 메트릭은 모델이 긍정 및 부정 클래스 분류의 정확도를 자신하는 정도를 표시합니다. AreaUnderRocCurve를 가능한 근접하게 하고자 합니다.

  • F1Score 메트릭은 모델의 F1 점수를 가져옵니다. 정밀도회수 사이의 균형을 측정한 값입니다. F1Score를 가능한 근접하게 하고자 합니다.

테스트 데이터 결과 예측

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

    void UseModelWithSingleItem(MLContext mlContext, ITransformer model)
    {
    
    }
    

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

    • 테스트 데이터의 단일 댓글을 만듭니다.
    • 테스트 데이터를 기반으로 감정을 예측합니다.
    • 보고를 위해 테스트 데이터 및 예측을 결합합니다.
    • 예측 결과를 표시합니다.
  2. 다음 코드를 사용하여 Evaluate() 메서드 호출 바로 아래에 새 메서드 호출을 추가합니다.

    UseModelWithSingleItem(mlContext, model);
    
  3. 다음 코드를 추가하여 UseModelWithSingleItem() 메서드의 첫 줄로 만듭니다.

    PredictionEngine<SentimentData, SentimentPrediction> predictionFunction = mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);
    

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

    참고

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

  4. SentimentData 인스턴스를 만들어 댓글을 추가하여 UseModelWithSingleItem() 메서드에서 학습된 모델의 예측을 테스트합니다.

    SentimentData sampleStatement = new SentimentData
    {
        SentimentText = "This was a very bad steak"
    };
    
  5. 다음을 UseModelWithSingleItem() 메서드의 다음 코드 줄로 추가하여 테스트 주석 데이터를 PredictionEngine에 전달합니다.

    var resultPrediction = predictionFunction.Predict(sampleStatement);
    

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

  6. 다음 코드를 사용하여 SentimentText 및 해당 감정 예측을 표시합니다.

    Console.WriteLine();
    Console.WriteLine("=============== Prediction Test of model with a single sample and test dataset ===============");
    
    Console.WriteLine();
    Console.WriteLine($"Sentiment: {resultPrediction.SentimentText} | Prediction: {(Convert.ToBoolean(resultPrediction.Prediction) ? "Positive" : "Negative")} | Probability: {resultPrediction.Probability} ");
    
    Console.WriteLine("=============== End of Predictions ===============");
    Console.WriteLine();
    

예측에 모델 사용

일괄 처리 항목 배포 및 예측

  1. 다음 코드를 사용하여 UseModelWithSingleItem() 메서드 바로 뒤에 UseModelWithBatchItems() 메서드를 만듭니다.

    void UseModelWithBatchItems(MLContext mlContext, ITransformer model)
    {
    
    }
    

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

    • 일괄 처리 테스트 데이터를 만듭니다.
    • 테스트 데이터를 기반으로 감정을 예측합니다.
    • 보고를 위해 테스트 데이터 및 예측을 결합합니다.
    • 예측 결과를 표시합니다.
  2. 다음 코드를 사용하여 UseModelWithSingleItem() 메서드 호출 바로 아래에 새 메서드 호출을 추가합니다.

    UseModelWithBatchItems(mlContext, model);
    
  3. 몇몇 댓글을 추가하여 UseModelWithBatchItems() 메서드에서 학습된 모델의 예측을 테스트합니다.

    IEnumerable<SentimentData> sentiments = new[]
    {
        new SentimentData
        {
            SentimentText = "This was a horrible meal"
        },
        new SentimentData
        {
            SentimentText = "I love this spaghetti."
        }
    };
    

주석 감정 예측

모델을 사용하여 Transform() 메서드를 통한 주석 데이터 감정 예측:

IDataView batchComments = mlContext.Data.LoadFromEnumerable(sentiments);

IDataView predictions = model.Transform(batchComments);

// Use model to predict whether comment data is Positive (1) or Negative (0).
IEnumerable<SentimentPrediction> predictedResults = mlContext.Data.CreateEnumerable<SentimentPrediction>(predictions, reuseRowObject: false);

예측 결합 및 표시

다음 코드를 사용하여 예측에 대한 헤더를 만듭니다.

Console.WriteLine();

Console.WriteLine("=============== Prediction Test of loaded model with multiple samples ===============");

SentimentPredictionSentimentData에서 상속되므로 Transform() 메서드가 예측된 필드로 SentimentText를 입력했습니다. ML.NET 프로세스를 처리하면서 각 구성 요소가 열을 추가하므로 결과를 쉽게 표시합니다.

foreach (SentimentPrediction prediction  in predictedResults)
{
    Console.WriteLine($"Sentiment: {prediction.SentimentText} | Prediction: {(Convert.ToBoolean(prediction.Prediction) ? "Positive" : "Negative")} | Probability: {prediction.Probability} ");
}
Console.WriteLine("=============== End of predictions ===============");

결과

다음과 같은 결과가 나타나야 합니다. 처리 중 메시지가 표시됩니다. 경고 또는 메시지 처리를 확인할 수 있습니다. 이해하기 쉽도록 이러한 결과는 다음 결과에서 제거되었습니다.

Model quality metrics evaluation
--------------------------------
Accuracy: 83.96%
Auc: 90.51%
F1Score: 84.04%

=============== End of model evaluation ===============

=============== Prediction Test of model with a single sample and test dataset ===============

Sentiment: This was a very bad steak | Prediction: Negative | Probability: 0.1027377
=============== End of Predictions ===============

=============== Prediction Test of loaded model with a multiple samples ===============

Sentiment: This was a horrible meal | Prediction: Negative | Probability: 0.1369192
Sentiment: I love this spaghetti. | Prediction: Positive | Probability: 0.9960636
=============== End of predictions ===============

=============== End of process ===============
Press any key to continue . . .

지금까지 이제 메시지 감정을 분류하고 예측하기 위한 기계 학습 모델을 성공적으로 빌드했습니다.

성공한 모델 빌드하는 것은 반복적인 프로세스입니다. 자습서에서는 작은 데이터 세트를 사용하여 빠른 모델 학습을 제공하므로 이 모델은 초기 품질이 좋지 않습니다. 모델 품질에 만족하지 않는 경우 더 큰 학습 데이터 세트를 제공하거나 각 알고리즘에 대한 다양한 하이퍼 매개 변수와 함께 다양한 학습 알고리즘을 선택하여 모델 품질을 개선할 수 있습니다.

dotnet/samples 리포지토리에서 이 자습서의 소스 코드를 찾을 수 있습니다.

다음 단계

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

  • 콘솔 애플리케이션 만들기
  • 데이터 준비
  • 데이터 로드
  • 모델 빌드 및 학습
  • 모델 평가
  • 모델로 예측 수행
  • 결과 보기

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