API への接続: フィードバックの感情を分析する

コーディング レベル: 中級
所要時間: 20 分
プロジェクト タイプ: カスタム メニューを使用した自動化

目標

  • ソリューションの機能を理解します。
  • ソリューション内で Apps Script サービスが何を行うかを理解します。
  • 環境をセットアップする。
  • スクリプトを設定します。
  • スクリプトを実行します。

このソリューションについて

自由回答式フィードバックなどのテキストデータを大規模に分析できます。このソリューションでは、Google スプレッドシート内からエンティティ分析と感情分析を行うために、UrlFetch サービスを使用して Google Cloud Natural Language API に接続します。

感情分析の仕組みの図

仕組み

このスクリプトは、スプレッドシートからテキストを収集し、Google Cloud Natural Language API に接続して、文字列に含まれるエンティティと感情を分析します。ピボット テーブルには、テキストデータのすべての行で言及されている各エンティティの平均感情スコアがまとめられています。

Apps Script サービス

このソリューションでは、次のサービスを使用します。

  • スプレッドシート サービス - テキストデータを Google Cloud Natural Language API に送信し、感情分析が完了した各行を「完了」としてマークします。
  • UrlFetch サービス - Google Cloud Natural Language API に接続して、テキストのエンティティ分析と感情分析を行います。

前提条件

このサンプルを使用するには、次の前提条件を満たしている必要があります。

  • Google アカウント(Google Workspace アカウントの場合、管理者の承認が必要となる可能性があります)。
  • インターネットにアクセスできるウェブブラウザ。

  • 請求先アカウントが関連付けられている Google Cloud プロジェクト。プロジェクトの課金を有効にするを参照してください。

環境の設定

Google Cloud コンソールで Cloud プロジェクトを開く

まだ開いていない場合は、このサンプルで使用する Cloud プロジェクトを開きます。

  1. Google Cloud コンソールで、[プロジェクトを選択] ページに移動します。

    Cloud プロジェクトを選択する

  2. 使用する Google Cloud プロジェクトを選択します。または、[プロジェクトを作成] をクリックし、画面の指示に沿って操作します。Google Cloud プロジェクトを作成する場合は、プロジェクトの課金を有効にする必要がある場合があります。

Google Cloud Natural Language API を有効にする

このソリューションは、Google Cloud Natural Language API に接続します。Google API を使用する前に、Google Cloud プロジェクトで API を有効にする必要があります。1 つの Google Cloud プロジェクトで 1 つ以上の API を有効にできます。

このソリューションには、同意画面が構成された Cloud プロジェクトが必要です。OAuth 同意画面を構成することで、Google がユーザーに表示する内容を定義し、後でアプリを公開できるようにアプリを登録します。

  1. Google Cloud コンソールで、メニュー > Google Auth platform > [ブランディング] に移動します。

    [ブランディング] に移動

  2. Google Auth platformをすでに構成している場合は、[ブランディング]、[対象ユーザー]、[データアクセス] で次の OAuth 同意画面の設定を構成できます。[Google Auth platform まだ設定されていません] というメッセージが表示された場合は、[使ってみる] をクリックします。
    1. [アプリ情報] の [アプリ名] に、アプリの名前を入力します。
    2. [ユーザー サポートメール] で、ユーザーが同意について問い合わせる際に使用するサポートのメールアドレスを選択します。
    3. [続行] をクリックします。
    4. [対象] で [内部] を選択します。
    5. [続行] をクリックします。
    6. [連絡先情報] で、プロジェクトに対する変更の通知を受け取るメールアドレスを入力します。
    7. [続行] をクリックします。
    8. [完了] で、Google API サービスのユーザーデータに関するポリシーを確認し、同意する場合は [Google API サービス: ユーザーデータに関するポリシーに同意します] を選択します。
    9. [続行] をクリックします。
    10. [作成] をクリックします。
  3. 現時点では、スコープの追加はスキップできます。今後、Google Workspace 組織外で使用するアプリを作成する場合は、[ユーザータイプ] を [外部] に変更する必要があります。次に、アプリに必要な認可スコープを追加します。詳細については、OAuth 同意画面を構成するの完全なガイドをご覧ください。

Google Cloud Natural Language API の API キーを取得する

  1. Google Cloud コンソールに移動します。 課金が有効になっているプロジェクトが開いていることを確認します。
  2. Google Cloud コンソールで、メニュー > [API とサービス] > [認証情報] に移動します。

    [認証情報] に移動

  3. [認証情報を作成] > [API キー] をクリックします。

  4. 後の手順で使用するために、API キーを書き留めます。

スクリプトを設定する

Apps Script プロジェクトを作成する

  1. 下のボタンをクリックして、フィードバックの感情分析のサンプル スプレッドシートのコピーを作成します。このソリューションの Apps Script プロジェクトはスプレッドシートに添付されています。
    コピーを作成
  2. [拡張機能] > [Apps Script] をクリックします。
  3. スクリプト ファイル内の次の変数を API キーで更新します。
    const myApiKey = 'YOUR_API_KEY'; // Replace with your API key.
  4. 保存アイコン[保存] をクリックします。

テキストデータを追加する

  1. スプレッドシートに戻ります。
  2. id 列と comments 列にテキストデータを追加します。Kaggle のサンプル宿泊施設のレビューを使用するか、独自のデータを使用できます。必要に応じて列を追加できますが、スクリプトを正常に実行するには、id 列と comments 列にデータが含まれている必要があります。

