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

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

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

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

327閲覧

pythonのgroupby()の使用について

1mzmk

総合スコア42

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/03/26 07:32

Pandasのgroupby()の使用方法について分からないことがあります。
私のjsonファイルはワインについてのレビューについてのデータで、多くの種類のワインのレビューについてリストとして記載されています。行には"variety", "price", "point", "description"などの項目があります。
また、ワインの種類に関しては”variety”の列に記載されております。
イメージ説明

groupby()を使用して私のjsonファイルにおいて、例えばpriceの項目の値の平均値が20より小さい値、かつpointという項目の値の平均値が90以上の値の条件を満たすワインの種類を知りたい場合、
どのようにgroupby()を使用して、コードを書けば求められるのかが知りたいです。

私はまず、
**df.groupby("variety")["price"].filter(lambda x: x.mean() >20) **
を使って、まずpriceの項目の値の平均値が20より小さい値のワインだけを求めようとしたのですがエラーとなってしまいました。

なので、以下のことが知りたいです。
・priceの項目の値の平均値だけがが20より小さい値のワインの種類を求めるコード
・priceの項目の値の平均値が20より小さい値、かつpointという項目の値の平均値が90以上の値の条件を満たすワインの種類を求めるコード

よろしくお願いいたします。

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

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

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

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

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

tiitoi

2019/03/26 07:52 編集

読み込んでいる json の取得元を記載いただくか、データをどこかにアップしていただけますか?
t_obara

2019/03/26 07:51

priceの平均とpointの平均が出てきていますが、同一種類のワインがあり、その中の平均ということでしょうか。レビューデータの場合、単に同一種類としたとしても種類は同じだけれど、異なる個体と同一の個体が一緒になっていると思われますが、その点は考慮せず、単に貴殿が提示されている通り、varietyでgroupingすれば良いのでしょうか。
1mzmk

2019/03/26 08:13

https://github.com/tulip-lab/sit742/raw/master/Assessment/2019/data/wine.json こちらがjsonファイルの取得先になります。 また、同じ名称のワインの平均ということで求めて頂きたいです。なので、種類は同じだけれど、異なる個体と同一の個体が一緒になっている可能性があるということは考慮せずにお願いします。
guest

回答3

0

既に解決されているのですが・・

今回のように'variety'で纏めた(groupby()した)結果として

  • 'price'列 の平均
  • 'points'列 の平均
  • 'description'の数

など複数の結果を求めたい場合は

groupby().agg() を使用するのが適当です。

具体的に書くと、今回の場合は

Python

1res = df.groupby('variety').agg({'description':'count', 'price':'mean', 'points':'mean'})

のように記述します。あとは

Python

1res.loc[(res['price']<20) & (res['points']>90)]

のように書くことで

  • 'price'列 の平均が20以下
  • 'points'列 の平均が90以上

の銘柄が求まるのではないでしょうか。

投稿2019/03/27 00:34

magichan

総合スコア15898

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

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

1mzmk

2019/03/27 07:38

お答え頂きありがとうございます。 貴方の方法を使用すれば、jsonファイルにない項目を使って、新たな表も作成できるということでしょうか? 例えば、”country”ごとに それぞれの国で最もレビューを受けとったワインの種類、 それぞれの国での”point”の平均値 それぞれの国での”price”の平均値 に関する表を作りたい場合、それも可能ということでしょうか?
magichan

2019/03/27 09:51

「jsonファイルにない項目を使って、新たな表も作成」の箇所がどのようなことを指しているのかが掴めていないのですが、 DataFrame.groupby().agg() は既存のデータフレームを特定の列の値を元に再構成しえ新しいデータフレームを作成するものと考えてよいかと思います。 上記の目的であれば、guroupby() の引数に2つのカラム名をリストで指定して df.groupby(['country','variety']).agg({'price':['min','mean','max']}) のように書くと、国毎に各銘柄の最低価格、平均価格、最大価格を求めることができうかと思います。
1mzmk

2019/03/27 11:06

再三、お答え頂き本当にありがとうございます。 df.groupby(['country','variety']).agg({'price':['min','mean','max']}) では、行として”country”,"variety"のそれぞれの"price"の最低、最高、平均に関する表が作成できると思うのですが、 この同じ表に更に"price"と同じように”point”の項目の最低、最高、平均を追加したい場合はどのようにコードを書けるのでしょうか? また、貴方に提示していただいたコードでは”variety”の項目がそれぞれの国に対してすべての種類ものが表示されていると思われるのですが、これをそのそれぞれの国で最もレビューを受けとったワインの種類だけを”variety”の項目として表に表示したい場合は”count()”などを使用して表すことができるのでしょうか? 整理いたしますと、”country”, "variety", "price", "point"という項目で表を作りたく、 varietyの項目で、 そのそれぞれの国で最も一番レビューを受けとったワインの種類だけを”variety”の項目として表に表示したい。 先ほど、提示していただいたコードに”price”と同様に”point”の項目を追加したい。 となります。 いろいろとご迷惑おかけしますが、よろしくお願いいたします。
magichan

2019/03/28 02:43

