【Python初心者でも分かる】データサイエンティスト協会の100本ノック|住所データの処理

スポンサーリンク
Python
ゼロ知識の初心者がデータサイエンスを完全無料で学習する方法5選
データサイエンスの知識や技術、またはPythonについて学びたい。でも「大学に行くほど本気度がない」、「スクールに行くほどお金がない」、なんせ「時間がない」という方も多いはずです。というよりほとんどの方がそうだと思います(当然わたし...
ウソ情報にだまされない、研究と因果関係から読み解く情報の取捨選択
ビジネス書やビジネスYouTuberなどは、ビジネスに役立つ情報を発信しています。これらは、ビジネスパーソンにとって、自分を成長させるための有用なツールになっている。 たとえば、優秀な社員が行っている行動や考え方、ダメな社員が行ってい...

データサイエンティスト協会の100本ノックがGitHubに公開しているデータとPythonコードを初心者にでも分かるように解説していきます。

今回は85~88本です。内容は主に、データから新たなデータを作成する「住所データを処理する方法」について解説していきます。

Pythonの環境設定は以下の記事を参考にして下さい。

【2021年最新】M1 mac でanacondaをインストールする方法

【2021年最新】WindowsでAnacondaをインストールする方法

  1. 住所データを処理する方法
    1. P-085: 顧客データフレーム(df_customer)の全顧客に対し、郵便番号(postal_cd)を用いて経度緯度変換用データフレーム(df_geocode)を紐付け、新たなdf_customer_1を作成せよ。ただし、複数紐づく場合は経度(longitude)、緯度(latitude)それぞれ平均を算出すること。
    2. P-086: 前設問で作成した緯度経度つき顧客データフレーム(df_customer_1)に対し、申込み店舗コード(application_store_cd)をキーに店舗データフレーム(df_store)と結合せよ。そして申込み店舗の緯度(latitude)・経度情報(longitude)と顧客の緯度・経度を用いて距離(km)を求め、顧客ID(customer_id)、顧客住所(address)、店舗住所(address)とともに表示せよ。計算式は簡易式で良いものとするが、その他精度の高い方式を利用したライブラリを利用してもかまわない。結果は10件表示すれば良い。
    3. P-087: 顧客データフレーム(df_customer)では、異なる店舗での申込みなどにより同一顧客が複数登録されている。名前(customer_name)と郵便番号(postal_cd)が同じ顧客は同一顧客とみなし、1顧客1レコードとなるように名寄せした名寄顧客データフレーム(df_customer_u)を作成せよ。ただし、同一顧客に対しては売上金額合計が最も高いものを残すものとし、売上金額合計が同一もしくは売上実績の無い顧客については顧客ID(customer_id)の番号が小さいものを残すこととする。
    4. P-088: 前設問で作成したデータを元に、顧客データフレームに統合名寄IDを付与したデータフレーム(df_customer_n)を作成せよ。ただし、統合名寄IDは以下の仕様で付与するものとする。

住所データを処理する方法

まずは、以下からダウンロードして下さい。

GitHubからデータをダウンロードする方法

P-085: 顧客データフレーム(df_customer)の全顧客に対し、郵便番号(postal_cd)を用いて経度緯度変換用データフレーム(df_geocode)を紐付け、新たなdf_customer_1を作成せよ。ただし、複数紐づく場合は経度(longitude)、緯度(latitude)それぞれ平均を算出すること。

import pandas as pd

df_customer = pd.read_csv("customer.csv")  # データの読み込み
df_geocode = pd.read_csv("geocode.csv")    # データの読み込み

df_customer_1 = pd.merge(df_customer[["customer_id","postal_cd"]],
                         df_geocode[["postal_cd","longitude","latitude"]],
                         how="inner",on="postal_cd")

df_customer_1 = df_customer_1.groupby("customer_id").\
    agg({"longitude":"mean","latitude":"mean"}).reset_index().\
    rename(columns={"longitude":"m_longitude","latitude":"m_latitude"})

df_customer_1 = pd.merge(df_customer,df_customer_1,how="inner",on="customer_id")
df_customer_1.head(3)

出力:

赤くなっているところは、警告メッセージです。

出力結果が正しいため、原因究明に無駄な時間は使わずに、とりあえず無視してOKでしょう。

コードの処理を分割してみていきましょう。

df_customer = pd.read_csv("customer.csv")  # データの読み込み
df_geocode = pd.read_csv("geocode.csv")    # データの読み込み

df_customer_1 = pd.merge(df_customer[["customer_id","postal_cd"]],
                         df_geocode[["postal_cd","longitude","latitude"]],
                         how="inner",on="postal_cd")
df_customer_1.head()

出力:

df_customer と df_geocode を郵便番号(postal_cd)が一致させた状態で結合させています。

次のコードをみてみましょう。

df_customer_1[df_customer_1.duplicated(keep=False,subset='customer_id')].head(5)

出力:

顧客ID(customer_id)が重複したデータをみを抽出しています。

出力結果をみると、顧客ID(customer_id)と郵便番号(postal_cd)が同じでも、緯度(longitude) 経度(latitude)の結果に少しばらつきが確認できます。

次のコードでは経度と緯度のばらつきを解消するために、平均値をとる処理を行っています。

df_customer_1 = df_customer_1.groupby("customer_id").\
    agg({"longitude":"mean","latitude":"mean"}).reset_index().\
    rename(columns={"longitude":"m_longitude","latitude":"m_latitude"})
df_customer_1.head()

出力:

顧客IDごとに、経度と緯度の平均値を算出し、変数名を変更しています。

一つひとつのコードを見ていくとコードの意味が分かりやすくなると思います。

P-086: 前設問で作成した緯度経度つき顧客データフレーム(df_customer_1)に対し、申込み店舗コード(application_store_cd)をキーに店舗データフレーム(df_store)と結合せよ。そして申込み店舗の緯度(latitude)・経度情報(longitude)と顧客の緯度・経度を用いて距離(km)を求め、顧客ID(customer_id)、顧客住所(address)、店舗住所(address)とともに表示せよ。計算式は簡易式で良いものとするが、その他精度の高い方式を利用したライブラリを利用してもかまわない。結果は10件表示すれば良い。

import math

df_store = pd.read_csv("store.csv")  # データの読み込み

def calc_distance(x1,y1,x2,y2):
    distance = 6371*math.acos(math.sin(math.radians(y1))*math.sin(math.radians(y2))
                    +math.cos(math.radians(y1))*math.cos(math.radians(y2))
                        *math.cos(math.radians(x1)-math.radians(x2)))
    return distance

df_86 = pd.merge(df_customer_1, df_store,
                 how="inner",
                 left_on="application_store_cd",
                 right_on="store_cd")

df_86["distance"] = df_86[["m_longitude","m_latitude","longitude","latitude"]].\
                        apply(lambda x: calc_distance(x[0],x[1],x[2],x[3]),axis=1)

df_86[["customer_id","address_x","address_y","distance"]].head(10)

出力:

このコードは経度と緯度から2点の距離を求めています。コードの上の関数の内容は計算式です。この計算式の詳細は割愛します。とりあえず使えればいいのです。

関数の実行は lambda を使って行っています。作成した関数 「calc_distance」は()内に4つの変数を指定することで計算してくれるので、4つの変数を指定しています。

すなわち、”m_longitude”, “m_latitude”, “longitude”, “latitude” ですね。

これで、2点の距離を計算し、「distance」という変数にして、出力しています。

P-087: 顧客データフレーム(df_customer)では、異なる店舗での申込みなどにより同一顧客が複数登録されている。名前(customer_name)と郵便番号(postal_cd)が同じ顧客は同一顧客とみなし、1顧客1レコードとなるように名寄せした名寄顧客データフレーム(df_customer_u)を作成せよ。ただし、同一顧客に対しては売上金額合計が最も高いものを残すものとし、売上金額合計が同一もしくは売上実績の無い顧客については顧客ID(customer_id)の番号が小さいものを残すこととする。

df_receipt = pd.read_csv("receipt.csv")

df_87 = df_receipt.groupby("customer_id").agg({"amount":"sum"}).reset_index()

df_customer_u = pd.merge(df_customer, df_87,
                         how="left",
                         on="customer_id").\
                             sort_values(["amount","customer_id"],
                                         ascending=[False,True])

df_customer_u.drop_duplicates(subset=["customer_name","postal_cd"],
                              keep="first",
                              inplace=True)

print("減少数: ",len(df_customer)-len(df_customer_u))

出力:

このコードで肝心なのは、sort_valuesで、売り上げ(amount)は高い順に、顧客ID(customer_id)は低い順に並び替えることです。

この処理をすることで、drop_duplicates() を用いた重複データの削除するときに、keep=”first” を指定することで、最初のデータを残すようにするだけでよくなります。

問題文に示されている、「同一顧客に対しては売上金額合計が最も高いものを残すものとし、売上金額合計が同一もしくは売上実績の無い顧客については顧客IDの番号が小さいものを残す」との条件を満たすためですね。

P-088: 前設問で作成したデータを元に、顧客データフレームに統合名寄IDを付与したデータフレーム(df_customer_n)を作成せよ。ただし、統合名寄IDは以下の仕様で付与するものとする。

  • 重複していない顧客:顧客ID(customer_id)を設定
  • 重複している顧客:前設問で抽出したレコードの顧客IDを設定
df_customer_n = pd.merge(df_customer,
                         df_customer_u[["customer_name","postal_cd","customer_id"]],
                         how="inner",
                         on=["customer_name","postal_cd"])

df_customer_n.rename(columns={"customer_id_x":"customer_id",
                              "customer_id_y":"integration_id"},
                     inplace=True)

print("ID数の差:",len(df_customer_n["customer_id"].unique())-\
                   len(df_customer_n["integration_id"].unique()))

出力:

データの結合、変数名の変更、IDの数の差を計算しています。

出力結果は、0。つまり、IDの数が同じだということですね。

データサイエンティスト協会の100本ノックを解説|ダウンロードから読み込みまで

データサイエンティスト協会の100本ノックを解説|データの抽出

データサイエンティスト協会の100本ノックを解説|変数の一部を使ってデータを抽出する

データサイエンティスト協会の100本ノックを解説|ソート(順序で整列)

データサイエンティスト協会の100本ノックを解説|グループ分け

データサイエンティスト協会の100本ノック|新たなデータフレームの作成

データサイエンティスト協会の100本ノック|日付データ

データサイエンティスト協会の100本ノック|特徴量エンジニアリング

データサイエンティスト協会の100本ノック|変数を整える

データサイエンティスト協会の100本ノック|小数点の処理

データサイエンティスト協会の100本ノック|時系列データの処理

データサイエンティスト協会の100本ノック|欠損値の処理




コメント

タイトルとURLをコピーしました