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

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

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

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

Q&A

解決済

2回答

441閲覧

pandas で条件をもとに列追加したい

mmtt

総合スコア23

Python

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

0グッド

0クリップ

投稿2019/06/02 09:40

編集2019/06/03 03:43

##やりたいこと
既に作成しているDataFrameに対して、新しく追加する列に、特定の条件のもと適した値を入れたいと思っています。
今回はゲームの大会のデータを持ってきているのですが、そのゲームの対戦方式として、
1セット目:2人vs2人のバトル(2本先取で勝ち)
2セット目:1人vs1人のバトル(2本先取で勝ち)
3セット目:1人vs1人のバトル(3名の勝ち残りで相手を全滅させたら勝利)

となっており、2セット先取で試合に勝利となっています。

既にはdfというデータフレームの中に列が[match(通算で何試合目か),set(何セット目か),game(セット内で何試合目か),gamewinner(その1試合での勝者),team1(チーム1の名前),team2(チーム2の名前)]という風に入っています。

↓現在のデータフレーム

print(df)   #match #set #game #gamewinner #team1 #team2 #1 1 1 1 1 A B #2 1 1 2 1 A B #3 1 2 1 2 A B #4 1 2 2 1 A B #5 1 2 3 2 A B #6 1 3 1 1 A B #7 1 3 2 2 A B #8 1 3 3 1 A B #9 1 3 4 1 A B #10 2 1 1 2 C D ...続く

このようになっているデータフレームにsetwinner,matchwinnerという新たな列を追加し、そのセット全体/試合全体でどちらが勝利したのかを1つの行から分かるようにしたいと考えています。

↓やりたいイメージ

print(df)   #match #set #game #gamewinner #team1 #team2 #setwinner #matchwinner #1 1 1 1 1 A B 1 1 #2 1 1 2 1 A B 1 1 #3 1 2 1 2 A B 2 1 #4 1 2 2 1 A B 2 1 #5 1 2 3 2 A B 2 1 #6 1 3 1 1 A B 1 1 #7 1 3 2 2 A B 1 1 #8 1 3 3 1 A B 1 1 #9 1 3 4 1 A B 1 1 #10 2 1 1 2 C D 2 1

##わからないこと
前後の行の情報を用いないとできないため、どのようにしたらやりたいことが実装できるのかわからず、困っています。

##試してみたこと
他行の情報を見なくてもだできる点に関してはこれで実装できたのですが、そのほかの場合が分かりませんでした。

♯1,2セット目において3ゲームまでもつれ込んだ場合、3ゲーム目の勝者がそのセットの勝者 df.loc[(df["game"]==3)&(df["set"]!=3),"setwinner"] = df["gamewinner"]

追記

magichanさんに教えていただいた方法を試したところ、以下のようになってしまいました。
イメージ説明
イメージ説明
ご回答よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

基本的な考え方としては、以下のように groupby() にて match毎にグループ化し、
さらにその中でset毎にグループ化して2重ループを構成し、各set毎に 'gamewinner'
の最頻値(mode)をもとめることで各setの勝者を、さらにはsetの勝者が多い方を match
の勝者として算出するとよいだけです。

Python

1# match毎にループ 2for match, match_df in df.groupby('match'): 3 # set毎にループ 4 winners = [] 5 for set, set_df in match_df.groupby('set'): 6 # setの勝者(同点は無いものとして算出してます) 7 set_winner = set_df['gamewinner'].mode()[0] 8 print("MATCH: {}, SET: {}, WINNER: {}".format(match, set, set_winner)) 9 winners.append(set_winner) 10 # matchの勝者(同点は無いものとして算出してます) 11 match_winner = pd.Series(set_winner).mode()[0] 12 print("MATCH: {}, WINNER: {}".format(match, match_winner))

あとは、これをgroupby.transform() や groupby.apply() でまとめるとスッキリと書けます。

Python

1df['setwinner'] = df.groupby(['match','set'])['gamewinner'].transform(lambda d:d.mode()[0]) 2df['matchwinner'] = df.groupby(['match'])['setwinner'].transform(lambda d:d.mode()[0])

以下は動作サンプルです。

Python

