回答編集履歴

1

回答に追記

2019/04/01 00:37

投稿

magichan
magichan

スコア15898

test CHANGED
@@ -61,3 +61,111 @@
61
61
  #333 製品CCC 0.5 3000 2 (A1, A2)
62
62
 
63
63
  ```
64
+
65
+
66
+
67
+ ---
68
+
69
+
70
+
71
+ **【追記】**
72
+
73
+
74
+
75
+ 上記のコードを 先に ``groupby()`` してから ``agg()`` の中で "箱"と"ふくろ"を処理しないように修正してみます。
76
+
77
+
78
+
79
+ ```Python
80
+
81
+ def conv_parts_to_tuple(d):
82
+
83
+ return tuple(d[~d.isin(['箱', 'ふくろ'])])
84
+
85
+
86
+
87
+ def num_of_parts(d):
88
+
89
+ return d[~d.isin(['箱', 'ふくろ'])].count()
90
+
91
+
92
+
93
+ res = df.groupby(['品番','品名']).agg(
94
+
95
+ {
96
+
97
+ '単価':'first',
98
+
99
+ '生産数':'first',
100
+
101
+ '部品': [ num_of_parts,
102
+
103
+ conv_parts_to_tuple,]
104
+
105
+ })
106
+
107
+ res.columns = ['単価','生産数','部品項目数','部品一覧']
108
+
109
+ ```
110
+
111
+
112
+
113
+ やっていることはほとんどど同じなのですが、 ``agg()``内で2つのlambda(無名関数)を指定することが困難そうだったので、関数として切り出して処理しております。
114
+
115
+
116
+
117
+ "箱"と"ふくろ"の処理部が2つの関数に含まれて若干冗長な感じはあるのですが、この程度であればまあ個人的には問題ないかと思います。
118
+
119
+
120
+
121
+ ただ複数個の関数を切り出す必用があるのであれあ、``apply()``を使って1つの関数で処理したほうがシンプルになる気もしますね・・。
122
+
123
+
124
+
125
+ やってみます。
126
+
127
+
128
+
129
+ ```Python
130
+
131
+ def fnc(row):
132
+
133
+ tmp = row.loc[~row['部品'].isin(['箱', 'ふくろ']), '部品']
134
+
135
+ return pd.Series(
136
+
137
+ {
138
+
139
+ '単価': row['単価'].iat[0],
140
+
141
+ '生産数': row['生産数'].iat[0],
142
+
143
+ '部品項目数': tmp.count(),
144
+
145
+ '部品一覧': tuple(tmp)
146
+
147
+ })
148
+
149
+
150
+
151
+ res = df.groupby(['品番','品名']).apply(fnc)
152
+
153
+ print(res)
154
+
155
+ ```
156
+
157
+
158
+
159
+ > ``apply()``の場合は Series型のデータを返すことで列を構成します。
160
+
161
+
162
+
163
+ この方法であれば
164
+
165
+ - "箱"と"ふくろ"の処理部を共通化できる
166
+
167
+ - Column名を直に指定できるため変更の必要がない
168
+
169
+
170
+
171
+ のですこしシンプルになります。まあ、好みの問題ではありますが。。