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

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

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

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

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

1回答

888閲覧

Pandasデータフレームの結合

SatokoM

総合スコア4

Python

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

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2020/07/09 04:36

編集2020/07/09 23:19

Python、Pandasを使ったデータフレーム結合に関する質問です。

下記のような色々な種類の果物の数量をDF_1と仮定しています。

BascketGrapeAppleOrange
050500
102080
207030

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

NameWeightPriceSuger_content
0Grape105003
1Apple202005
2Orange151002

DF_1で各果物の値が0より大きい場合に果物の属性DF_2を横持ちで追加したいです。

Bascket|Grape|Apple|Orange|weight_1|price_1|Suger_content_1|weight_2|price_2|Suger_content_2
|:--:|:--:|:--:|:--:
0|50|50|0|10|500|3|20|200|5
1|0|20|80|20|200|5|15|100|2
2|0|70|30|...|...|...|...|...|...|

該当のソースコード

Python

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

試したこと

よろしくお願いいたします。

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

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

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

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

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

aokikenichi

2020/07/09 08:58

_1 が Grape _2 が Apple _3 が Orange と紐づいているわけではなく 各果物の値が0以外の場合に左から詰めて_1、_2が付与されるということでよいでしょうか Bascket0のweight_2はAppleの20が入るのではないのでしょうか? 出来なくはないと思いますがテーブル構造はシンプルにして集計で工夫した方がよいと思います。
SatokoM

2020/07/09 23:22

>各果物の値が0以外の場合に左から詰めて_1、_2が付与されるということでよいでしょうか その通りです。二種類の果物の組み合わせだけで考えたいので左から詰めて_1、_2に格納したいです。 >Bascket0のweight_2はAppleの20が入るのではないのでしょうか? ご指摘ありがとうございます。訂正いたしました。
kirara0048

2020/07/10 02:33 編集

DF_1の各行につき、0になっている果物は常に1つという理解で良いですか? もしそうでない場合、 ・3つの果物すべてが50の場合、結果テーブルは_2までで打ち切るのか、_3まですべて含めるのか ・3つの果物すべてが0の場合、結果テーブルにはどのような値が入るのか よろしくお願いします。
guest

回答1

0

ベストアンサー

「DF_1の各行につき、0以上の果物の種類の数は常に同じ」の場合の方法です。

python

1import numpy as np 2import pandas as pd 3 4df_1 = pd.DataFrame({'Bascket': [0, 1, 2], 5 'Grape': [50, 0, 0], 6 'Apple': [50, 20, 70], 7 'Orange': [0, 80, 30]}) 8# Bascket Grape Apple Orange 9# 0 0 50 50 0 10# 1 1 0 20 80 11# 2 2 0 70 30 12 13df_2 = pd.DataFrame({'Name': ['Grape', 'Apple', 'Orange'], 14 'Weight': [10, 20, 15], 15 'Price': [500, 200, 100], 16 'Suger_content': [3, 5, 2]}) 17# Name Weight Price Suger_content 18# 0 Grape 10 500 3 19# 1 Apple 20 200 5 20# 2 Orange 15 100 2

このとき、

python

1array_left = df_1.to_numpy() 2_, idx = array_left[:, 1:].nonzero() 3array_right = df_2.iloc[:, 1:].to_numpy()[idx].reshape(len(array_left), -1) 4pd.DataFrame(np.hstack((array_left, array_right)), 5 columns=[*df_1.columns, 6 *[n + '_1' for n in df_2.columns[1:]], 7 *[n + '_2' for n in df_2.columns[1:]]]) 8# Bascket Grape Apple Orange Weight_1 Price_1 Suger_content_1 Weight_2 Price_2 Suger_content_2 9# 0 0 50 50 0 10 500 3 20 200 5 10# 1 1 0 20 80 20 200 5 15 100 2 11# 2 2 0 70 30 20 200 5 15 100 2

考え方

