【解説】手を動かしながらソートと表連結を学ぶ | データサイエンス100本ノック【問17〜問20 回答】

【解説】手を動かしながらソートと表連結を学ぶ | データサイエンス100本ノック【問17〜問20 回答】





目次

この記事の対象者


・ ソートと表連結を手を動かしながら学びたい人

・ データサイエンティストを目指している人

本記事で学ぶpythonのメソッド



本記事では以下3つのメソッドを学びます

  • ソート
  • 順位・ランク付け
  • 表連結

以降それぞれの内容についてまとめていきます。

ソート

ソートとは、データを降順または昇順に並び替えることです。

pythonを用いてソートする場合は、sort_values()というメソッドを使用します。

使い方は以下のとおりです。

sort_values()の使い方
1
df.sort_values('カラム名', ascending=True)

ascending=Trueにすると昇順、ascending=Falseにすると降順に並び替えられます。

順位・ランク付け

ソートした値に順位をつけたい場合は、rank()メソッドを使用します。

使い方の例は以下のとおりです。

rank()メソッドの使い方
1
df.rank(method='min', ascending=False)

method='min'は、重複値を持つ場合の順位が、最小値の順位となります。

method='first'とすることで、値が重複してても出てきた順番にランク付けされます。

表の連結

表の連結は以下のとおりです。

  • 縦方向に連結

pandas.concat([DataFrameのリスト], axis=0)

  • 横方向に連結

pandas.concat([DataFrameのリスト], axis=1)

実際に手を動かしながら学んでみよう

早速問題を解いてみよう!

ソート、順位・ランク付け、表の連結を実際に使ってみましょう。

以降は、一般社団法人データサイエンティスト協会がGitHubに公開している「データサイエンス100本ノック」の17問目〜20問目を題材にします。

データサイエンス100本ノックの環境構築方法は以下の記事にまとめていますので、こちらを参照してください。

第17問目: ソート(昇順)

P-17: 顧客データフレーム(df_customer)を生年月日(birth_day)で高齢順にソートし、先頭10件を全項目表示せよ。

この問題を解くためにはソートを用います。

第17問目回答
1
df_customer.sort_values('birth_day', ascending=True).head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
12

customer_id customer_name gender_cd gender birth_day age postal_cd address application_store_cd application_date status_cd
18817 CS003813000014 村山 菜々美 1 女性 1928-11-26 90 182-0007 東京都調布市菊野台********** S13003 20160214 0-00000000-0
12328 CS026813000004 吉村 朝陽 1 女性 1928-12-14 90 251-0043 神奈川県藤沢市辻堂元町********** S14026 20150723 0-00000000-0
15682 CS018811000003 熊沢 美里 1 女性 1929-01-07 90 204-0004 東京都清瀬市野塩********** S13018 20150403 0-00000000-0
15302 CS027803000004 内村 拓郎 0 男性 1929-01-12 90 251-0031 神奈川県藤沢市鵠沼藤が谷********** S14027 20151227 0-00000000-0
1681 CS013801000003 天野 拓郎 0 男性 1929-01-15 90 274-0824 千葉県船橋市前原東********** S12013 20160120 0-00000000-0
7511 CS001814000022 鶴田 里穂 1 女性 1929-01-28 90 144-0045 東京都大田区南六郷********** S13001 20161012 A-20090415-7
2378 CS016815000002 山元 美紀 1 女性 1929-02-22 90 184-0005 東京都小金井市桜町********** S13016 20150629 C-20090923-C
4680 CS009815000003 中田 里穂 1 女性 1929-04-08 89 154-0014 東京都世田谷区新町********** S13009 20150421 D-20091021-E
16070 CS005813000015 金谷 恵梨香 1 女性 1929-04-09 89 165-0032 東京都中野区鷺宮********** S13005 20150506 0-00000000-0
6305 CS012813000013 宇野 南朋 1 女性 1929-04-09 89 231-0806 神奈川県横浜市中区本牧町********** S14012 20150712 0-00000000-0

第18問目: ソート(降順)

P-18: 顧客データフレーム(df_customer)を生年月日(birth_day)で若い順にソートし、先頭10件を全項目表示せよ。

第18問目回答
1
df_customer.sort_values('birth_day', ascending=False).head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
12

