「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