DF_1をndarrayに変換した後、まずnp.nonzero()を用いて、各列に対して「数量が0以上の果物が何であるか」という配列を作成します。
なお今回の例では存在しませんが、もしDF_1において果物の数量に負の値(0未満)が入っている場合は、0に変換してください。

python

1In [11]: array_left = df_1.to_numpy() 2 : array_left[array_left<0] = 0 # 数量が全て0以上の場合この行は不要 3 : _, idx = array_left[:, 1:].nonzero() 4 : 5 : idx.reshape(-1, 2) 6Out[11]: # (0, 1, 2) はそれぞれ (Grape, Apple, Orange) を表す 7array([[0, 1], # ←0列目は0=Grape, 1=Apple 8 [1, 2], # ←1列目は1=Apple, 2=Orange 9 [1, 2]], dtype=int64) # ←2列目は1=Apple, 2=Orange

次に、この配列をインデックスにして、ndarrayに変換したDF_2から各値を引っ張ってきます。
なお今回の例では問題ありませんが、DF_2の果物行の並び順が、DF_1の果物列の並び順(Grape→Apple→Orange)と異なる場合は、同じ順番にしてからndarrayに変換してください。

python

1In [12]: array_2 = df_2.iloc[:, 1:].to_numpy() 2 : array_2 = df_2.set_index('Name').loc[df_1.columns[1:]].to_numpy() # 並び順が異なる場合 3 : array_2 4Out[12]: 5array([[ 10, 500, 3], # ←0=Grapeのデータ 6 [ 20, 200, 5], # ←1=Appleのデータ 7 [ 15, 100, 2]], dtype=int64) # ←2=Orangeのデータ 8 9 10In [13]: array_right_pre = array_2[idx.reshape(-1, 2)] 11 : array_right_pre 12Out[13]: 13array([[[ 10, 500, 3], # 0列目 # 0=Grape のデータ 14 [ 20, 200, 5]], # 1=Apple のデータ 15 16 [[ 20, 200, 5], # 1列目 # 1=Apple のデータ 17 [ 15, 100, 2]], # 2=Orange のデータ 18 19 [[ 20, 200, 5], # 2列目 # 1=Apple のデータ 20 [ 15, 100, 2]]], dtype=int64) # 2=Orange のデータ 21 22 23In [14]: array_right = array_right_pre.reshape(len(array_left), -1) 24 : array_right 25Out[14]: 26array([[ 10, 500, 3, 20, 200, 5], 27 [ 20, 200, 5, 15, 100, 2], 28 [ 20, 200, 5, 15, 100, 2]], dtype=int64)

最後に結合してデータフレームに変換します。列名は手動で適切なものを設定してください。

python

1In [15]: data = np.hstack((array_left, array_right)) 2 : 3 : data 4Out[15]: # <----left----> <-----------right----------> 5array([[ 0, 50, 50, 0, 10, 500, 3, 20, 200, 5], 6 [ 1, 0, 20, 80, 20, 200, 5, 15, 100, 2], 7 [ 2, 0, 70, 30, 20, 200, 5, 15, 100, 2]], dtype=int64) 8 9 10In [16]: pd.DataFrame(data, 11 : columns=[*df_1.columns, 12 : *[n + '_1' for n in df_2.columns[1:]], 13 : *[n + '_2' for n in df_2.columns[1:]]]) 14Out[16]: 15 Bascket Grape Apple Orange Weight_1 Price_1 Suger_content_1 Weight_2 Price_2 Suger_content_2 160 0 50 50 0 10 500 3 20 200 5 171 1 0 20 80 20 200 5 15 100 2 182 2 0 70 30 20 200 5 15 100 2

投稿2020/07/14 01:11

kirara0048

総合スコア1399

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

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

SatokoM

2020/07/15 06:02

ご回答いただきありがとうございます。 解説も丁寧にしていただいたので理解することができ、今後応用もできそうです。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問