CHAPTER 6 ・ pandas を一歩進める / Lesson 22
欠損値・型・表記ゆれを整える
空欄、文字になった数字、全角半角や社名の揺れ。分析の前に必ずやる「下ごしらえ」です。
このレッスンが終わったら
「分析の前に、欠損・型・表記ゆれを整える。errors='coerce' で変換できないものを見つけられる」と言える。
こんな場面、ありませんか?
別のシステムから出力したCSVを、そのまま集計しようとして、エラーで止まってしまった。経理や総務の仕事では、よくある場面です。ここに、10月の売上を10行だけ記録した messy.csv(「散らかったCSV」という意味の名前です)があります。
日付,得意先名,商品,数量,金額 2025/10/01,アオイ電機(株),ノートPC,1,"120,000" 2025/10/02,株式会社 ミドリ商事,モニター,2,"70,000" 2025-10-03,ミドリ商事株式会社,モニター,2,"70,000" 2025/10/04,サクラ印刷,業務ソフト,1,48000 2025/10/05, サクラ印刷 ,業務ソフト,,48000 2025/10/06,タチバナ工業,保守サービス,1, 2025/10/07,アオイ電機(株),ノートPC,1,"120,000" 2025/10/08,ヒマワリ食品,ミネラルウォーター,10,"15,000" 2025/10/08,ヒマワリ食品,ミネラルウォーター,10,"15,000" 2025/10/09,スミレ運輸,モニター,1,不明
普通の売上表に見えますが、よく見ると、金額に「120,000」のカンマ、「不明」の文字、空欄、全角の「2」、同じ会社の書き方のばらつきが混ざっています。まず pandas で読み込んで、各列の型を見てみましょう。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
「金額」も「数量」も、object(文字の列)になっています。基礎編の orders.csv では、金額は最初から数字として読めましたが、今回は文字が混ざっているので、列全体が文字として扱われました。この状態で合計を出すと、どうなるでしょうか。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
TypeError(型が合わない)と出ました。文字と数字を足そうとして、止まっています。分析の前に、データを整える下ごしらえが必要です。この回では、その手順を順番に学びます。
欠損を数えて、金額を数字にする
最初にやるのは、どこに何が欠けているかを数えることです。空欄は、pandas では 欠損値(NaN)として読み込まれます。isna() は「欠けているか」を調べ、sum() で数えます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
数量と金額に1つずつ、欠損があります。info() は、列ごとの「欠けていない数」と型をまとめて表示します。Non-Null Count が 10 より小さい列が、欠けのある列です。
次に、金額を数字にします。カンマを取ってから、数字に変換します。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
金額が数字になり、合計も出せました。空欄と「不明」は nan になっています。nan が混ざる列は、float64(小数を含む数字)の型になります。合計では、nan は無視されます。
仕組みを読む
金額を数字にした1行は、3つの部品でできています。
pd.to_numeric(文字を数字に変えるdf["金額"]対象の列.str.replace(",", "")文字の列に使う:カンマを空に置き換えるerrors="coerce"変換できないものは NaN にする)閉じるdf["金額"].str金額の列を、1つずつ「文字」として扱う入り口(文字の道具を使えるようにする).replace(",", "")カンマを、何もない文字に置き換える。「120,000」は「120000」になるpd.to_numeric(...)文字になっている数字を、数字に変換するerrors="coerce"変換できなかったもの(「不明」など)は、エラーにせず、欠損値(NaN)にするdf["金額"] = ...できた数字の列で、金額の列を置き換える日本語にすると
errors="coerce"(コーズ:無理にでも変換する、の意味)の効果は、止まらずに、どれが変換できなかったかを残せることです。付けなかった場合は、最初に見つけた変換できない文字で止まります。
変えて、試す
① 変換できなかった行を、捨てる前に確かめる。 「不明」と書かれていた行は、変換後に NaN になるので、もともとの空欄と区別がつきません。変換の前の値と見比べて、「何かが書いてあったのに、変換できなかった行」だけを抜き出します。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
amount.isna()(変換後に欠けている)と df["金額"].notna()(変換前は欠けていない)を &(かつ)でつなぎました。該当するのは、スミレ運輸の「不明」の1行です。空欄のタチバナ工業の行は、もともと空欄なので、ここには入りません。元の伝票を調べて、金額を確かめる行はどちらなのか、一覧で分かります。
② 全角の数字は、先に半角にそろえる。 数量に、全角の「2」があります。そのまま変換するとどうなるでしょうか。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
全角の「2」が nan になってしまいました。エラーも出ないので、気づきにくい落とし穴です。Lesson 02 で学んだ NFKC(全角を半角にそろえる変換)を、列全体にかけてから変換します。pandas では .str.normalize("NFKC") と書きます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
「2」が 2.0 になりました。残る nan は、もともと空欄だった1行です。
③ 会社名の表記ゆれをそろえる。 「アオイ電機(株)」「株式会社 ミドリ商事」「ミドリ商事株式会社」のように、同じ会社が別の書き方になっていると、会社ごとの集計がばらばらになります。「株式会社」と「(株)」を取り除き、前後の空白(全角空白も)を取り除きます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
nunique() は、種類の数です。整える前は8種類、整えたあとは6社になりました。strip() は、全角の空白も取り除きます。
④ 重複を見つけて、除く。 ヒマワリ食品の10月8日の行が、2回入っています。duplicated() は、「上の行と全く同じ内容の行」に True を付けます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
keep=False は「重複している行を、全部表示する」指定です。drop_duplicates() で、1行目を残して2行目以降が除かれ、10行が9行になりました。
自分で書く
お題① messy.csv の金額を数字にして、合計を整数で表示してください。(nan の行は、合計に入りません)
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
pd.to_numeric(df["金額"].str.replace(",", ""), errors="coerce") で数字にし、.sum() で合計を出します。そのままでは 506000.0 と表示されるので、int(...) で囲みます。
答えの例を見る
import pandas as pd
df = pd.read_csv("messy.csv")
amount = pd.to_numeric(df["金額"].str.replace(",", ""), errors="coerce")
print(int(amount.sum()))お題② 金額が数字にできなかった(NaN になった)行の「得意先名」を、リストで表示してください。(空欄の行も、「不明」の行も含めます)
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
df[df["金額"].isna()] で、欠けている行を取り出します。その得意先名の列を .tolist() でリストにして、print します。
答えの例を見る
import pandas as pd
df = pd.read_csv("messy.csv")
df["金額"] = pd.to_numeric(df["金額"].str.replace(",", ""), errors="coerce")
print(df[df["金額"].isna()]["得意先名"].tolist())お題③ 重複した行を除いた表の、行数を表示してください。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
df.drop_duplicates() で重複を除いた表ができます。その行数を len(...) で数えます。
答えの例を見る
import pandas as pd
df = pd.read_csv("messy.csv")
print(len(df.drop_duplicates()))仕事ならどう使う?
理解チェックpd.to_numeric(列, errors="coerce") を実行したとき、「不明」という文字はどうなりますか?
理解チェック金額が欠けている行を、fillna(0) で 0円 にしてから集計しました。どんな問題が起きるでしょうか?