RとITとデータサイエンス

ITとデータ分析に関係する記事を中心にしたブログです。

訪日外客数データを縦持ちデータに加工する

2020年現在、新型コロナウィルスの影響で観光業界は出口の見えない状況になってしまっています。特にインバウンドは以前の面影なく、観光で日本を訪れる外国人はゼロになってしまっています。

そんな中でもこの先訪れる観光の再開に向けて、インバウンドに関わる人たちは準備を進めていかなければなりません。今この時に基本に立ち返り、インバウンドのターゲット国に関する分析をしてみるのはいかがでしょうか。

訪日外客数データ

日本政府観光局(JNTO)は、日本を訪れた外国人の数を公表しています。ただ残念なことに、多くの行政のオープンデータの例に漏れず、データ分析には使いにくいExcelで作り込まれた形での公開となっており、データ活用の幅を狭めてしまっています。そこで今回はこの訪日外国人数の統計データをデータ分析に使いやすい形に加工するコードを公開します。コードはPythonで記載します。

訪日外客数データは日本政府観光局(JNTO)のウェブサイト上で公開されています。

www.jnto.go.jp

今回はこの中にある訪日外客数(年表)のうち、「国籍/月別 訪日外客数」のExcelデータを取り扱います。

訪日外客数データのデータ加工コード

訪日外客数データを縦持ちデータに加工するコードは以下になります。

# Pandasのインポート
import pandas as pd

# Excelファイルの読み込み
book_ef = pd.ExcelFile('/since2003_visitor_arrivals.xlsx')

# Excelファイルのシート名を取得
sheet_names = book_ef.sheet_names

# 変換した訪日外客数データを格納するデータフレームの定義
visitor_arrivals_df = pd.DataFrame(columns=['市場', '年', '月', '訪日外客数'])

# 1つずつシートを取り出して、変換処理を実行
for name in sheet_names:

  # 2020の場合
  if name == '2020':

    # ヘッダー3行を飛ばしてシートをデータフレームとして読み込み
    sheet_df = book_ef.parse(name, skiprows=3)
    
    # 列名を変更
    sheet_df = sheet_df.rename(columns={'Unnamed: 0':'市場', '1月':'1', '2月':'2', '3月':'3', '4月':'4', '5月':'5', '6月':'6', '7月':'7', '8月':'8', '9月':'9', '10月':'10', '11月':'11', '12月':'12'})

    # 中東地域の処理として、市場(小項目)を市場列にコピー
    sheet_df.iloc[14, 0] = sheet_df.iat[14, 1]
    sheet_df.iloc[15, 0] = sheet_df.iat[15, 1]
    sheet_df.iloc[16, 0] = sheet_df.iat[16, 1]

    # 中東地域の市場名にある先頭の全角空白を削除
    sheet_df.iloc[14, 0] = sheet_df.iloc[14, 0].replace(' ', '')
    sheet_df.iloc[15, 0] = sheet_df.iloc[15, 0].replace(' ', '')
    sheet_df.iloc[16, 0] = sheet_df.iloc[16, 0].replace(' ', '')

    # 不要な列を削除(市場(小項目):1、伸び率:3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25、累計と伸び率:26-27)
    sheet_df = sheet_df.drop(sheet_df.columns[[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 26, 27]], axis=1)

    # 不要な行を削除(総数:0、アジア計:1、中東地域:13、ヨーロッパ計:20、北アメリカ計:40、南アメリカ計:45、オセアニア計48、フッター:53-54)
    sheet_df = sheet_df.drop(sheet_df.index[[0, 1, 13, 20, 40, 45, 48, 53, 54]])

    # 月をアンピボット
    sheet_df = pd.melt(sheet_df, id_vars=sheet_df.columns.values[:1], var_name='月', value_name='訪日外客数')

    # 年の列を追加
    sheet_df.insert(1, '年', name)

    # 訪日外客数のデータフレーム追加
    visitor_arrivals_df = pd.concat([visitor_arrivals_df, sheet_df])

  # 2016-2019の場合
  elif name=='2019' or name=='2018' or name=='2017' or name=='2016':
    
    # ヘッダー3行を飛ばしてシートをデータフレームとして読み込み
    sheet_df = book_ef.parse(name, skiprows=3)
    
    # 列名を変更
    sheet_df = sheet_df.rename(columns={'Unnamed: 0':'市場', '1月':'1', '2月':'2', '3月':'3', '4月':'4', '5月':'5', '6月':'6', '7月':'7', '8月':'8', '9月':'9', '10月':'10', '11月':'11', '12月':'12'})

    # 不要な列を削除(伸び率:2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24、累計と伸び率:25-26)
    sheet_df = sheet_df.drop(sheet_df.columns[[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 26]], axis=1)

    # 不要な行を削除(総数:0、アジア計:1、ヨーロッパ計:18、北アメリカ計:38、南アメリカ計:43、オセアニア計:46、フッター:51-52)
    sheet_df = sheet_df.drop(sheet_df.index[[0, 1, 18, 20, 38, 43, 46, 51, 52]])

    # 月をアンピボット
    sheet_df = pd.melt(sheet_df, id_vars=sheet_df.columns.values[:1], var_name='月', value_name='訪日外客数')

    # 年の列を追加
    sheet_df.insert(1, '年', name)

    # 訪日外客数のデータフレーム追加
    visitor_arrivals_df = pd.concat([visitor_arrivals_df, sheet_df])

  # 2015以前の場合
  else:
    
    # ヘッダー3行を飛ばしてシートをデータフレームとして読み込み
    sheet_df = book_ef.parse(name, skiprows=3)
    
    # 列名を変更
    sheet_df = sheet_df.rename(columns={'Unnamed: 0':'市場', '1月':'1', '2月':'2', '3月':'3', '4月':'4', '5月':'5', '6月':'6', '7月':'7', '8月':'8', '9月':'9', '10月':'10', '11月':'11', '12月':'12'})

    # 不要な列を削除(伸び率:2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24、累計と伸び率:25-26)
    sheet_df = sheet_df.drop(sheet_df.columns[[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 26]], axis=1)

    # 不要な行を削除(総数:0、アジア計:1、ヨーロッパ計:15、北アメリカ計:34、南アメリカ計:38、オセアニア計:40、フッター:44-45)
    sheet_df = sheet_df.drop(sheet_df.index[[0, 1, 15, 34, 38, 38, 40, 44, 45]])

    # 月をアンピボット
    sheet_df = pd.melt(sheet_df, id_vars=sheet_df.columns.values[:1], var_name='月', value_name='訪日外客数')

    # 年の列を追加
    sheet_df.insert(1, '年', name)

    # 訪日外客数のデータフレーム追加
    visitor_arrivals_df = pd.concat([visitor_arrivals_df, sheet_df])

