LoginSignup
2
3

More than 3 years have passed since last update.

データサイエンス100本ノック~初心者未満の戦いpart3

Last updated at Posted at 2020-06-23

これはデータサイエンティストの卵がわけもわからないまま100本ノックを行っていく奮闘録である。
完走できるか謎。途中で消えてもQiitaにあげてないだけと思ってください。

100本ノックの記事
100本ノックのガイド

ネタバレも含みますのでやろうとされている方は注意

記事を書く時点で27本目まで終わっていますが、知らなかった書き方も多く、また「自分はこう書いたけど答えはこうだった」というものも多くあったのでメモ代わりに置いておきます。

コレは見づらい!この書き方は危険!等ありましたら教えていただきたいです。心にダメージを負いながら糧とさせていただきます。

今回は19~22まで。
[前回]10~18
目次付き初回

戦いはここから始まる

19本目

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

今回の要件は

id amo rank
A00 100 1
B00 70 2
C00 80 2
D00 70 4

みたいな形の表を作る、ということらしい
SQLでいうなら

rei.sql
SELECT id,amo amo,
(SELECT count(amo) FROM df b WHERE a.amo < b.amo)+1 rank
FROM df a ORDER BY rank 

といったところか(久々にSQL打った)
一応解説するとamoa.amoが今見ている売上で、その見ている売上よりも高い売上b.amoの数をカウントして(一番大きいと0になるから)+1する。と、いうrankを作りその列を追加するという内容。
注意:とても計算に時間がかかる書き方です。10本ノックのSQLで試しましたが、数分単位でかかりました。

Dataframeでも同じように
df_receipt[['customer_id', 'amount']]
ランク列を作り、(横に)結合すると表ができる

ランク列の作り方は
df_receipt['amount'].rank(method='min', ascending=False)
[参考]

  • ascending=Falseで降順(多いほうが優先)データ。
  • method='min'は少ない数(最小値)が順位データとして返る。

横結合をするには
pd.concat([['列A'],['列B']], axis=1)
pd.concatはaxisがデフォルトだと縦結合(表の下に表がくっつく)が、axis=1をつけると横結合されるらしい

最後に列名を変え、rank昇順に並び替えると

mine19.py
df_tmp = pd.concat([df_receipt[['customer_id', 'amount']] ,df_receipt['amount'].rank(method='min', ascending=False)], axis=1)
df_tmp.columns = ['customer_id', 'amount', 'ranking']
df_tmp.sort_values('ranking', ascending=True).head(10)

こうなる

もちろん分からなくてカンニングである

20本目

mine20.py
df=df_receipt
df=pd.concat([df[['customer_id','amount']] ,df['amount'].rank(method='first',ascending=False) ],axis=1)
df.columns=['customer_id','amount','ranking']
df.sort_values('ranking',ascending=True).head(10)

19本目と内容が一部被るので割愛
変わる部分は

なお、売上金額(amount)が等しい場合でも別順位を付与すること。

の部分。つまり、表示として

id amo rank
A00 100 1
B00 70 2
C00 80 3
D00 70 4

という形をとりたい。

  • method='min'は少ない数(最小値)が順位データとして返る。

ここを変更すればよく、降順データにした後に'min''first'とすることで出現順にナンバリングされる。

21,22本目

mine21.py
len(df_receipt)
mine22.py
len(df_receipt['customer_id'].unique())

解説いる?
22本目をSQLに直すと
SELECT COUNT(DISTINCT customer_id) FROM receipt
でいけます。どっちが楽?

今回はここまで

実際ランクをつけるのをSQLとPythonで比較してPythonのほうが早いと感じたので、ようやくpandasを使うことに意義を見出し始めました。LIKEとかSQLのが楽やろ
問題を解いているだけだとあまり頭に入ってこないので、また問題を解いてから整理をするをしていきたいと思います。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3