pandasで、カラム(列)から重複行や特定の文字列を含む行を抽出する

以前に整形した郵便番号データが綺麗に整形出来ているか、チェックするためにpandasを使います。しかし、pandasの使い方がよくわからなかったので、調べながら進めていくことにしました。読み込んだCSVファイルにヘッダーがないので、カラム(列)番号で抽出していきます。

カラムの番号で抽出

import pandas as pd

df = pd.read_csv('20201130_zipcode_all_utf8.csv', header=None)

一つのカラム番号で抽出

df.iloc[:,0]
0          600000
1          640941
2          600041
3          600042
4          640820
           ...
124196    9071433
124197    9071751
124198    9071544
124199    9071800
124200    9071801
Name: 0, Length: 124201, dtype: int64

複数のカラム番号で抽出

df.iloc[:,[0,6]]
              0             6
0        600000           NaN
1        640941           旭ケ丘
2        600041           大通東
3        600042   大通西(1〜19丁目)
4        640820  大通西(20〜28丁目)
...         ...           ...
124196  9071433          南風見仲
124197  9071751           波照間
124198  9071544            鳩間
124199  9071800           NaN
124200  9071801           与那国

[124201 rows x 2 columns]

範囲を指定して抽出

df.iloc[:,2:6]
                      2                    3    4         5
0          サッポロシチュウオウク                  NaN  北海道    札幌市中央区
1          サッポロシチュウオウク              アサヒガオカ  北海道    札幌市中央区
2          サッポロシチュウオウク           オオドオリヒガシ  北海道    札幌市中央区
3          サッポロシチュウオウク   オオドオリニシ(1-19チョウメ)  北海道    札幌市中央区
4          サッポロシチュウオウク  オオドオリニシ(20-28チョウメ)  北海道    札幌市中央区
...                 ...                  ...  ...       ...
124196   ヤエヤマグンタケトミチョウ                ハイミナカ  沖縄県   八重山郡竹富町
124197   ヤエヤマグンタケトミチョウ                 ハテルマ  沖縄県   八重山郡竹富町
124198   ヤエヤマグンタケトミチョウ                  ハトマ  沖縄県   八重山郡竹富町
124199  ヤエヤマグンヨナグニチョウ                  NaN  沖縄県  八重山郡与那国町
124200  ヤエヤマグンヨナグニチョウ                ヨナグニ  沖縄県  八重山郡与那国町

[124201 rows x 4 columns]

重複した行を抽出

duplicated() と引数keep

duplicated()

引数keepを指定しないと、keep=’first’になり、重複した最初の行が、Falseになる。

duplicated(keep='first')

重複した最初の行が、Falseになる。

duplicated(keep='last')

重複した最後の行が、Falseになる。

duplicated(keep=False)

重複したすべての行が、Trueになる。

重複判定するカラムを指定:引数subset

headerをつけていれば、判定するカラムをカラム名で指定することができます。

df.duplicated(subset='カラム名')
df.duplicated(subset=['カラム名1', 'カラム名2'])

重複した行数をカウント:value_counts()

df.duplicated().value_counts()

duplicated()で得たTrueをカウントし、重複した行の数が確認できます。

引数keepによって、結果が変わります。

カラム番号を指定して重複行数をカウント

引数なし(keep=’first’)
df.iloc[:,0].duplicated().value_counts()
False    120360
True       3841
Name: 0, dtype: int64
引数 keep=False
df.iloc[:,0].duplicated(keep=False).value_counts()
False    119031
True       5170
Name: 0, dtype: int64

特定の文字列を含む行を抽出

完全一致:==

要素が文字列に完全一致すると、Trueになります。

特定の文字列を含む:str.contains()

要素が特定の文字列を含むと、Trueになります。

NaNの処理

要素がNaNである場合、デフォルトではTrueでもFalseでもなくNaNを返します。NaNだとstr.contains()を使って行を抽出するとエラーになります。

そこで、str.contains()の引数naでNaNの結果を置き換える値を指定します。

条件として使う場合、na=TrueとすればNaNの行も選択され、na=FalseとすればNaNの行は選択されません。

df.iloc[:,6].str.contains('、', na=True)
df.iloc[:,6].str.contains('、', na=False)