1import pandas as pd 2import io 3 4csv = """ 5match,set,game,gamewinner,team1,team2 61,1,1,1,A,B 71,1,2,1,A,B 81,2,1,2,A,B 91,2,2,1,A,B 101,2,3,2,A,B 111,3,1,1,A,B 121,3,2,2,A,B 131,3,3,1,A,B 141,3,4,1,A,B 152,1,1,2,B,C 162,1,2,2,B,C 172,2,1,1,B,C 182,2,2,2,B,C 192,2,3,2,B,C 202,3,1,1,B,C 212,3,2,2,B,C 222,3,3,1,B,C 232,3,4,2,B,C 242,3,5,2,B,C 25""" 26 27df = pd.read_csv(io.StringIO(csv)) 28 29df['setwinner'] = df.groupby(['match','set'])['gamewinner'].transform(lambda d:d.mode()[0]) 30df['matchwinner'] = df.groupby(['match'])['setwinner'].transform(lambda d:d.mode()[0]) 31print(df) 32# match set game gamewinner team1 team2 setwinner matchwinner 33#0 1 1 1 1 A B 1 1 34#1 1 1 2 1 A B 1 1 35#2 1 2 1 2 A B 2 1 36#3 1 2 2 1 A B 2 1 37#4 1 2 3 2 A B 2 1 38#5 1 3 1 1 A B 1 1 39#6 1 3 2 2 A B 1 1 40#7 1 3 3 1 A B 1 1 41#8 1 3 4 1 A B 1 1 42#9 2 1 1 2 B C 2 2 43#10 2 1 2 2 B C 2 2 44#11 2 2 1 1 B C 2 2 45#12 2 2 2 2 B C 2 2 46#13 2 2 3 2 B C 2 2 47#14 2 3 1 1 B C 2 2 48#15 2 3 2 2 B C 2 2 49#16 2 3 3 1 B C 2 2 50#17 2 3 4 2 B C 2 2 51#18 2 3 5 2 B C 2 2

###【追記】
動作確認サンプル その2

Python

1import pandas as pd 2import io 3 4csv = """ 5,week,match,set,game,team1,team2,game winner 60,1,1,1,1,gamewith,detonation,1 71,1,1,1,2,gamewith,detonation,1 82,1,1,2,1,gamewith,detonation,2 93,1,1,2,2,gamewith,detonation,1 104,1,1,2,3,gamewith,detonation,2 115,1,1,3,1,gamewith,detonation,2 126,1,1,3,2,gamewith,detonation,1 137,1,1,3,3,gamewith,detonation,1 148,1,1,3,4,gamewith,detonation,1 159,1,2,1,1,C,talon-espo,2 1610,1,2,1,2,C,talon-espo,1 1711,1,2,1,3,C,talon-espo,2 1812,1,2,2,1,C,talon-espo,2 1913,1,2,2,2,C,talon-espo,1 2014,1,2,2,3,C,talon-espo,1 2115,1,2,3,1,C,talon-espo,2 2216,1,2,3,2,C,talon-espo,1 2317,1,2,3,3,C,talon-espo,1 2418,1,2,3,4,C,talon-espo,2 2519,1,2,3,5,C,talon-espo,1 2620,1,3,1,1,bren-espo,sandbox,2 2721,1,3,1,2,bren-espo,sandbox,2 2822,1,3,2,1,bren-espo,sandbox,2 2923,1,3,2,2,bren-espo,sandbox,1 3024,1,3,3,1,bren-espo,sandbox,2 3125,1,3,3,2,bren-espo,sandbox,1 32""" 33 34df = pd.read_csv(io.StringIO(csv), index_col=0) 35print(df) 36 37df['set winner'] = df.groupby(['match','set'])['game winner'].transform(lambda d:d.mode()[0]) 38df['match winner'] = df.groupby(['match'])['set winner'].transform(lambda d:d.mode()[0]) 39print(df) 40# week match set game team1 team2 game winner setwinner matchwinner 41#0 1 1 1 1 gamewith detonation 1 1 1 42#1 1 1 1 2 gamewith detonation 1 1 1 43#2 1 1 2 1 gamewith detonation 2 2 1 44#3 1 1 2 2 gamewith detonation 1 2 1 45#4 1 1 2 3 gamewith detonation 2 2 1 46#5 1 1 3 1 gamewith detonation 2 1 1 47#6 1 1 3 2 gamewith detonation 1 1 1 48#7 1 1 3 3 gamewith detonation 1 1 1 49#8 1 1 3 4 gamewith detonation 1 1 1 50#9 1 2 1 1 C talon-espo 2 2 1 51#10 1 2 1 2 C talon-espo 1 2 1 52#11 1 2 1 3 C talon-espo 2 2 1 53#12 1 2 2 1 C talon-espo 2 1 1 54#13 1 2 2 2 C talon-espo 1 1 1 55#14 1 2 2 3 C talon-espo 1 1 1 56#15 1 2 3 1 C talon-espo 2 1 1 57#16 1 2 3 2 C talon-espo 1 1 1 58#17 1 2 3 3 C talon-espo 1 1 1 59#18 1 2 3 4 C talon-espo 2 1 1 60#19 1 2 3 5 C talon-espo 1 1 1 61#20 1 3 1 1 bren-espo sandbox 2 2 1 62#21 1 3 1 2 bren-espo sandbox 2 2 1 63#22 1 3 2 1 bren-espo sandbox 2 1 1 64#23 1 3 2 2 bren-espo sandbox 1 1 1 65#24 1 3 3 1 bren-espo sandbox 2 1 1 66#25 1 3 3 2 bren-espo sandbox 1 1 1

投稿2019/06/03 00:24

編集2019/06/03 04:41
magichan

総合スコア15898

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

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

mmtt

2019/06/03 02:08

