41626


以下のデータフレームの一部の列において他のデータフレームの要素と一致するものを特定の番号に置き換える方法を教えていただけないでしょうか。

[code]

    import pandas as pd
    import numpy as np
    names = "A", "B", "C", "D"
    df1 = pd.DataFrame({'Name' : names,
                        'Test1' : [50, "Math", "game", "game"],
                        'Test2' : ["English", 40, 45, "game"],
                        'Test3' : ["work", "movie","Japanese", 50],
                        'Test4' : [30,"work","movie" ,"Japanese"]}
                      )
    df2 = pd.DataFrame({'Test' : ["English", "Math", "Japanese"],
                        'TestNumber' : [10, 20, 30]}
                      )    
    df1 
    df2
    
[/code]

出力結果  
df1

[code]

       Name Test1   Test2   Test3   Test4
    0   A    50    English  work     30
    1   B   Math     40     movie   work
    2   C   game     45   Japanese  movie
    3   D   game    game     50    Japanese
    
[/code]

df2

[code]

        Test    TestNumber
    0   English    10
    1   Math       20
    2   Japanese   30
    
[/code]

という二つのデータフレームがあります。  
(df1のイメージとして、4回の実験中1回のみ英語・数学・国語いずれかを勉強し、それ以外の3回の実験では何をして過ごしたのか睡眠をしたらその時間、その他は活動名を記録するというものです。実際はnamesもdf2のTestに相当するものも膨大にあります)  
これを、df1のTest1、Test2、Test3、Test4の中でdf2のTestと一致するものだけそのTestNumberで表して最終的に

[code]

      Name TestNumber   Test
    0   A   10         English
    1   B   20          Math
    2   C   30         Japanese
    3   D   30         Japanese
    
[/code]

となるようにしたいですが、方法が全く思いつきません...。  
何か有効な方法はないでしょうか？  
どうぞよろしくお願い致します。


CC BY-SA 3.0
2018-02-10T03:00:00.010
41623
2018-02-21T00:27:16.033
2018-02-15T06:31:25.367
27294
27294
question
python pandas
データフレームの一部の列において他のデータフレームの要素と一致するものを特定の番号に置き換える


こんな感じでどうでしょうか

> もう少しシンプルに記述できそうですがとりあえず・・。
[code]

    import pandas as pd
    import numpy as np
    names = "A", "B", "C", "D"
    df1 = pd.DataFrame({'Name' : names,
                        'Test1' : [50, "Math", "game", "game"],
                        'Test2' : ["English", 40, 45, "game"],
                        'Test3' : ["work", "movie","Japanese", 50],
                        'Test4' : [30,"work","movie" ,"Japanese"]}
                      )
    df2 = pd.DataFrame({'Test' : ["English", "Math", "Japanese"],
                        'TestNumber' : [10, 20, 30]}
                      )
    
    
    df1['TestNumber'] = df1.apply(lambda d: d.loc['Test1':].map(df2.set_index('Test').TestNumber).dropna().reset_index(drop=True), axis=1)[0]
    print(df1)
    #   Name Test1    Test2     Test3     Test4  TestNumber
    # 0    A    50  English      work        30        10.0
    # 1    B  Math       40     movie      work        20.0
    # 2    C  game       45  Japanese     movie        30.0
    # 3    D  game     game        50  Japanese        30.0
    
    
    # 必用であればTest1～Test4を削除
    print(Df1.drop(['Test1','Test2','Test3','Test4'], axis=1))
    #   Name  TestNumber
    # 0    A        10.0
    # 1    B        20.0
    # 2    C        30.0
    # 3    D        30.0
    
[/code]

**【追記】**  
上記の処理内容をわかりやすく書き直してみました。

[code]

    # df2 より 教科名->数値の変換用のSeriesデータを作成
    conv = df2.set_index('Test').TestNumber
    # 行毎にループ
    for idx, row in df1.iterrows():
        # Test1以降の列を変換データにて変換
        tmp = row['Test1':].map(conv)
        # 上の処理で変換できなかったデータは削除
        tmp = tmp.dropna()
        # 結果を 'TestNumber'列に追加
        if tmp.size > 0:
            df1.loc[idx, 'TestNumber'] = tmp[0]
    print(df1)
    
[/code]

**【更に追記】**

[code]

    # 上記のループの結果
    print(df1)
    #   Name Test1    Test2     Test3     Test4  TestNumber
    # 0    A    50  English      work        30        10.0
    # 1    B  Math       40     movie      work        20.0
    # 2    C  game       45  Japanese     movie        30.0
    # 3    D  game     game        50  Japanese        30.0
    
    # Test1～4 の列を削除
    df1 = df1.drop(['Test1','Test2','Test3','Test4'], axis=1)
    print(df1)
    #   Name  TestNumber
    # 0    A        10.0
    # 1    B        20.0
    # 2    C        30.0
    # 3    D        30.0
    
    # df2とマージ
    ret = pd.merge(df1, df2, on='TestNumber')
    print(ret)
    #   Name TestNumber      Test
    # 0    A         10   English
    # 1    B         20      Math
    # 2    C         30  Japanese
    # 3    D         30  Japanese
    
[/code]

**【更に追記２】**  
ループ内に教科名を追加する処理を追加

[code]

    conv = df2.set_index('Test').TestNumber
    for idx, row in df1.iterrows():
        # Test1以降の列を変換データにて変換
        tmp = row['Test1':].map(conv)
        # 変換できたデータを'Test'列に追加
        df1.loc[idx, 'Test'] = row[row['Test1':].index[tmp.notnull()][0]]
        # 上の処理で変換できなかったデータは削除
        tmp = tmp.dropna()
        # 結果を 'TestNumber'列に追加
        if tmp.size > 0:
            df1.loc[idx, 'TestNumber'] = tmp[0]
    
[/code]


CC BY-SA 3.0
2018-02-10T06:03:13.083
41626
2018-02-21T00:27:16.033
2018-02-21T00:27:16.033
24801
24801
41623
answer