大文字小文字の処理:引数case

デフォルトでは大文字と小文字は区別して処理されます。引数caseをFalseとすると大文字小文字が区別されません。

条件を指定

&、|、~を使って条件を指定していきます。(and、or、notだとエラーになります)

ソースコード(python)

郵便番号データを整形するときに、「、()」の有無を条件として分岐しているので、整形に失敗していると、()が上手く閉じられていないはずです。そこで、片方の()が残っているデータと「、」が入っていて()がどちらもないデータを抽出していきます。

import pandas as pd

df = pd.read_csv('20201130_zipcode_all_utf8.csv', header=None)

par_start = df.iloc[:,6].str.contains('(', na=False)
par_end = df.iloc[:,6].str.contains(')', na=False)
comma = df.iloc[:,6].str.contains('、', na=False)

print(df[par_start & ~par_end])
print(df[~par_start & par_end])
print(df[comma & ~par_start & ~par_end])

結果

Empty DataFrame
Columns: [0, 1, 2, 3, 4, 5, 6]
Index: []
Empty DataFrame
Columns: [0, 1, 2, 3, 4, 5, 6]
Index: []
             0      1              2                            3    4        5                6
12566   295503  イワテケン  ワガグンニシワガマチ          アナアケ22チワリ、アナアケ23チワリ  岩手県  和賀郡西和賀町    穴明22地割、穴明23地割
12572   295523  イワテケン  ワガグンニシワガマチ  カツラゴザワ75チワリ、カツラゴザワ76チワリ  岩手県  和賀郡西和賀町  桂子沢75地割、桂子沢76地割
12573   295502  イワテケン  ワガグンニシワガマチ        カバサワ16チワリ、カバサワ17チワリ  岩手県  和賀郡西和賀町    樺沢16地割、樺沢17地割
12574   295512  イワテケン  ワガグンニシワガマチ          カワシリ40チワリ、カワシリ41チワリ  岩手県  和賀郡西和賀町    川尻40地割、川尻41地割
12591   295523  イワテケン  ワガグンニシワガマチ          サワナカ73チワリ、サワナカ74チワリ  岩手県  和賀郡西和賀町    沢中73地割、沢中74地割
12601   295522  イワテケン  ワガグンニシワガマチ          ナカムラ58チワリ、ナカムラ59チワリ  岩手県  和賀郡西和賀町    中村58地割、中村59地割
12603   295523  イワテケン  ワガグンニシワガマチ          ホソナイ68チワリ、ホソナイ69チワリ  岩手県  和賀郡西和賀町    細内68地割、細内69地割
12608   295523  イワテケン  ワガグンニシワガマチ    ヤナギザワ70チワリ、ヤナギザワ71チワリ  岩手県  和賀郡西和賀町    柳沢70地割、柳沢71地割
12609   295514  イワテケン  ワガグンニシワガマチ          ユガワ52チワリ、ユガワ53チワリ  岩手県  和賀郡西和賀町    湯川52地割、湯川53地割
12612   295505  イワテケン  ワガグンニシワガマチ            ユモト29チワリ、ユモト30チワリ  岩手県  和賀郡西和賀町    湯本29地割、湯本30地割
67796  4400833  アイチケン          トヨハシシ              イムレチョウニシヤマ、タカヤマ  愛知県      豊橋市         飯村町西山、高山
67804  4400032  アイチケン          トヨハシシ            イワタチョウイムラ、キタゴウナカ  愛知県      豊橋市        岩田町居村、北郷中
67805  4400041  アイチケン          トヨハシシ              イワタチョウミヤシタ、ミチアイ  愛知県      豊橋市         岩田町宮下、道合
72044  4411324  アイチケン          シンシロシ              イミチ、オクイミチ、ウチイミチ  愛知県      新城市       井道、奥井道、内井道

()が片方だけ残っているデータは0でした。

()が無く「、」が入っているデータは14件ありましたが、件数が少ないので元の郵便番号データ(KEN_ALL.CSV)をEXCELのフィルターにかけて確認してみます。

元から()が無く「、」だけで区切られているデータのようです。

他にも、isinを使って差分チェックもしましたが、一目でわかるようなミスはなかったので、あとは使いながら検証していくことにします。