

pythonを用いて全国住所データＣＳＶ；KEN_ALL.CSVから市の数を都道府県ごとにカウントしたいと考えています。

[![全国住所データＣＳＶ](https://i.stack.imgur.com/GtFxg.png)](https://i.stack.imgur.com/GtFxg.png)  
全国住所データＣＳＶの中身

[code]

    import csv
    result = {}
    filename = 'KEN_ALL.CSV'
    prefs, cities = [], []
    with open(filename, encoding='Shift JIS', newline='') as f:
        csvreader = csv.reader(f)
        for row in csvreader:
            prefs.append(row[6])  # 7列目: 都道府県名
            cities.append(row[7]) # 8列目: 市区町村名
    
    　# 重複を削除
    prefs = [*{*prefs}]
    cities = [*{*cities}]
    
    cities = list(filter(lambda x: x.endswith('市'), cities))
    
    length = len(cities)
    print(f'cities の要素数: {length}')
    
    #　⇓今回の質問に関わる部分
    for pref in prefs:
        result[pref] = 0
    
    for city in cities:
        for pref in prefs:
            if city.startswith(pref):
                result[pref] += 1
                break
    
    print(result)
    print(prefs)    # 47件
    print(cities) # 1894件
    
[/code]

これを実行すると

[code]

    {'徳島県': 0, '石川県': 0, '鳥取県': 0, '群馬県': 0, '宮崎県': 0, '熊本県': 0, '高知県': 0, '大阪府': 0, '富山県': 0, '北海道': 0, '福井県
    
[/code]

件数が多いので、一部のみですが、市のカウントが０になってしまいます。citiesに入っている市の数をカウントして都道府県ごとに記述するにはどのようにすればよいのでしょうか。


CC BY-SA 4.0
2022-12-28T13:12:48.563
93078
2022-12-30T06:15:26.893
2022-12-29T08:38:24.770
3060
56088
question
python
csvファイルから都道府県ごとに市の数をカウントしたい


`KEN_ALL.CSV`から都道府県名と市の数だけ欲しいのであれば以下のように出来ます。  
それから市かどうかを`.endswith('市')`で判定していると、政令指定都市は含まれません。  
市の名前を後で使いたいとか、政令指定都市を含めたいとかなら、追加の処理が必要です。

[code]

    import csv
    result = {}
    filename = 'KEN_ALL.CSV'
    with open(filename, encoding='Shift JIS', newline='') as f:
        csvreader = csv.reader(f)
        pref = ''
        city = ''
        cities = 0
        for row in csvreader:
            p = row[6]
            if pref and (pref != p):
                result[pref] = cities
                cities = 0
            pref = p
            c = row[7]
            #### 政令指定都市を含めるなら以下を有効化
            # if c.endswith('区') and ('市' in c):
            #     c = c[:(c.rfind('市') + 1)]
            if c.endswith('市') and (c != city):
                cities += 1
                city = c
        
        if cities != 0:
            result[pref] = cities
    
    print(result)
    
[/code]


CC BY-SA 4.0
2022-12-28T23:35:31.420
93080
2022-12-29T00:47:25.703
2022-12-29T00:47:25.703
26370
26370
93078
answer


### groupby 使う方法

この手の処理は (課題云々は別にして) (個人的には) pandas使うと楽にできそうに思います  
CSVは [郵便番号データ](https://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html)
の「全国一括 (1,691,520Byte)」らしいので zipから算出してみます

**update:** コメントの指摘受け簡略化  
(サイトには `ShiftJIS`と記されてるので念の為それで)

[code]

    import pandas as pd
    
    fname = '/path/to/ken_all.zip'
    df = pd.read_csv(fname, encoding='ShiftJIS', header=None, usecols=[6, 7])
    df = df.drop_duplicates().rename(columns={6: '都道府県', 7: '市区町村'})
    df[df['市区町村'].str.endswith('市')].groupby('都道府県', sort=False).count()
    
[/code]

#### Pythonで行なう

pandas使わず Pythonで行なうなら, 同等の機能を見つけ置き換える必要があり

  * `drop_duplicates` ⇛ set or dict
  * `df.groupby` ⇛ itertools.groupby

[code]

    import csv
    from itertools import groupby
    
    with open(csvfile, encoding='ShiftJIS', newline='') as fp:
        reader = csv.reader(fp)
        dct = {k: sum(c.endswith('市')for _,c in g)
                for k,g in groupby(dict.fromkeys((row[6], row[7])for row in reader),
                                   key=lambda x: x[0])}
    
[/code]

#### 検証

確認の為, [都道府県別市区町村数一覧](https://www.j-lis.go.jp/spd/code-address/kenbetsu-
inspection/cms_11914151.html) との比較

[code]

    df, = pd.read_html('https://www.j-lis.go.jp/spd/code-address/kenbetsu-inspection/cms_11914151.html', index_col=0)
    df.rename(columns={df.columns[0]: '都道府県'}, inplace=True)
    display(df.tail())
    
    df.市.to_list()[:-1] == list(dct.values())   # True
    df.set_index('都道府県').drop('計').市.to_dict() == dct   # True
    
[/code]

| 都道府県 | 指定都市 | 市 | 特別区 | 町 | 村 | 計  
---|---|---|---|---|---|---|---  
44 | 大分県 | - | 14 | - | 3 | 1 | 18  
45 | 宮崎県 | - | 9 | - | 14 | 3 | 26  
46 | 鹿児島県 | - | 19 | - | 20 | 4 | 43  
47 | 沖縄県 | - | 11 | - | 11 | 19 | 41  
計 | 計 | 20 | 772 | 23 | 743 | 183 | 1741


CC BY-SA 4.0
2022-12-30T04:48:05.797
93103
2022-12-30T06:15:26.893
2022-12-30T06:15:26.893
43025
43025
93078
answer


参考までに、Pandas を使うのであれば以下の様に記述しても可。

[code]

    import pandas as pd
    
    num_cities = pd.read_csv('ken_all.zip', encoding='cp932', header=None,
                             usecols=[6, 7], names=['都道府県名', '市区町村名'])\
                   .drop_duplicates().query('市区町村名.str.endswith("市")')\
                   .value_counts('都道府県名').to_dict()
    
    ref = pd.read_html('https://www.j-lis.go.jp/spd/code-address/kenbetsu-inspection/cms_11914151.html',
                       index_col=1)[0].drop('計')['市'].to_dict()
    
    print(num_cities == ref)
    
[/code]


CC BY-SA 4.0
2022-12-30T06:13:10.973
93107
2022-12-30T06:13:10.973
47127
93078
answer