こんにちは、Pythonエンジニア育成推進協会 顧問理事の寺田です。私は試験の問題策定とコミュニティ連携を行う立場です。
2024年9月に公開されたPython3エンジニア認定データ分析実践試験の主教材の後半には、時系列データ、テキストデータ、画像データ、グラフデータ、地理空間データの5つ各種データの取り扱いに関する解説が入っており、すべて出題範囲となっています。どれも重要なものではありますが、関わりがない人にとっては難しいものもありますので、こちらのコラムを使って順番に簡単な説明をしていこうと考えています。
前回は時系列データについてお話しましたが、今回はテキストデータの処理(7章)についてお話したいと思います。
※Python 3 エンジニア認定データ分析実践試験
https://www.pythonic-exam.com/cpda
※前回のコラムは以下よりご覧いただけます。
データ分析実践試験のヒント「時系列データ処理」
■データ分析におけるテキストデータ処理を学ぶ必要性
データ分析におけるテキストデータの処理は、分野によっては非常に重要です。例えば、アンケートの内容の分析や、LLMなどのディープラーニング技術を使ったAI的なものにも文字列の処理が必要だからです。数値予測的なデータ分析を得意とする人にとっては、テキスト処理は普段そう関わる分野ではないと思いますが、データ分析を進めるにはテキストの処理ができるようになっておくことはとても大切です。
この実践試験では、テキストを最低限扱えるようになっていることを求めています。ただ、テキストデータの処理から進んだ先、例えば機械学習やディープラーニングをどのようにするかは、分野ごとの違いや、得意不得意などの個人的な事情もあるため試験範囲からは外されています。
書籍の中では、テキストデータの処理方法として、Pythonでやる方法と、pandasでやる方法の2つが説明されています。パターンとしては、Pythonだけでやる、pandasだけでやる、両方使ってやるというものがありますので、どちらの方法も使えるようになっておくと、より柔軟に対応できるようになると思います。
■Pythonを使った文字列処理
さて、テキスト処理において重要な技術のひとつに、正規表現があります。正規表現はとても難しい技術で、多くの言語で、正規表現を利用して処理することがあります。。
しかし、Pythonはテキスト処理が非常に得意な言語で、正規表現なしでもある程度のことなら文字列を処理することができます。むしろ、Pythonではできるだけ正規表現を使わずにやるという考えが一般的です。
というのも、正規表現は、わかる人にとっては使うのも、読み解くのも問題はないのですが、分からない人にとっては使いにくい上に、中身を理解しにくく、可読性が悪くなります。その結果、バグが入りやすくなってしまいます。
とはいえ、正規表現ができないと、テキスト処理が完全にできるようになったという事にはならないため、主教材では、あえて最初に正規表現での処理を説明しています。
■正規表現について
ところで、初心者向け講習をしてると、「正規表現とは何か」と問われることがよくあります。
正規表現を使うと、文章の中から、定めたあるルールにマッチするかしないか、つまり、検索的なことや、改行(\n)の指定、テキストの置換などができます。
例えば、検索的な利用の応用として、Webフォームで入力された郵便番号が、郵便番号のフォーマット(3桁-4桁)に合っているかを調べる時に正規表現を用いると、フォーマットに合っているかを判定することができます。このように正規表現は、文字が、決められたルールにマッチしているかを検索することができます。
また、より高度な処理として、置き換えや変換、グループ化してピックアップするといったようなこともできます。郵便番号やメールアドレスのようなものの場合は、ほとんど決まった正規表現が使われますが、正規表現にはいくつかの表現方法があります。ただ、正規表現のルールを覚えるのがとても難しいのです。
主教材では正規表現の使い方について簡単に説明されています。
使い方を理解しておくことは必要なので、別の本などで集中して勉強しておくと、データ分析の中でもテキスト分析の世界での幅が広がると思います。
ちなみに正規表現ができると、他の言語でも利用できるので、エンジニアとしてかっこいいね、なんて言われることがあります。
そんな正規表現をPythonでどのように利用するかを、書籍ではルビの処理を例に解説しています。
Pythonで正規表現を使う際、正規表現用の標準ライブラリreをインポート[import re]して、コンパイルします。コンパイルの必要性については色々と議論の対象ではありますが、一般的には最初に正規表現に利用するものをコンパイルしてから、[.findall]や[.serach]メソッドを利用します。この正規表現の文字列を作る時、「r」プリフェックスが一般的にt使われ。「r」以外のプリフィックスには「f」フォーマット文字、「b」バイト文字列を宣言するというものがありますが、「r」はロー文字列を意味します。
先ほど挙げた改行コードである「\n(バックスラッシュn)」のように、正規表現の中にはバックスラッシュを使ったメタ文字がたくさんあります。バックスラッシュをPythonの文字列を表す「”(ダブルクォーテーション)」の中に書いてしまうと、バックスラッシュが別の意味を持ってしまいます。
例えば、「\”」と書くと、「\」の後ろにある「”」は、文字列を区切るための「”」ではなく、内部に「”」の文字列が宣言されているという時に使うための「\」という意味になってしまいますが、rプリフェックスを付けることによって、「\」はそのままの意味の「\」であり、別のものではないことを宣言できます。もしrプリフィックスを使わずに「\d」を表すとすると、「\\d」と書かないといけなくなります。こうなると読みにくくなってしまうため、rを使って「\を特別扱いしませんよ」と宣言するというのが正規表現ではよく使われる方法です。
もちろんrを使わなくてもいい場合はありますが、一般的に正規表現の中に「\」がたくさん出てくることが多いため、通常はrプリフェックスを使って文字列を宣言します。その後、コンパイルしたものが正規表現オブジェクトになるので、[.find]や[sub]などで置き換え、文字列の置き換えなどをメソッドで行えるようになります。
繰り返しになりますが、Pythonは正規表現を使わなくても使うことができます。
例えば、文字列の最後の文字が、「sで終わるか」を聞くだけであれば、Pythonの文字列型のメソッドにある[endswith]を使えば「s」で終わっているかを聞くことができますので、正規表現をあえて使う必要はありません。
この書籍では、Pythonでの正規表現の使い方を理解してもらう程度になっており、試験もそういった内容になっています。とはいえ、確かに正規表現ができれば、本当に便利ではありますので、深く正規表現を理解したい場合には別で勉強していただければと思います。
■複数行のテキストデータ処理
次に、書籍では複数行のテキストデータ処理について、open関数を使ったデータの処理が説明されています。open関数のポイントは3つです。
- with構文を利用する
ファイルをオープンする時、閉じる作業をするのはOSとのお約束であるため、[f=open()]で開き、[f.close()]とする必要があります。それらを自動でやってくれるwith構文がありますので、それを利用するようにして、閉じ忘れを防止しましょう。 - openで開いたファイル「f」は繰り返し可能オブジェクトである
openで開いたファイルを一般的には「f」に置き換えますが、「f」は繰り返し可能オブジェクトです。書籍ではあえて、rモード(読み込みモード)で読んでおり、「f」は改行ごとに1行ずつ取り出せる仕組みになっています。「f」には[readlines()]などのメソッドがありますが、[readlines()]を使うと、リストを作ってしまうため、長いテキストになり、メモリ効率が悪くなります。「f」は、for文に直接渡せる繰り返し可能オブジェクトで1行ずつ取り出せるという特徴があるため、一般的にはこの「f」を直接for文に渡します。 - openする時にエンコーディングUTF-8を指定する
特に日本語を扱っている時、一般的にはエンコーディングUTF-8をopen関数の引数として入れます。環境によってはUTF-8でなくなってしまうことがあるため、今のところ重要な設定です。多くの場合、日本語でmacOSを使っているのなら、ほとんどの場合問題ありませんが、Windowsを使っている場合は、別のエンコーディングShift_JISを拡張させたCP932が日本語のWindowsの場合使われる仕組みになっています。エンコーディングを意識することは、テキスト処理をする上では非常に重要なポイントになります。
文字エンコーディングについて
ここで少し、文字エンコーディングについて深掘りしたいと思います。
文字を表現するエンコーディングには古くからいろんなものがあります。 日本語だとShift_JISや、それを拡張したCP932が日本では一般的に多く使われていました。
例えば、ExcelでCSVを出すとき、現在はUTF-8での書き出しと、読み込みができるようになっていますが、かつては基本的にCP932が長く使われており、UTF-8ではできなかった時代がありました。そういった事情もあって、日本においてはCP932が比較的多くの場所で使われています。
ところで、先ほどから出ているCP932やShift_JISは文字エンコーディングの種類で、他にはUNIXで使われていたEUC-JPやASCIIなどがあります。
エンコーディングについては何年もの間、いろんな議論がある中、UTF-8は世の中でほとんどの文字列を表現することができており、大体がUTF-8でされるようになってきています。これはPythonにおいてのみでなく、他の物事においてもUTF-8が標準化されてきたというのが現状としてあります。
テキストを表現する時に、どういう表現の仕方をするかでエンコーディングが決まっています。UTF-8はこの10年ほどの間に標準的に使われるようになっています。例えば、かつてiモードなどがあった時代には、Shift_JISがWebサイトなどでも使われていましたが、そういったものがだんだんなくなってきたことで、現在はWebの表現はUTF-8が中心です。
ただ、現状のPythonにおいては、Windowsでopen関数を利用する場合にCP932が使われてしまうことがありますので、宣言が必要です。が、最近の発表で、2年後に出るPython3.15では、エンコーディングでUTF-8を指定しなくとも、Windowsにおいても全てがUTF-8になると宣言されていますので、Python3.15からは宣言は不要になります。それまでは、WindowsでCP932が使われてしまい、動かない場合があることに変わりありませんので、UTF-8をエンコーディングに指定するのを忘れないようにしましょう。
ちなみにPythonの内部は、今はUnicode(ユニコード)にデコードされたオブジェクトとして内部では扱われており、先ほどのopen関数でエンコーディングをUTF-8とすると、ファイルというデータを UTF-8でUnicode化して内部で扱ってくださいねという仕組みになっています。そのため、ファイルの読み書きにおいてはUnicodeにするときのエンコーディングはちょっと注意する必要があります。
■pandasによる文字列処理
では次に、pandasを利用したテキストデータの処理について説明されており、ここではテキストデータを扱うデータ型というのが紹介されています。
- object型よりstring型
pandasにおいては、文字列が入っているものはobject型になるというのが標準です。pandasは列(厳密にはSeries)ごとに、データ型を1つにする必要がありますので、列の中に文字列が1個でも入っていれば、その文字列はobject型になります。ちなみに、pandas上で文字列しかないセルを扱う場合、object型のままでも処理できることはことたくさんありますが、文字列を扱うのであれば、string型にする方がよくなります。公式ドキュメントでも、文字列しかない場合には、object型よりも、string型を使うことをおすすめされています。
- .strアクセサでループが不要
次に、書籍では.strアクセサについて解説されています。
.strアクセサはstring型の属性にアクセスできるということが書かれています。まず、アクセサとは、seriesの列や単体に対して処理を入れることが可能なものですが、元々持っている処理がPythonのデータ型だった場合、このまとめた縦に並んでいる複数のデータに対して、まとめて何らかの処理を入れるというようなことができます。
Pythonには文字列型が持つupperメソッドという、大文字のデータデータを返してくれるためのメソッドがあります。(例:小文字のabcに対して、[.upper()]とすると大文字のABCの値を返す)
一方、pandasの場合、複数の行に渡ってデータが入っている状態です。例えば、1行目にはabc、2行目にはdefというようないろいろなデータが、いろんな行に入っています。そうすると、直接.upperするには、for文による繰り返し処理をして、1行ずつ取りだして.upper()の処理をしなければ全部のデータの変換ができません。そこで.strアクセサを使うと、[.str.upper()]と書けばループを書かずに全部の行に対して.upperが適用されたseriesが戻ってくる仕組みになっており、一括で.upperの処理を済ませることができます。
これで文字列への処理も.strアクセサで何かしらやることができそうだなというのがわかるかなと思います。
書籍では続けて、正規表現をregex=Trueで置き換える方法などの、正規表現を使ってできることが紹介されています。
こうした.strアクセサによる手法は、pandasにおいて、文字列をいろんな処理をするときに非常に便利な手法になりますので、ぜひ覚えておいてほしいなという風に思っています。
これらを使いこなせるようになると、先ほど、Pythonの世界でうまく正規表現を使いこなせるといろんな処理ができますよという話をしましたが、pandasの世界でもそうしたことが一括でできるようになります。
文字列を普段取り扱うことが無い人にとってはわかりにくい部分はあると思いますが、学習を続けてもらえればと思います。