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

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

ただいまの
回答率

91.04%

  • Python 3.x

    4060questions

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

pythonでの加重平均について

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 307

jaja

score 4

前提・実現したいこと

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

返ってくる値の一例

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

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

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


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

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

python3.5.2

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+6

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

def wighted_avg(score, amount, top_n):
    liner = sum(([s] * a for s, a in zip(score, amount)), [])
    return sum(liner[:top_n]) / top_n

score = [500, 400, 300, 200, 100, 50, 0]
amount = [3, 8, 3, 5, 10, 3, 1]
print(wighted_avg(score, amount, 10))

以下は別解。itertools祭り版。

from itertools import chain
from itertools import islice
from itertools import repeat

def wighted_avg(score, amount, top_n):
    flatten = chain.from_iterable(map(repeat, score, amount))
    return sum(islice(flatten, top_n)) / top_n

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/16 22:37

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

    キャンセル

  • 2017/11/16 23:29 編集

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

    キャンセル

+3

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

score = [500, 400, 300, 200, 100, 50, 0]
amount = [3, 8, 3, 5, 10, 3, 1]

num_of_human = 10

score_total = 0
human_total = 0
for s, a in zip(score, amount):
    for h in range(a):
        score_total += s
        human_total += 1
        if human_total >= num_of_human:
            break
    if human_total >= num_of_human:
        break

wt_avg = score_total / num_of_human            

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/16 22:00

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

    キャンセル

  • 2017/11/16 22:14

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

    キャンセル

  • 2017/11/16 22:21

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

    キャンセル

  • 2017/11/16 22:28

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

    キャンセル

  • 2017/11/16 22:35

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

    キャンセル

  • 2017/11/16 22:44

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

    キャンセル

  • 2017/11/16 22:52

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

    キャンセル

+3

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

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

score = [500, 400, 300, 200, 100, 50, 0]
amount = [3, 8, 3, 5, 10, 3, 1]

num_of_human = 10

from itertools import chain
# http://d.hatena.ne.jp/xef/20121027/p2
target = list(chain.from_iterable([[s]*a for s,a in zip(score,amount)]))[0:num_of_human]

avg = sum(target)/len(target)
print(avg)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/16 22:55 編集

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

    キャンセル

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

  • ただいまの回答率 91.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    4060questions

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