# CSV形式で出力
visitor_arrivals_df.to_csv('visitor_arrivals_processed.csv', index=False, encoding='shift_jis')

データ加工のポイント

Excelデータを加工する上でのポイントとして一番のネックになるのは、ある年を境に国や地域が追加されている点です。2020年から中東地域が追加されており、2020年のシートのデータ加工コードとそれ以前のシートのデータ加工コードは異なります。また、中東地域は大項目と小項目に分かれており、ここも心が折れるポイントの一つです。2016年にも国や地域の変更があったようで、2015年以前のコードはまた変える必要があります。

また、Excelでは良くやる方法ですが、年ごとにシートが分かれているのもデータ加工がしにくいポイントの一つです。一つずつシートを処理しながらシート名から年の情報を取り出し、データに追加していかなければなりません。

今回のようにExcel形式で公開されてるデータは、多くの場合Excelを使う人のために作られています。今回も、アジアやヨーロッパのような単位での合計や全体の総計が記載されているのですが、データ分析をしたい人にとっては余計なデータです。同様に前年同月と比べた伸び率も記載されているのですが、こちらも余計なデータになります。それぞれ行ごと、列ごと削除する必要があります。 (一般に、データ分析ではデータを加工する前の純粋な値のみをデータとして残しておき、合計や総計、前年同月比等はデータ加工途中で計算したり、BIツール上で表現する際に改めて計算したりします。)

まとめ

今回は観光業界のオープンデータの一つとして、日本政府観光局(JNTO)が公表している訪日外客数データをデータ分析に使いやすい形に加工するコードを紹介しました。日本に人が多く訪れている国や地域はどこなのか、どこの国や地域の訪日数が伸びているのかを分析することができますので、是非ご活用頂けますと幸いです。

(2020.12.31追記)
中東地域の市場(小項目)の値の先頭に全角空白が残ってしまっていたため、全角空白を削除する処理を追加しました。