89185


### 前提

材料開発においてMIを使用したいと考えております。言語はpythonを使用しています。

材料a,b,cを比率a : b : c=A:B:Cで混合する実験を想定しています。a,b,cには種類があり、例えばaはa_1とa_2があります。  
a,b,cにはそれぞれx,y,zという特性値をもっており、別のデータフレームにまとまっています。

### 目標

以下のコードで実行しているように材料の混合比率表に特性値を結合し、どの材料の特性値かが分かるようにしたいです。  
更に特性値ごとに材料の添加量で加重平均を計算したカラムを新たに追加したいです。

一つずつ書くことはできるのですが、実データでは膨大な特性値がありプログラム化したいです。  
初学者のため考えても分からず、困っております。大変恐縮ですが、どなたかお詳しい方ご教授いただけないでしょうか。

### 実現したいこと

以下のコードをプログラム化する。  
またはどのようにすれば類似のことが実行できるのか知りたいです。

### 該当のソースコード

[code]

    import pandas as pd
    
    # 材料a,b,cを比率a:b:c=A:B:Cで混合する表
    # a,b,cには種類があり、例えばaはa_1とa_2があります。
    df = pd.DataFrame({'a':['a_1', 'a_1', 'a_2'],
                       'b':['b_1', 'b_2', 'b_3'],
                       'c':['c_1', 'c_1', 'c_2'],
                       'A':[0.5,0.2,0.3],
                       'B':[0.2,0.3,0.4],
                       'C':[0.3,0.5,0.3]})
    #     a　 b   c   A   B   C
    #0  a_1 b_1 c_1 0.5 0.2 0.3
    #1  a_1 b_2 c_1 0.2 0.3 0.5
    #2  a_2 b_3 c_2 0.3 0.4 0.3
    
    
    # a,b,cはそれぞれx,y,zという特性値をもっており、別のデータフレームにまとまっています。
    df_a = pd.DataFrame({'a':['a_1','a_2'],'x': [1, 2], 'y': [4, 5],'z':[7, 8]})
    df_b = pd.DataFrame({'b':['b_1','b_2','b_3'],'x': [3, 4, 5], 'y': [6, 7, 8],'z':[9, 10, 11]})
    df_c = pd.DataFrame({'c':['c_1','c_2'],'x': [5, 6], 'y': [8, 9],'z':[11, 12]})
    #   a   x   y   z
    #0  a_1 1   4   7
    #1  a_2 2   5   8
    
    #   b   x   y   z
    #0  b_1 3   6   9
    #1  b_2 4   7   10
    #2  b_3 5   8   11
    
    #   c   x   y   z
    #0  c_1 5   8   11
    #1  c_2 6   9   12
    
    
    # 材料の混合表(df)に特性値(df_a,df_b,df_c)を結合し、どの材料の特性値かが分かるようにする
    df_new = df.merge(df_a,on='a')
    df_new = df_new.rename(columns={'x':'x_a','y':'y_a','z':'z_a'})
    df_new = df_new.merge(df_b,on='b')
    df_new = df_new.rename(columns={'x':'x_b','y':'y_b','z':'z_b'})
    df_new = df_new.merge(df_c,on='c')
    df_new = df_new.rename(columns={'x':'x_c','y':'y_c','z':'z_c'})
    
    #   a   b   c   A   B   C   x_a y_a z_a x_b y_b z_b x_c y_c z_c
    #0  a_1 b_1 c_1 0.5 0.2 0.3 1   4   7   3   6   9   5   8   11
    #1  a_1 b_2 c_1 0.2 0.3 0.5 1   4   7   4   7   10  5   8   11
    #2  a_2 b_3 c_2 0.3 0.4 0.3 2   5   8   5   8   11  6   9   12
    
    # 特性値ごとに材料の添加量で加重平均を計算したカラムを新たに追加
    df_new['x_ave'] = 
    (df_new['x_a']*df_new['A']+df_new['x_b']*df_new['B']+df_new['x_c']*df_new['C'])
    /(df_new['A']+df_new['B']+df_new['C'])
    df_new['y_ave'] = 
    (df_new['y_a']*df_new['A']+df_new['y_b']*df_new['B']+df_new['y_c']*df_new['C'])
    /(df_new['A']+df_new['B']+df_new['C'])
    df_new['z_ave'] = 
    (df_new['z_a']*df_new['A']+df_new['z_b']*df_new['B']+df_new['z_c']*df_new['C'])
    /(df_new['A']+df_new['B']+df_new['C'])
    
    #   a   b   c   A   B   C   x_a y_a z_a x_b y_b z_b x_c y_c z_c x_ave   y_ave   z_ave
    #0  a_1 b_1 c_1 0.5 0.2 0.3 1   4   7   3   6   9   5   8   11  2.6     5.6     8.6
    #1  a_1 b_2 c_1 0.2 0.3 0.5 1   4   7   4   7   10  5   8   11  3.9     6.9     9.9
    #2  a_2 b_3 c_2 0.3 0.4 0.3 2   5   8   5   8   11  6   9   12  4.4     7.4     10.4
    
