質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

3回答

533閲覧

pythonでの加重平均について

jaja

総合スコア11

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2017/11/16 12:48

編集2017/11/16 13:03

###前提・実現したいこと
下記のような配列があり、amountの上位n人目までの加重平均を取りたいです。
10人目までの加重平均を取りたい場合は例の配列で言うと(5003+4007)/10ということをしたいです。
また、scoreとamountはHTTPリクエストから返ってくる数字を整形したものなのでリクエスト毎に値が違います。
下記の配列は一例ですが、どのような値が返ってきてもn番目までを加重平均の取れるようにしたいです。

###返ってくる値の一例

python

1score = [500, 400, 300, 200, 100, 50, 0]#ここは点数で降順に並ぶ。 2amount = [3, 8, 3, 5, 10, 3, 1]#人数

下記のようにすれば、全体の加重平均は取れるのですが、n人目までの加重平均を取り方が分からず困っています。
n人目というのはamountの上位n人目という意味で、amountの左から上位n人までのことです。

python

1wt_avg = sum([s*a for s,a in zip(score,amount)]) / sum(amount)#234.84848484848484 2

scoreは降順で並んでいて、amountはランダムの数字になります。
初歩的な質問で恐縮ですが、よろしくお願いします。

###補足情報(言語/FW/ツール等のバージョンなど)
python3.5.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

最初にデータを平たく並べるところがミソです。

python

1def wighted_avg(score, amount, top_n): 2 liner = sum(([s] * a for s, a in zip(score, amount)), []) 3 return sum(liner[:top_n]) / top_n 4 5score = [500, 400, 300, 200, 100, 50, 0] 6amount = [3, 8, 3, 5, 10, 3, 1] 7print(wighted_avg(score, amount, 10))

以下は別解。itertools祭り版。

python

1from itertools import chain 2from itertools import islice 3from itertools import repeat 4 5def wighted_avg(score, amount, top_n): 6 flatten = chain.from_iterable(map(repeat, score, amount)) 7 return sum(islice(flatten, top_n)) / top_n

投稿2017/11/16 13:32

編集2017/11/16 14:08
YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jaja

2017/11/16 13:37

解決しました!ありがとうございます。 このような関数を作ればいけるのですね。 誠にありがとうございます!
mkgrei

2017/11/16 14:29 編集

失礼しました。 質問の意図を勘違いしていました。
guest

0

デバッグしているうちに解決してしまいましたが…

ここによると、sumによるflattenは遅いそうです。
当該記述を参考に私が書いてみたのが下のコードです。

python

1score = [500, 400, 300, 200, 100, 50, 0] 2amount = [3, 8, 3, 5, 10, 3, 1] 3 4num_of_human = 10 5 6from itertools import chain 7# http://d.hatena.ne.jp/xef/20121027/p2 8target = list(chain.from_iterable([[s]*a for s,a in zip(score,amount)]))[0:num_of_human] 9 10avg = sum(target)/len(target) 11print(avg) 12

投稿2017/11/16 13:50

KojiDoi

総合スコア13671

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YouheiSakurai

2017/11/16 13:55 編集

chainだと上手く描けないなぁと思ってreduce的にsumを使いました。まぁsumだと遅いと思います。chainのfrom_iterable、勉強になります。
guest

0

すみません、修正しました。慌てて作ったのでちょっと良くないコードですね...

Python

1score = [500, 400, 300, 200, 100, 50, 0] 2amount = [3, 8, 3, 5, 10, 3, 1] 3 4num_of_human = 10 5 6score_total = 0 7human_total = 0 8for s, a in zip(score, amount): 9 for h in range(a): 10 score_total += s 11 human_total += 1 12 if human_total >= num_of_human: 13 break 14 if human_total >= num_of_human: 15 break 16 17wt_avg = score_total / num_of_human

投稿2017/11/16 12:52

編集2017/11/16 13:14
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jaja

2017/11/16 13:00

回答ありがとうございます。 amountのn番目というかamoutの上位n人の加重平均が取りたいのですが、 n番目と質問したのが悪かったです。。。 質問が分かりにくくて申し訳ないです。
LouiS0616

2017/11/16 13:14

しっかり読めば理解できた質問内容ではありました。大変失礼しました。 慌てて作ったのでかなり汚いコードですが、いちおう要件を満たすように編集しました。
LouiS0616

2017/11/16 13:21

もうちょっときれいに書けるはずなので、出来次第追記します。
jaja

2017/11/16 13:28

追加の回答ありがとうございます! n人目までの加重平均が取れました。ありがとうございます。 宜しければ、追記も頂ければ嬉しいです。
LouiS0616

2017/11/16 13:35

YouheiSakuraiさんのコードが非常に美しいですので、そちらを見ていただいた方がよさそうです。
jaja

2017/11/16 13:44

回答とコメントありがとうございました。 高評価させていただきました。
LouiS0616

2017/11/16 13:52

ご丁寧にありがとうございます、慌ててよろしくない回答をしてしまってすみません。 焼け石に水レベルですが、上記ループはfor-else文を用いるとちょっときれいになります。 さらに改良出来そうですが、もともとの方針的にYouheiSakuraiさんのコードの簡潔さは超えられなさそうですので、ちょっと控えておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問