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

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

ただいまの
回答率

87.58%

複数のデータフレームを組み合わせたあと、その中の数値を使って計算する

解決済

回答 2

投稿

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

score 4

Python、Pandasを使ったデータフレーム結合とその中の数値を使った計算に関する質問です。

下記のような色々な種類の果物と野菜の入ったバスケットをDF_1と仮定しています。

Bascket Grape Apple Orange Cucumber Carrot
0 50 50 0 0 100
1 0 20 80 50 50
2 0 70 30 70 30

各果物と野菜は下記DF_2のような属性を持っています。

Name Weight Price Suger_content
0 Grape     10 500 3
1 Apple     20 200 5
2 Orange 15 100 2
3 Cucumber 5 50 1
4 carrot 13 200 4

この二つのDFを組み合わせて以下のようにバスケットごとの属性を整理したいのですがうまくいきません。
fruitはfruitだけのWeight, Price, Suger contentでまとめてVegetableはVegetableのみでまとめたいです。
表には説明のため計算式を書いていますが、結果が表示されるようにしたいです。

Bascket Grape Apple Orange Cucumber carrot fruit_weight fruit_price fruit_Scontent vege_weight vege_price vege_Scontent
0 50 50 0 0 100 =10*50/100+20*50/100 =500*50/100+200*50/100 =3*50/100+5*50/100 =13*100/100 =200*100/100 =4*100/100
1 0 20 80 50 50 =20*20/100+15*80/100 =200*20/100+100*80/100 =5*20/100+2*80/100 =5*50/100+13*50/100 =50*50/100+200*50/100 =1*50/100+4*50/100
2 0 70 30 70 30 ... ... ... ... ... ...

該当のソースコード

for i, _ in df_1.iterrows():
    for i2, _ in df_2.iterrows():
        if df_2['Name'][i] in df_1.columns:
            df_1[i].append(df_2[i2])

試したこと

まずはDF_1とDF_2をつなげることからだと思い、上記のコードで結合しようとしたのですがkeyエラーが出てしまいそこから先に進めなくなってしまいました。
PriceやWeightの計算をするまで段階を経て進めていかなければならないことなのにすでに第一段階で躓いてしまい困っています。
ご助言を頂けると幸いです。
よろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

縦も横もサイズの違うdataframeを結合するのは、面倒な気がします。
果物&野菜の各情報は辞書型にして呼び出したほうがわかりやすのではないでしょうか。
参考にコード載せておきます。

import pandas as pd
import numpy as np

# テスト用データ作成
import io
txt = """
Bascket    Grape    Apple    Orange    Cucumber    Carrot
0    50    50    0    0    100
1    0    20    80    50    50
2    0    70    30    70    30
"""
df = pd.read_table(io.StringIO(txt), sep="\t")
print(df)
"""
Bascket  Grape  Apple  Orange  Cucumber  Carrot
0        0     50     50       0         0     100
1        1      0     20      80        50      50
2        2      0     70      30        70      30
"""

txt2 = """
Name    Weight    Price    Suger_content
0    Grape        10    500    3
1    Apple        20    200    5
2    Orange    15    100    2
3    Cucumber    5    50    1
4    Carrot    13    200    4
"""
df2 = pd.read_table(io.StringIO(txt2), sep="\s*\t+")
d = df2.set_index('Name').T.to_dict()
print(d)
"""
{'Grape': {'Weight': 10, 'Price': 500, 'Suger_content': 3}, 'Apple': {'Weight': 20, 'Price': 200, 'Suger_content': 5}, 'Orange': {'Weight': 15, 'Price': 100, 'Suger_content': 2}, 'Cucumber': {'Weight': 5, 'Price': 50, 'Suger_content': 1}, 'Carrot': {'Weight': 13, 'Price': 200, 'Suger_content': 4}}
"""

# ここから処理

def cal(x, e, f_v):
    #global e
    if f_v == "Vege":
        names = ["Cucumber", "Carrot"]
    else:
        names = ["Grape", "Apple", "Orange"]
    sum_e = 0
    for v in names:
        sum_e += x[v]*d[v][e]/100
    return sum_e
fruit_vege = ["Fruit", "Vege"]
es = ["Weight",  "Price", "Suger_content"]

for f_v in fruit_vege:
    for e in es:
        df[f"{f_v}_{e}"]=np.nan
        df[f"{f_v}_{e}"] = df.apply(cal, e=e, f_v=f_v, axis=1)
print(df)
"""
   Bascket  Grape  Apple  Orange  Cucumber  Carrot  Fruit_Weight  Fruit_Price  \
0        0     50     50       0         0     100          15.0        350.0   
1        1      0     20      80        50      50          16.0        120.0   
2        2      0     70      30        70      30          18.5        170.0   

   Fruit_Suger_content  Vege_Weight  Vege_Price  Vege_Suger_content  
0                  4.0         13.0       200.0                 4.0  
1                  2.6          9.0       125.0                 2.5  
2                  4.1          7.4        95.0                 1.9  
"""

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/09 16:31

    ありがとうございます。
    仰る通りで縦も横もサイズの違うDFをどうやって結合するかに気を取られており、辞書にするのは思いつきもしませんでした。
    目的の形にできて本当に助かりました。
    ありがとうございます!

    キャンセル

0

果物と野菜の分類の部分で少しコードがややこしくなっていますが、掛け算して足すだけなので容易に可能です。

import io

import pandas as pd

txt = """
Bascket,Grape,Apple,Orange,Cucumber,Carrot
0,50,50,0,0,100
1,0,20,80,50,50
2,0,70,30,70,30
"""
df = pd.read_csv(io.StringIO(txt))

txt2 = """
Name,Weight,Price,Suger_content
Grape,10,500,3
Apple,20,200,5
Orange,15,100,2
Cucumber,5,50,1
Carrot,13,200,4
"""
df2 = pd.read_csv(io.StringIO(txt2))


df
#    Bascket  Grape  Apple  Orange  Cucumber  Carrot
# 0        0     50     50       0         0     100
# 1        1      0     20      80        50      50
# 2        2      0     70      30        70      30
df2
#        Name  Weight  Price  Suger_content
# 0     Grape      10    500              3
# 1     Apple      20    200              5
# 2    Orange      15    100              2
# 3  Cucumber       5     50              1
# 4    Carrot      13    200              4

このとき、

groups = {'fruit': ['Grape', 'Apple', 'Orange'],
          'vege': ['Cucumber', 'Carrot']}

values = df.mul(df2.set_index('Name').unstack(), level=1)
sums = [values.loc[:, (slice(None), cols)]
        .sum(axis=1, level=0)
        .rename(columns=lambda n: groupname + '_' + n) / 100
        for groupname, cols in groups.items()]
pd.concat([df, *sums], axis=1)
#    Bascket  Grape  Apple  Orange  ...  fruit_Suger_content  vege_Weight  vege_Price  vege_Suger_content
# 0        0     50     50       0  ...                  4.0         13.0       200.0                 4.0
# 1        1      0     20      80  ...                  2.6          9.0       125.0                 2.5
# 2        2      0     70      30  ...                  4.1          7.4        95.0                 1.9

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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