Google Cloud Natural Language APIを使ったテキストのカテゴリ分類

テキストの分類はその目的によって、様々な方法がとられます。Sentiment分析やEmotion分析も分類タスクの一つと考えられます。これらはテキストと分類結果との組み合わせを学習させることにより、実現しています。

以下の記事では文章ベクトルのコサイン類似度を使って、話題の分類をすることを試してみました。

sentenceBERTによる分類例

音声チャットボットの開発では、応答を生成するために、事前学習済みのT5モデルに、対話データを学習させました。 このモデルは、どんな話題をしているのかを理解している…

こちらは、学習はしていませんが、いくつかのワードの平均値を求めることで、一番ちかい話題を推定するということをしています。この時、問題となったのは「どういうカテゴリに分類するか?」ということです。 例えば商品レビューの分析のように分析対象が決まっていれば、カテゴリを決めておくこともできますが、雑談を分類しようとすると、カテゴリの数が増えてしまい、なかなか大変そうです。

Googleのカテゴリ分類 (オンラインデモ)

そこで、Google CloudのNatural Language APIの一つの機能であるカテゴリ分類を試してみることにしました。

分類されるカテゴリは、こちらです。

体系的に620のカテゴリが定義されています。

テキストボックスに対象の文章を入力して「分類」ボタンを押すと、先ほどのカテゴリ分類と信頼スコア(confidence)が表示されます。

Sample Code

Google Cloudのチュートリアルは、pythonで記述されていますので、上記デモのFlutterのサンプルコードを記載しておきます。

まず、以下のパッケージをインストールしておきます。

flutter pub add http
flutter pub add google_fonts      

mainのコードは以下の様になります。

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:google_fonts/google_fonts.dart'; 

final categoryUrl = Uri.parse(
    'https://cloud.google.com/natural-language/docs/categories?hl=ja');

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Classification Demo',
      theme: ThemeData(
        textTheme: GoogleFonts.kosugiMaruTextTheme(Theme.of(context).textTheme),
        primarySwatch: Colors.blue,
      ),
      home: const ClassificationPage(),
    );
  }
}

class ClassificationPage extends StatefulWidget {
  const ClassificationPage({super.key});

  @override
  State createState() => _ClassificationPage();
}

class _ClassificationPage extends State {
  final TextEditingController _textController = TextEditingController();
  String classifyResult = '';
  String key = '<Your API key>';  // Google Cloud からAPIを有効にしてキーを取得する
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Classification Sample'),
      ),
      body: Container(
        padding: const EdgeInsets.all(10.0),
        child: Center(
          child: Column(
            children: [
              TextField(
                maxLength: 300,
                keyboardType: TextInputType.multiline,
                maxLines: 5,
                minLines: 5,
                autofocus: true,
                controller: _textController,
                textInputAction: TextInputAction.next,
                decoration: const InputDecoration(
                  hintText: '分類する文章を入力してください。',
                  labelText: 'Input Text',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(
                      Radius.circular(10),
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () {
                  //classification(translateResult);
                  classification(_textController.text);
                },
                child: const Text('分類'),
              ),
              const SizedBox(height: 10),
              Text(classifyResult),
              const SizedBox(height: 10),
            ],
          ),
        ),
      ),
    );
  }

  void classification(query) async {
    String url = "https://language.googleapis.com/v1/documents:classifyText";
    String classsifyUrl = "$url?key=$key";

    String body = json.encode({
      "document": {"type": "PLAIN_TEXT", "language": "ja", "content": query},
      "classificationModelOptions": {
        "v2Model": {"contentCategoriesVersion": "V2"}
      }
    });

    http.Response resp = await http.post(Uri.parse(classsifyUrl), body: body);

    var decode = json.decode(resp.body);

    setState(() {
      classifyResult = decode.toString();
    });
  }
}

void classification()に、テキストを引数として渡すと、分類結果をclassifyResultにセットしています。

ニュースサイトの記事や、様々なブログを入力してみると、うまく分類できている様です。よろしければお試しください。