customer_id customer_name gender_cd gender birth_day age postal_cd address application_store_cd application_date status_cd
15639 CS035114000004 大村 美里 1 女性 2007-11-25 11 156-0053 東京都世田谷区桜********** S13035 20150619 6-20091205-6
7468 CS022103000002 福山 はじめ 9 不明 2007-10-02 11 249-0006 神奈川県逗子市逗子********** S14022 20160909 0-00000000-0
10745 CS002113000009 柴田 真悠子 1 女性 2007-09-17 11 184-0014 東京都小金井市貫井南町********** S13002 20160304 0-00000000-0
19811 CS004115000014 松井 京子 1 女性 2007-08-09 11 165-0031 東京都中野区上鷺宮********** S13004 20161120 1-20081231-1
7039 CS002114000010 山内 遥 1 女性 2007-06-03 11 184-0015 東京都小金井市貫井北町********** S13002 20160920 6-20100510-1
3670 CS025115000002 小柳 夏希 1 女性 2007-04-18 11 245-0018 神奈川県横浜市泉区上飯田町********** S14025 20160116 D-20100913-D
12493 CS002113000025 広末 まなみ 1 女性 2007-03-30 12 184-0015 東京都小金井市貫井北町********** S13002 20171030 0-00000000-0
15977 CS033112000003 長野 美紀 1 女性 2007-03-22 12 245-0051 神奈川県横浜市戸塚区名瀬町********** S14033 20150606 0-00000000-0
5716 CS007115000006 福岡 瞬 1 女性 2007-03-10 12 285-0845 千葉県佐倉市西志津********** S12007 20151118 F-20101016-F
15097 CS014113000008 矢口 莉緒 1 女性 2007-03-05 12 260-0041 千葉県千葉市中央区東千葉********** S12014 20150622 3-20091108-6

第19問目: 順位・ランク付け、表連結

P-19: レシート明細データフレーム(df_receipt)に対し、1件あたりの売上金額(amount)が高い順にランクを付与し、先頭10件を抽出せよ。項目は顧客ID(customer_id)、売上金額(amount)、付与したランクを表示させること。なお、売上金額(amount)が等しい場合は同一順位を付与するものとする。

少し難しく感じるかと思いますが、順を追って欲しいデータを取得しましょう。

まずは、df_receiptというデータフレーム全体を確認しましょう。

1
df_receipt
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	sales_ymd	sales_epoch	store_cd	receipt_no	receipt_sub_no	customer_id	product_cd	quantity	amount
0 20181103 1541203200 S14006 112 1 CS006214000001 P070305012 1 158
1 20181118 1542499200 S13008 1132 2 CS008415000097 P070701017 1 81
2 20170712 1499817600 S14028 1102 1 CS028414000014 P060101005 1 170
3 20190205 1549324800 S14042 1132 1 ZZ000000000000 P050301001 1 25
4 20180821 1534809600 S14025 1102 2 CS025415000050 P060102007 1 90
... ... ... ... ... ... ... ... ... ...
104676 20180221 1519171200 S13043 1132 2 ZZ000000000000 P050101001 1 40
104677 20190911 1568160000 S14047 1132 2 ZZ000000000000 P071006005 1 218
104678 20170311 1489190400 S14040 1122 1 CS040513000195 P050405003 1 168
104679 20170331 1490918400 S13002 1142 1 CS002513000049 P060303001 1 148
104680 20190423 1555977600 S13016 1102 2 ZZ000000000000 P050601001 1 138
104681 rows × 9 columns

次に、1件あたりの売上金額(amount)を高い順にランクを付与して取得してみましょう。

1
2
df_tmp = df_receipt['amount'].rank(method='min', ascending=False)
df_tmp

以下のような出力が得られるかと思います。

出力
1
2
3
4
5
6
7
8
9
10
11
12
0          55059.0
1 95294.0
2 51700.0
3 104339.0
4 89871.0
...
104676 103127.0
104677 38644.0
104678 52588.0
104679 57032.0
104680 62707.0
Name: amount, Length: 104681, dtype: float64

上記の出力結果において、右側の数字がランキングになります。

これを顧客ID(customer_id)、売上金額(amount)列を抽出した表に、横方向に連結させます。

横方向に連結させるためにはpandas.concat([DataFrameのリスト], axis=1)とすればよかったですね。

1
2
df_merge = pd.concat([df_receipt[['customer_id','amount']], df_tmp], axis=1)
df_merge
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	customer_id	amount	amount
0 CS006214000001 158 55059.0
1 CS008415000097 81 95294.0
2 CS028414000014 170 51700.0
3 ZZ000000000000 25 104339.0
4 CS025415000050 90 89871.0
... ... ... ...
104676 ZZ000000000000 40 103987.0
104677 ZZ000000000000 218 39599.0
104678 CS040513000195 168 53996.0
104679 CS002513000049 148 61293.0
104680 ZZ000000000000 138 66061.0
104681 rows × 3 columns

上記の出力をみると、amountというカラムが2つ存在していますね。

一番右側のamount列はランキングなので、一番右側の列名をrankingに変更します。