スクリプトを実行する

  1. スプレッドシートの上部にある [感情分析ツール] > [エンティティと感情をマークする] をクリックします。このカスタム メニューを表示するには、ページの更新が必要になる場合があります。
  2. メッセージが表示されたら、スクリプトを承認します。OAuth 同意画面に「このアプリは確認されていません」という警告が表示された場合は、[詳細] > [{プロジェクト名} に移動(安全でない)] を選択して続行します。

  3. [Sentiment Tools] > [Mark entities and sentiment] をもう一度クリックします。

  4. スクリプトが終了したら、[ピボット テーブル] シートに切り替えて結果を確認します。

コードを確認する

このソリューションの Apps Script コードを確認するには、下の [ソースコードを表示] をクリックします。

ソースコードを表示

コード.gs

solutions/automations/feedback-sentiment-analysis/code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/automations/feedback-sentiment-analysis

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Sets API key for accessing Cloud Natural Language API.
const myApiKey = 'YOUR_API_KEY'; // Replace with your API key.

// Matches column names in Review Data sheet to variables.
let COLUMN_NAME = {
  COMMENTS: 'comments',
  ENTITY: 'entity_sentiment',
  ID: 'id'
};

/**
 * Creates a Demo menu in Google Spreadsheets.
 */
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Sentiment Tools')
    .addItem('Mark entities and sentiment', 'markEntitySentiment')
    .addToUi();
};

/**
* Analyzes entities and sentiment for each comment in  
* Review Data sheet and copies results into the 
* Entity Sentiment Data sheet.
*/
function markEntitySentiment() {
  // Sets variables for "Review Data" sheet
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let dataSheet = ss.getSheetByName('Review Data');
  let rows = dataSheet.getDataRange();
  let numRows = rows.getNumRows();
  let values = rows.getValues();
  let headerRow = values[0];

  // Checks to see if "Entity Sentiment Data" sheet is present, and
  // if not, creates a new sheet and sets the header row.
  let entitySheet = ss.getSheetByName('Entity Sentiment Data');
  if (entitySheet == null) {
   ss.insertSheet('Entity Sentiment Data');
   let entitySheet = ss.getSheetByName('Entity Sentiment Data');
   let esHeaderRange = entitySheet.getRange(1,1,1,6);
   let esHeader = [['Review ID','Entity','Salience','Sentiment Score',
                    'Sentiment Magnitude','Number of mentions']];
   esHeaderRange.setValues(esHeader);
  };

  // Finds the column index for comments, language_detected, 
  // and comments_english columns.
  let textColumnIdx = headerRow.indexOf(COLUMN_NAME.COMMENTS);
  let entityColumnIdx = headerRow.indexOf(COLUMN_NAME.ENTITY);
  let idColumnIdx = headerRow.indexOf(COLUMN_NAME.ID);
  if (entityColumnIdx == -1) {
    Browser.msgBox("Error: Could not find the column named " + COLUMN_NAME.ENTITY + 
                   ". Please create an empty column with header \"entity_sentiment\" on the Review Data tab.");
    return; // bail
  };

  ss.toast("Analyzing entities and sentiment...");
  for (let i = 0; i < numRows; ++i) {
    let value = values[i];
    let commentEnCellVal = value[textColumnIdx];
    let entityCellVal = value[entityColumnIdx];
    let reviewId = value[idColumnIdx];

    // Calls retrieveEntitySentiment function for each row that has a comment 
    // and also an empty entity_sentiment cell value.
    if(commentEnCellVal && !entityCellVal) {
        let nlData = retrieveEntitySentiment(commentEnCellVal);
        // Pastes each entity and sentiment score into Entity Sentiment Data sheet.
        let newValues = []
        for (let entity in nlData.entities) {
          entity = nlData.entities [entity];
          let row = [reviewId, entity.name, entity.salience, entity.sentiment.score, 
                     entity.sentiment.magnitude, entity.mentions.length
                    ];
          newValues.push(row);
        }
      if(newValues.length) {
        entitySheet.getRange(entitySheet.getLastRow() + 1, 1, newValues.length, newValues[0].length).setValues(newValues);
      }
        // Pastes "complete" into entity_sentiment column to denote completion of NL API call.
        dataSheet.getRange(i+1, entityColumnIdx+1).setValue("complete");
     }
   }
};

/**
 * Calls the Cloud Natural Language API with a string of text to analyze
 * entities and sentiment present in the string.
 * @param {String} the string for entity sentiment analysis
 * @return {Object} the entities and related sentiment present in the string
 */
function retrieveEntitySentiment (line) {
  let apiKey = myApiKey;
  let apiEndpoint = 'https://language.googleapis.com/v1/documents:analyzeEntitySentiment?key=' + apiKey;
  // Creates a JSON request, with text string, language, type and encoding
  let nlData = {
    document: {
      language: 'en-us',
      type: 'PLAIN_TEXT',
      content: line
    },
    encodingType: 'UTF8'
  };
  // Packages all of the options and the data together for the API call.
  let nlOptions = {
    method : 'post',
    contentType: 'application/json',  
    payload : JSON.stringify(nlData)
  };
  // Makes the API call.
  let response = UrlFetchApp.fetch(apiEndpoint, nlOptions);
  return JSON.parse(response);
};

寄稿者

このサンプルは、Google デベロッパー エキスパートの協力を得て Google が管理しています。

次のステップ