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

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

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

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

Q&A

解決済

1回答

9230閲覧

python データフレーム 複数の列を条件として関数を適用させたい

yuyu127

総合スコア27

Python 3.x

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

0グッド

3クリップ

投稿2018/07/01 02:36

python のデータフレームで、複数の列を条件とした、新しい列(フラグ)を出力し、
それをもとに計算をしたいです。
下記2点質問があります。

質問1:複数列を条件としたapplyの適用
質問2:applyで作った新しい列をもとにした集計方法

詳細:
例として、曜日と時間の情報が入ったデータフレームに対し、各行毎に
「曜日-時間」という新しいフラグから、A、B、C列のそれぞれの値を計算したい。

python3

1#データフレーム例 2 3df = pd.DataFrame({ 'A' : [0,0,10,15,0,0], 4 'B' : [10,12,3,0,0,16], 5 'C' : [0,0,0,10,11,12], 6 '曜日' : ['日','日','月','月','火','火'], 7 '時間' : [9,10,11,12,9,10] 8 })
A B C 時間 曜日

0 0 10 0 9 日
1 0 12 0 10 日
2 10 3 0 11 月
3 15 0 10 12 月
4 0 0 11 9 火
5 0 16 12 10 火

やりたいこと:A、B、C 毎に、「曜日」と「時間帯」の組み合わせの数字を平均する。
時間は(9,10,11)を朝、(12,13,14)を昼の時間帯とする。

質問1:複数列を条件としたapplyの適用
まずは、新たに「曜日-時間」の列を作成しましたが、
なるべくfor文を使わず、高速化、効率化のため「applyで適用」させたいです。
なにかよい方法はありますでしょうか。

下記でforで作ってみました。

python3

1df['曜日-時間'] = 0 2 3for i in range(len(df)): 4 if (df['曜日'][i]=='日') & (df['時間'][i] in (9,10,11)): 5 df['曜日-時間'][i] = '日-朝' 6 7 elif(df['曜日'][i]=='月') & (df['時間'][i] in (9,10,11)): 8 df['曜日-時間'][i] = '月-朝' 9 10 elif(df['曜日'][i]=='火') & (df['時間'][i] in (9,10,11)): 11 df['曜日-時間'][i] = '火-朝' 12 13 elif (df['曜日'][i]=='日') & (df['時間'][i] in (12,13,14)): 14 df['曜日-時間'][i] = '日-昼' 15 16 elif(df['曜日'][i]=='月') & (df['時間'][i] in (12,13,14)): 17 df['曜日-時間'][i] = '月-昼' 18 19 elif(df['曜日'][i]=='火') & (df['時間'][i] in (12,13,14)): 20 df['曜日-時間'][i] = '火-昼' 21 22 else: 23 df['曜日-時間'] = 1

結果:
A B C 時間 曜日 曜日-時間
0 0 10 0 9 日 日-朝
1 0 12 0 10 日 日-朝
2 10 3 0 11 月 月-朝
3 15 0 10 12 月 月-昼
4 0 0 11 9 火 火-朝
5 0 16 12 10 火 火-朝

質問2:applyで作った新しい列をもとにした集計方法
A、B、C 毎に曜日と時間帯の組み合わせで平均する。
以下のようなデータフレームを最終的に作りたいのですが、何か効率的な
良い方法はありますでしょうか。

No 日-昼 日-朝 月-昼 月-朝 火-昼 火-朝

0 A 0 0 15 10 0 0.0
1 B 0 11 0 3 0 8.0
2 C 0 0 10 0 0 11.5

なにとぞよろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

曜日はそのまま採用、時間orに振り分ける関数を用意します。
この関数をdf.apply(にて行方向(axis=1)に適用します。

Python

1def to_wh(row): 2 hour = '?' 3 if row['時間'] in (9,10,11): 4 hour = '朝' 5 elif row['時間'] in (12,13,14): 6 hour = '昼' 7 return '{}-{}'.format(row['曜日'],hour) 8 9import pandas as pd 10df = pd.DataFrame({ 'A' : [0,0,10,15,0,0], 11 'B' : [10,12,3,0,0,16], 12 'C' : [0,0,0,10,11,12], 13 '曜日' : ['日','日','月','月','火','火'], 14 '時間' : [9,10,11,12,9,10] 15 }) 16df['曜日-時間'] = df.apply( to_wh, axis=1) 17print (df) 18 19# 集計 20gr = df.groupby('曜日-時間') 21print(gr.describe()) 22cols = ('A','B','C') 23print(gr.mean().loc[:,cols])

投稿2018/07/01 03:17

編集2018/07/01 07:12
can110

総合スコア38266

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

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

yuyu127

2018/07/01 04:37

can110さん ありがとうございます。 新列の作成はできました。 そのあと、A、B、C毎に曜日-時間の平均を出したく、 df.groupby('曜日-時間')['A'].mean() で出すことはできますが、A、B、Cの数が増えた場合に 効率的にデータフレームを作ることはできますでしょうか。 なにとぞよろしくお願いいたします。
can110

2018/07/01 07:15

推測ですが、groupby時点で各列の統計量が算出されているようなので 単一列でも複数列でも効率は変わらないかと思います。 なお、必要な複数列の結果を表示したい場合は 回答に示したようにcolsを動的に作りこむことでコードは簡略化できます。
yuyu127

2018/07/01 13:46

can110さん ありがとうございました。 最後のデータフレームまでできました。 大変助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問