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

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

ただいまの
回答率

88.82%

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 319

mmtt

score 18

やりたいこと

既に作成している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さんに教えていただいた方法を試したところ、以下のようになってしまいました。
イメージ説明
イメージ説明
ご回答よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

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

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

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

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

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

import pandas as pd
import io

csv = """
match,set,game,gamewinner,team1,team2
1,1,1,1,A,B
1,1,2,1,A,B
1,2,1,2,A,B
1,2,2,1,A,B
1,2,3,2,A,B
1,3,1,1,A,B
1,3,2,2,A,B
1,3,3,1,A,B
1,3,4,1,A,B
2,1,1,2,B,C
2,1,2,2,B,C
2,2,1,1,B,C
2,2,2,2,B,C
2,2,3,2,B,C
2,3,1,1,B,C
2,3,2,2,B,C
2,3,3,1,B,C
2,3,4,2,B,C
2,3,5,2,B,C
"""

df = pd.read_csv(io.StringIO(csv))

df['setwinner'] = df.groupby(['match','set'])['gamewinner'].transform(lambda d:d.mode()[0])
df['matchwinner'] = df.groupby(['match'])['setwinner'].transform(lambda d:d.mode()[0])
print(df)
#    match  set  game  gamewinner team1 team2  setwinner  matchwinner
#0       1    1     1           1     A     B          1            1
#1       1    1     2           1     A     B          1            1
#2       1    2     1           2     A     B          2            1
#3       1    2     2           1     A     B          2            1
#4       1    2     3           2     A     B          2            1
#5       1    3     1           1     A     B          1            1
#6       1    3     2           2     A     B          1            1
#7       1    3     3           1     A     B          1            1
#8       1    3     4           1     A     B          1            1
#9       2    1     1           2     B     C          2            2
#10      2    1     2           2     B     C          2            2
#11      2    2     1           1     B     C          2            2
#12      2    2     2           2     B     C          2            2
#13      2    2     3           2     B     C          2            2
#14      2    3     1           1     B     C          2            2
#15      2    3     2           2     B     C          2            2
#16      2    3     3           1     B     C          2            2
#17      2    3     4           2     B     C          2            2
#18      2    3     5           2     B     C          2            2

【追記】

動作確認サンプル その2

import pandas as pd
import io

csv = """
,week,match,set,game,team1,team2,game winner
0,1,1,1,1,gamewith,detonation,1
1,1,1,1,2,gamewith,detonation,1
2,1,1,2,1,gamewith,detonation,2
3,1,1,2,2,gamewith,detonation,1
4,1,1,2,3,gamewith,detonation,2
5,1,1,3,1,gamewith,detonation,2
6,1,1,3,2,gamewith,detonation,1
7,1,1,3,3,gamewith,detonation,1
8,1,1,3,4,gamewith,detonation,1
9,1,2,1,1,C,talon-espo,2
10,1,2,1,2,C,talon-espo,1
11,1,2,1,3,C,talon-espo,2
12,1,2,2,1,C,talon-espo,2
13,1,2,2,2,C,talon-espo,1
14,1,2,2,3,C,talon-espo,1
15,1,2,3,1,C,talon-espo,2
16,1,2,3,2,C,talon-espo,1
17,1,2,3,3,C,talon-espo,1
18,1,2,3,4,C,talon-espo,2
19,1,2,3,5,C,talon-espo,1
20,1,3,1,1,bren-espo,sandbox,2
21,1,3,1,2,bren-espo,sandbox,2
22,1,3,2,1,bren-espo,sandbox,2
23,1,3,2,2,bren-espo,sandbox,1
24,1,3,3,1,bren-espo,sandbox,2
25,1,3,3,2,bren-espo,sandbox,1
"""

df = pd.read_csv(io.StringIO(csv), index_col=0)
print(df)

df['set winner'] = df.groupby(['match','set'])['game winner'].transform(lambda d:d.mode()[0])
df['match winner'] = df.groupby(['match'])['set winner'].transform(lambda d:d.mode()[0])
print(df)
#    week  match  set  game      team1       team2  game winner  setwinner  matchwinner
#0      1      1    1     1   gamewith  detonation            1          1            1
#1      1      1    1     2   gamewith  detonation            1          1            1
#2      1      1    2     1   gamewith  detonation            2          2            1
#3      1      1    2     2   gamewith  detonation            1          2            1
#4      1      1    2     3   gamewith  detonation            2          2            1
#5      1      1    3     1   gamewith  detonation            2          1            1
#6      1      1    3     2   gamewith  detonation            1          1            1
#7      1      1    3     3   gamewith  detonation            1          1            1
#8      1      1    3     4   gamewith  detonation            1          1            1
#9      1      2    1     1          C  talon-espo            2          2            1
#10     1      2    1     2          C  talon-espo            1          2            1
#11     1      2    1     3          C  talon-espo            2          2            1
#12     1      2    2     1          C  talon-espo            2          1            1
#13     1      2    2     2          C  talon-espo            1          1            1
#14     1      2    2     3          C  talon-espo            1          1            1
#15     1      2    3     1          C  talon-espo            2          1            1
#16     1      2    3     2          C  talon-espo            1          1            1
#17     1      2    3     3          C  talon-espo            1          1            1
#18     1      2    3     4          C  talon-espo            2          1            1
#19     1      2    3     5          C  talon-espo            1          1            1
#20     1      3    1     1  bren-espo     sandbox            2          2            1
#21     1      3    1     2  bren-espo     sandbox            2          2            1
#22     1      3    2     1  bren-espo     sandbox            2          1            1
#23     1      3    2     2  bren-espo     sandbox            1          1            1
#24     1      3    3     1  bren-espo     sandbox            2          1            1
#25     1      3    3     2  bren-espo     sandbox            1          1            1

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/06/03 12:46

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

    キャンセル

  • 2019/06/03 13:47

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

    キャンセル

  • 2019/06/03 15:04

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

    キャンセル

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 12:49

    ameharaさん回答ありがとうございます。
    試してみます!

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

    キャンセル

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

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

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