IQ Bot:テーブルの列から必要な部分だけを取り出す


帳票例:テーブルの列から必要な部分だけを取り出す

以下の表では、「金額」というひとつの列の中に、金額・税区分(「外税」)・税率という3つの値が入っています。
ここでは、その中から純粋に金額部分だけを取り出したい場合に、どのように対処すればいいかを解説します。

難易度の違い:表をよく見てみよう

このケース、実は表のつくりは同じでも、OCRの取得結果によって対処の方法が違います。

以下の図の左側のように、青い枠が分割したい項目別にきっちり分かれてとれている場合は、とても簡単に対応できます。
一方、図の右側のように、青い枠が項目をまたいでくっついている場合があると、少し対処が難しくなります。

このページでは両方ともやりかたを解説します。

Easyモード:青い枠がきっちり分かれている場合

この場合の対応は簡単。
列値を選択する際に、以下の動画のイメージどおり、ほしい部分の値の幅だけを選択すればOKです。

Hardモード:青い枠がくっついている場合

青い枠がくっついてしまっていると、上記のようにはいきません。
IQ Botは値を青枠のかたまりごとに取得しようとするので、部分的に取得しようとしてもうまくいかないはずです。

Hardモードへの対応方法

Hardモードに対応する場合は、①マッピングでは列全体を取得しつつ、②カスタムロジックで必要な部分だけを取り出すと良いです。

①マッピングのとりかた

②カスタムロジックで必要な部分だけを取り出す

マッピングができたら、カスタムロジックで必要な部分だけを取り出します。
この「必要な部分」がどういう条件で決まるかは帳票によって千差万別なので、一概にパターン化できないのですが、例えば今回の帳票でいえば以下のような分割のしかたが可能です。

方法1:決まった文字列を根拠に分割する

考え方

今回の帳票では、金額は税区分(外税)の前に書いてあるか(パターン①)、単独で書いてあるか(パターン②)のどちらかです。

この考え方に基づいてカスタムロジックを作る場合、実装例は以下のようになります。

実装例

必要な部分だけを取り出す処理の例(決まった文字列で分割)
# 値を保存する変数: table_values
#表の操作をするときに必ず入れるコード(最初)
import pandas as pd
df = pd.DataFrame(table_values)

#############################################
# ↓↓↓ ここからが今回の処理 ↓↓↓ 
#############################################

#金額欄を分割する処理
def bunkatsu(x):
  result = ""
  splitter = ("外税","内税")       #Point1:分割の根拠となる文字列
  for i in splitter:
    if i in x:
      result = x.split(i)[0]      #Point2:↑を根拠に分割した上で、分割したどの部分を取り出すかの指定
  if result == "":
    result = x
  return result

df['金額'] = df['金額'].apply(bunkatsu)

#############################################
# ↑↑↑ ここまでが今回の処理 ↑↑↑
#############################################    

#表の操作をするときに必ず入れるコード(最後)
table_values = df.to_dict()

方法1の応用方法

例えば税区分で「外税」「内税」以外に「非課税」が考えられる場合は、上記のsplitter = ("外税","内税")splitter = ("外税","内税","非課税")のように変更します。

上記は税区分よりも前の部分を取り出していますが、税区分よりも後の部分(税率)を取り出したい場合は、上記のresult = x.split(i)[0][0][1]に変えます。

[0][1]に変えると、なぜ税区分より後の部分が取り出せるのかわからない&知りたい人は、文系初心者でもわかるsplitの説明を読んでみてください。

方法2:「数値以外の文字」を根拠に分割する

上記の処理をさらに一般化して、「数値以外の文字(1~複数)があれば、それを根拠に分割する」という組み方もできます。

注意:この方法は正規表現を使うので、pythonの正規表現ライブラリ(re)を使います。このライブラリは、V11系統では使用できますが、A2019系統の.14以前のバージョンでは使用できません。

必要な部分だけを取り出す処理の例(正規表現で分割)
# 値を保存する変数: table_values
#表の操作をするときに必ず入れるコード(最初)
import pandas as pd
df = pd.DataFrame(table_values)

#############################################
# ↓↓↓ ここからが今回の処理 ↓↓↓ 
#############################################

import re    #正規表現ライブラリのインポート

#金額欄を分割する処理(関数)
def bunkatsu(x):

  #結果の初期化
  result = ""

  #分割の根拠にしたくない文字列を除外
  x = x.replace(" ","")
  x = x.replace(",","")

  #対象の文字列に含まれる数字を取り除く → 数字以外の部分だけが残る (”\d"は正規表現で数字を表す)
  letterX = re.sub("\d","",x) 


  if letterX != "":                  #数字以外の文字列が含まれていたら...(★)
    result = re.split("\D+", x)[0]   #数字以外の文字列で分割した最初のかたまりを取り出してresultに入れる
                                     #"\D+" は正規表現で「数字以外の文字列の任意の数の繰り返し」を表す
  else:                              #★以外(=数字のみ)なら...
    result = x                       #もとの値をそのままresultに入れる

  return result   #resultの中身を返す

#↑ここまでが関数の定義

#金額欄に定義した関数を適用する
df['金額'] = df['金額'].apply(bunkatsu)


#############################################
# ↑↑↑ ここまでが今回の処理 ↑↑↑
#############################################    

#表の操作をするときに必ず入れるコード(最後)
table_values = df.to_dict()

いかがでしたか?

今回はIQ Botで使うカスタムロジックにしては、そこそこ長め&中級編の内容が入ってきました。
わからない部分があった場合は、質問を投稿していただければ回答しますのでお気軽にどうぞ!

それでは!