1
2
df_merge.columns = ['customer_id', 'amount', 'ranking']
df_merge
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	customer_id	amount	ranking
0 CS006214000001 158 55059.0
1 CS008415000097 81 95294.0
2 CS028414000014 170 51700.0
3 ZZ000000000000 25 104339.0
4 CS025415000050 90 89871.0
... ... ... ...
104676 ZZ000000000000 40 103127.0
104677 ZZ000000000000 218 38644.0
104678 CS040513000195 168 52588.0
104679 CS002513000049 148 57032.0
104680 ZZ000000000000 138 62707.0
104681 rows × 3 columns

一番右側の列名をrankingに変更することが出来ました。

最後にranking列の値を昇順にし、先頭の10件を表示させましょう。

1
df_merge.sort_values('ranking', ascending=True).head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
	customer_id	amount	ranking
1202 CS011415000006 10925 1.0
62317 ZZ000000000000 6800 2.0
54095 CS028605000002 5780 3.0
4632 CS015515000034 5480 4.0
72747 ZZ000000000000 5480 4.0
10320 ZZ000000000000 5480 4.0
97294 CS021515000089 5440 7.0
28304 ZZ000000000000 5440 7.0
92246 CS009415000038 5280 9.0
68553 CS040415000200 5280 9.0

これで完了です。

第20問目: 順位・ランク付け、表連結

P-020: レシート明細データフレーム(df_receipt)に対し、1件あたりの売上金額(amount)が高い順にランクを付与し、先頭10件を抽出せよ。項目は顧客ID(customer_id)、売上金額(amount)、付与したランクを表示させること。なお、売上金額(amount)が等しい場合でも別順位を付与すること。

20問目は、19問目とほぼ同じ処理を行いますが、違いは重複値を持つ際のランキングの付け方です。

method = 'first'とすることで、重複値は値が同じでも出てきた順番にランク付けされます。

それでは解いていきます。

19問目と同じように、まずは1件あたりの売上金額(amount)を高い順にランクを付与して取得してみましょう。method='first'とすることを忘れずに。

1
2
df_tmp = df_receipt['amount'].rank(method='first', ascending=False)
df_tmp
出力
1
2
3
4
5
6
7
8
9
10
11
12
0          55059.0
1 95294.0
2 51700.0
3 104339.0
4 89871.0
...
104676 103987.0
104677 39599.0
104678 53996.0
104679 61293.0
104680 66061.0
Name: amount, Length: 104681, dtype: float64

同様に横方向に連結させます。

1
2
df_merge = pd.concat([df_receipt[['customer_id','amount']], df_tmp], axis=1)
df_merge
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	customer_id	amount	amount
0 CS006214000001 158 55059.0
1 CS008415000097 81 95294.0
2 CS028414000014 170 51700.0
3 ZZ000000000000 25 104339.0
4 CS025415000050 90 89871.0
... ... ... ...
104676 ZZ000000000000 40 103987.0
104677 ZZ000000000000 218 39599.0
104678 CS040513000195 168 53996.0
104679 CS002513000049 148 61293.0
104680 ZZ000000000000 138 66061.0
104681 rows × 3 columns

19問目と同様に、一番右側の列名はランキングなので、amountという列名をrankingに変更します。

1
2
df_merge.columns = ['customer_id', 'amount', 'ranking']
df_merge
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	customer_id	amount	ranking
0 CS006214000001 158 55059.0
1 CS008415000097 81 95294.0
2 CS028414000014 170 51700.0
3 ZZ000000000000 25 104339.0
4 CS025415000050 90 89871.0
... ... ... ...
104676 ZZ000000000000 40 103987.0
104677 ZZ000000000000 218 39599.0
104678 CS040513000195 168 53996.0
104679 CS002513000049 148 61293.0
104680 ZZ000000000000 138 66061.0
104681 rows × 3 columns

最後にranking列の値を昇順にし、先頭の10件を表示させましょう。

1
df_merge.sort_values('ranking', ascending=True).head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
	customer_id	amount	ranking
1202 CS011415000006 10925 1.0
62317 ZZ000000000000 6800 2.0
54095 CS028605000002 5780 3.0
4632 CS015515000034 5480 4.0
10320 ZZ000000000000 5480 5.0
72747 ZZ000000000000 5480 6.0
28304 ZZ000000000000 5440 7.0
97294 CS021515000089 5440 8.0
596 CS015515000083 5280 9.0
11275 CS017414000114 5280 10.0

これでOKです。

まとめ: Pythonでソート、表連結、順位・ランキング付けができるようになりました。

本記事は、【Python】手を動かしながらソートと表連結を学ぶ | データサイエンス100本ノック【問17〜問20 回答】というテーマでまとめました。

後半の問題は、少し難しかったかもしれませんね。

しかしながら、一つ一つの要素の分解しながら整理していけば、「全然無理」なんてことは無いと思います。

この辺は、様々な処理を実際に手を動かしながらこなしていくことで慣れていけば良いと思います。

>> 続きはこちらから



コメント