magichanさん、ありがとうございます。 教えていただいた通り実行すると、エラーがなく動いたのですが、上に追記した画像のように、match wiinnerが全て2になってしまい、set winner も本来の正しい値を反映できていないようです。 原因がわかれば教えてください。
magichan

2019/06/03 02:32

申し訳ありませんが、添付していただいた画像では全てのデータが表示されておりませんので検証できません。 pd.set_option('display.max_columns', 20) として、最大20列表示できるように設定し、再度実行結果を貼っていただけないでしょうか。
mmtt

2019/06/03 03:46

こちらこそ申し訳ありません!全体表示が上手くできず、csvに保存し、今質問に関係のない部分を修正しているため見えにくくなっていますが、よろしくお願いします。
magichan

2019/06/03 04:47

今回追加していただいたデータを使ってみましたが、残念ながら現象を再現できませんでした。 とりあえず、私が動作させたサンプルコードを 【動作確認サンプル その2】として追加しました。そのままコピペしていただくと動作すると思いますので、一度動作させて確認してみていたでけませんでしょうか。 ご自身のデータと比較していただくとなにか違いがあるかもしれません。
mmtt

2019/06/03 06:04

すみません、色々と試してみたところ自分のデータに問題があり、修正したところ上手くいきました。手寧に教えてくださり大変助かりました。ありがとうございました!
guest

0

大会の性質上、セット内の最終ゲーム勝利者がセット勝利者、マッチ内の最終セット勝利者がマッチ勝利者になります。

すなわち、ゲーム勝利者を同マッチ・同セットのセット勝利者に反映、セット勝利者を同マッチのマッチ勝利者に反映するのを、各行毎に更新していけばいいのではないでしょうか。

コード例は以下になります。ただ、最終行の数値が必要になるので、magichanさんのコードのほうが便利かと思います。

print(df) for i in range(1,11): #すでに終了したマッチの分しか正確に記入できないので注意 #セット勝利の記入 df.loc[(df["#match"]==df.at['#'+str(i),'#match'])&(df["#set"]==df.at['#'+str(i),'#set']),"#setwinner"] = df.at['#'+str(i),'#gamewinner'] #マッチ勝利の記入 df.loc[(df["#match"]==df.at['#'+str(i),'#match']),"#matchwinner"] = df.at['#'+str(i),'#setwinner'] print(df)

あと、完全なる蛇足ですが、最初の実装方針は以下のように「ゲーム勝利数をカウントし、条件に応じてセット勝利・マッチ勝利をカウント・記入する」という感じでした。

import pandas as pd df=pd.read_excel('excel1.xlsx') print(df) for i in range(1,11): #セット勝利数リセット if df.at['#'+str(i),'#set']==1: print('match start') times_won_set_team1=0 times_won_set_team2=0 #ゲーム勝利数リセット if df.at['#'+str(i),'#game']==1: print('set start') times_won_game_team1=0 times_won_game_team2=0 #ゲーム勝利数カウント if df.at['#'+str(i),'#gamewinner']==1: print('team1 won') times_won_game_team1+=1 print('team1:'+str(times_won_game_team1)) else: print('team2 won') times_won_game_team2+=1 print('team2:'+str(times_won_game_team2)) #セット勝利数カウント、セット勝利の記入 #第1、第2セットの場合 if times_won_game_team1==2 and df.at['#'+str(i),'#set']<=2: print('team1 set won') times_won_set_team1+=1 df.at['#'+str(i),'#setwinner']=1 elif times_won_game_team2==2 and df.at['#'+str(i),'#set']<=2: print('team2 set won') times_won_set_team2+=1 df.at['#'+str(i),'#setwinner']=2 #第3セットの場合 elif times_won_game_team1==3 and df.at['#'+str(i),'#set']==3: print('team1 set won') times_won_set_team1+=1 df.at['#'+str(i),'#setwinner']=1 elif times_won_game_team2==3 and df.at['#'+str(i),'#set']==3: print('team2 set won') times_won_set_team2+=1 df.at['#'+str(i-1),'#setwinner']=2 #マッチ勝利の記入 if times_won_set_team1==2: print('team1 match won') df.at['#'+str(i),'#matchwinner']=1 elif times_won_set_team2==2: print('team2 match won') df.at['#'+str(i),'#matchwinner']=2 print(df)

このコードをたたき台にしていろいろ修正をかけた結果、冒頭のコードになりました。

プログラミングの勉強が目的でしたら、まずは愚直に冗長なクソコードを書いてみて、徐々に洗練させていく方針でいくと、上達も早いんじゃないかなと思います。

投稿2019/06/03 02:21

amahara_waya

総合スコア1029

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

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

mmtt

2019/06/03 03:49

ameharaさん回答ありがとうございます。 試してみます! >>プログラミングの勉強が目的でしたら、まずは愚直に冗長なクソコードを書いてみて、徐々に洗練させていく方針でいくと、上達も早いんじゃないかなと思います。 プログラミングの勉強に関するアドバイスもありがとうございます!助かります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問