スミマセン。遅くなりました。 『この同じ表に更に"price"と同じように”point”の項目の最低、最高、平均を追加したい場合はどのようにコードを書けるのでしょうか?』 agg() に渡す dict型のデータを agg({'price':['min','mean','max'], 'points':['min','mean','max'], 'description':'count'}) のようにするだけです。(descriptionの数も追加しております。) 『これをそのそれぞれの国で最もレビューを受けとったワインの種類だけを”variety”の項目として表に表示したい場合は”count()”などを使用して表すことができるのでしょうか?』 上記の処理で一度データフレームを作成し、そのデータフレームを再度 'country' で groupby() して 'description'の'count'値が大きいものだけに絞り込めばよいのではないでしょうか。
1mzmk

2019/03/28 08:36

df.groupby(['country','variety']).agg({'price':['min','mean','max'], 'points':['min','mean','max'], 'description':'count'})の処理をまず行い、その後に df.groupby("country")[df.groupby(['country','variety']).agg({'price':['min','mean','max'], 'points':['min','mean','max'],] すればよいということでしょうか?
magichan

2019/03/28 10:25

うーーん 違います。 1回目の groupby() にてすでに、国・銘柄毎の集計は終わっていますので、2回目の groupby() にて agg () を再度行う必要はありません。2回目は1回目の集計の中から'country' 毎にどの銘柄の description数が最大かを求めたら良いのではないかと提案したのです。
magichan

2019/03/28 10:40

あまり確認できておりませんが、 tmp = df.groupby(['country','variety']).agg({'price':['min','mean','max'], 'points':['min','mean','max'], 'description':'count'}).reset_index() のようにした後に tmp.groupby('country').apply(lambda d: d.loc[d[('description','count')].idxmax()]) とでもすると動くのではないでしょうか
magichan

2019/03/28 10:43

とりあえず、元の質問からかなり内容がズレてきましたので、いろいろ実験してみて、分からないところは再度質問を挙げていただけたらと思います。
1mzmk

2019/03/28 10:54

すいません、 おそらく私がPythonの学習を始めたばかりでまだその方法を理解できていないと思います。 なので、再三申し訳ないのですが、具体的なコードと説明をしていただけないでしょうか? 本当に何度も何度もすいません。
magichan

2019/03/28 10:56

2019/03/28 19:40 のコメントが具体的なコードです。
1mzmk

2019/03/28 12:10

本当にありがとうございます。 目的の列を抽出することができました。 ただ、作成された表に”country”が重複して表示せれているので、これを解消する方法はありますでしょうか? また、表から”description count ”という列も消去するほうほうはありますか?
1mzmk

2019/03/28 12:56

もしくはこの作成された表を保存したい列を指定してcsvファイルとして保存する方法ができる方法がありましたらその方法を教えてください。 よろしくお願いいたします。
magichan

2019/03/29 11:20

drop(columns=['country', 'description']) すれば良いのでは
guest

0

名称がtitleだとして、以下の様な感じでしょうか(未確認)

python

1mdf = df.groupby('title').mean() 2res = mdf.query('price < 20') 3print(res['variety']) 4res = mdf.query('price < 20 & points > 90') 5print(res['variety']) 6

投稿2019/03/26 08:28

t_obara

総合スコア5488

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

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

1mzmk

2019/03/26 08:43

すいません、priceの項目の値の平均値が20より小さい値、かつpointという項目の値の平均値が90以上の値の条件を満たすワインの種類(variery)だけを知りたく、”title”(名称)の列は関係ないようにおもわれるのですが、 その場合でも上のようなコードになるのですか?
t_obara

2019/03/26 08:46

同じ名称の平均値で比較するのではないのですか?
1mzmk

2019/03/26 08:53

すいません、説明が不十分でした。 同じ種類のワインの平均値で比較したいです。 よろしくお願いいたします。
t_obara

2019/03/26 08:58

であれば、titleの代わりにvarieryを使えばよろしいかと。
1mzmk

2019/03/26 09:01

それでは mdf = df.groupby('variety').mean() res = mdf.query('price < 20') print(res['variety']) res = mdf.query('price < 20 & points > 90') print(res['variety']) と入力すればよろしいですか?
guest

0

ベストアンサー

まず、data = df.groupby().mean()で平均値を集計して、そのあとに

print((data['price'] < 20) & ~(data['state'] > 90))

はダメでしょうか。

投稿2019/03/26 08:03

bamboo-nova

総合スコア1408

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

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

1mzmk

2019/03/26 08:27

まず、 data = df.groupby().mean() と入力すると TypeError: You have to supply one of 'by' and 'level' というエラーが表示されるのですが どうすればよろしいでしょうか。
bamboo-nova

2019/03/26 08:36

すみません、不十分でした。何の列のカテゴリを基準にして平均すれば良いのか教えてくださいと言われてますね。質問の文脈から察するに、 df.groupby(level=['variety']) ですね。
1mzmk

2019/03/26 08:58

df.groupby(level=['variety']) と入力すると level name variety is not the name of the index というエラーがでてきてしまいます。 私のjsonファイルには”variety”という行があるのにどうしてでしょうか? 再三ご迷惑をおかけしますが、よろしくお願いいたします。
bamboo-nova

2019/03/26 09:15

こちらこそ、重ねてご迷惑お掛けします汗 df.groupby(level=['variety'],axis=1) これによって、横方向にgroupbyしてくれます。詳しくはこちらを参考にしてください。 http://ailaby.com/groupby_yoko/
1mzmk

2019/03/26 10:57

ありがとうございました。 解決できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問