[/code]


CC BY-SA 4.0
2022-06-01T09:46:36.667
89179
2022-06-03T11:06:36.963
2022-06-01T16:10:03.443
3060
52898
question
python pandas
データフレームを結合し、名前の変更と加重平均を算出する


> 更に特性値ごとに材料の添加量で加重平均を計算したカラムを新たに追加したいです。

よく意味がわからないけど, 質問にある処理を単純な計算式にできればよいのかな？と

`df` の行(index) は実験回数のようなものと想定して

`df_a`, `df_b`, `df_c` は面倒そうなのでまとめます  
x,y,zという特性値は膨大だということで, とりあえずは rowで扱う

[code]

    df = pd.DataFrame({'a':['a1', 'a1', 'a2'],
                       'b':['b1', 'b2', 'b3'],
                       'c':['c1', 'c1', 'c2'],
                       'A':[0.5,0.2,0.3],
                       'B':[0.2,0.3,0.4],
                       'C':[0.3,0.5,0.3]})
    dfprop = pd.DataFrame([[1,2,3,4,5,5,6],
                           [4,5,6,7,8,8,9],
                           [7,8,9,10,11,11,12]],
                        columns=['a1', 'a2', 'b1', 'b2', 'b3', 'c1', 'c2'],
                        index=['x', 'y', 'z'])
    
[/code]

mergeのようなことを行う処理

[code]

    for p in ['a', 'b', 'c']:
        dfn = dfprop[df[p]].T.add_suffix(f'_{p}')   # .reset_index(drop=True)
        display(dfn)
    
    #       x_a y_a z_a
    # a1    1   4   7
    # a1    1   4   7
    # a2    2   5   8
    # (b,c も同様に出力されるが省略)
    
    # これは以下で使う分 (内容は上記とほぼ同じ)
    d = {p: dfprop[df[p]].T.reset_index(drop=True) for p in ['a', 'b', 'c']}
    
[/code]

平均値, のための加算と割り算

[code]

    sumabc = sum(d[p].mul(df[p.upper()], axis=0) for p in ['a', 'b', 'c'])
    sumabc.div(df[['A', 'B', 'C']].sum(axis=1), axis=0).add_suffix('_ave')
    #   x_ave   y_ave   z_ave
    #   2.6 5.6 8.6
    #   3.9 6.9 9.9
    #   4.4 7.4 10.4
    
[/code]

* * *

(追記)

#### x,y,z 特性値 DataFrame

`dfprop` として用意した DataFrameは, どのように持つのが正しいか(こちらでは)分かりません  
(tidy data (整然データ) として rows/columnsにどう分けるか一番詳しいのは質問者さんなので)  
縦横逆転させるなら

[code]

    dfprop[df[p]].T
    # これをこのように: dfprop.loc[df[p]]
    
    dfs = {p: dfprop.loc[df[p]].reset_index(drop=True) for p in ['a', 'b', 'c']}
    
    # その場合の作成手順
    dfprop = pd.concat([df_a.set_index('a'),
                        df_b.set_index('b'),
                        df_c.set_index('c')])
    
[/code]

#### 特性が増えても大丈夫なこと

この回答のポイントは, `a1` / `a_1` や `a2` / `a_2` など `x`, `y`, `z` などを計算で直接扱っていないこと  
`x`, `y`, `z` の種類が多くなり数百種に上っても(計算上は)大丈夫

ただしその場合, DataFrameのカラム数が 数百 * (3種類 + 平均) 項目となり  
普通に表示 無理なのでは？

表示の仕方などに工夫が必要かもです


CC BY-SA 4.0
2022-06-01T14:44:19.250
89185
2022-06-03T11:06:36.963
2022-06-03T11:06:36.963
43025
43025
89179
answer