teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

いろんなコードを試行してみました

2020/02/20 04:36

投稿

kirara0048
kirara0048

スコア1399

answer CHANGED
@@ -1,11 +1,29 @@
1
+ その1:質問のコードを直したもの
2
+
1
3
  ```python
2
- df['Season'].astype(str).str.cat([
4
+ df["ID"] = df['Season'].astype(str).str.cat([
3
5
  df[['WTeamID', 'LTeamID']].min(1).astype(str),
4
6
  df[['WTeamID', 'LTeamID']].max(1).astype(str)], '_')
5
7
  ```
6
8
 
7
- ## 解説
9
+ その2:より簡単なコード
8
10
 
11
+ ```python
12
+ df["ID"] = df['Season'].astype(str).str.cat(
13
+ np.sort(df[['LTeamID', 'WTeamID']].to_numpy()).astype(str), '_')
14
+ ```
15
+
16
+ その3:リストを使う方法
17
+
18
+ ```python
19
+ arr_s = df['Season'].tolist()
20
+ arr_lw = np.sort(df[['LTeamID', 'WTeamID']].to_numpy()).tolist()
21
+ df["ID"] = pd.Series([f'{s}_{lw[0]}_{lw[1]}' for s, lw in zip(arr_s, arr_lw)],
22
+ index=df.index)
23
+ ```
24
+
25
+ ## 解説(その1)
26
+
9
27
  > ①str(df["Season"]) のoutputがdataframe形式で返されない
10
28
 
11
29
  `str()`は文字列型を返す関数です。`pd.Series`(或いは`pd.DataFrame`)のデータ型を文字列型(正確にはオブジェクト型)にする場合は`pd.Series.astype(str)`を使います。
@@ -87,10 +105,10 @@
87
105
  したがって、
88
106
 
89
107
  ```python
90
- In [28]: df['Season'].astype(str).str.cat([
108
+ In [26]: df['Season'].astype(str).str.cat([
91
109
  2 df[['WTeamID', 'LTeamID']].min(1).astype(str),
92
110
  3 df[['WTeamID', 'LTeamID']].max(1).astype(str)], '_')
93
- Out[28]:
111
+ Out[26]:
94
112
  1916 2015_1214_1264
95
113
  1917 2015_1140_1279
96
114
  1918 2015_1129_1173
@@ -103,4 +121,83 @@
103
121
  1981 2015_1246_1458
104
122
  1982 2015_1181_1458
105
123
  Name: Season, dtype: object
106
- ```
124
+ ```
125
+
126
+ ## 解説(その2)
127
+
128
+ 今回の場合、数値を比較して「小さい方_大きい方」という部分がありますが、この部分は`np.sort()`を使うって行ごとに「小さい→大きい」順に並べ替えした配列を作るのが簡便です。
129
+ つまり、
130
+
131
+ ```python
132
+ In [5]: arr = np.sort(df[['LTeamID', 'WTeamID']].to_numpy())
133
+ 2 arr
134
+ Out[5]:
135
+ array([[1214, 1264],
136
+ [1140, 1279],
137
+ [1129, 1173],
138
+ [1316, 1352],
139
+ [1112, 1411],
140
+ ... ...
141
+ [1181, 1211],
142
+ [1257, 1277],
143
+ [1181, 1277],
144
+ [1246, 1458],
145
+ [1181, 1458]], dtype=int64)
146
+
147
+ In [6]: df['Season'].astype(str).str.cat(arr.astype(str), '_')
148
+ Out[6]:
149
+ 1916 2015_1214_1264
150
+ 1917 2015_1140_1279
151
+ 1918 2015_1129_1173
152
+ 1919 2015_1316_1352
153
+ 1920 2015_1112_1411
154
+ ... ...
155
+ 1978 2015_1181_1211
156
+ 1979 2015_1257_1277
157
+ 1980 2015_1181_1277
158
+ 1981 2015_1246_1458
159
+ 1982 2015_1181_1458
160
+ Name: Season, dtype: object
161
+ ```
162
+
163
+ ## 解説(その3)
164
+
165
+ pandasの`str`関連メソッドは実際にはとても動作が遅いです。標準のリストになおしてforループした方が速い場合があります。
166
+
167
+ ```python
168
+ In [11]: arr_s = df['Season'].tolist()
169
+ 2 arr_lw = np.sort(df[['LTeamID', 'WTeamID']].to_numpy()).tolist()
170
+ 3 id_list = [f'{s}_{lw[0]}_{lw[1]}' for s, lw in zip(arr_s, arr_lw)]
171
+ 4 id_list
172
+ Out[11]:
173
+ ['2015_1214_1264',
174
+ '2015_1140_1279',
175
+ '2015_1129_1173',
176
+ '2015_1316_1352',
177
+ '2015_1112_1411',
178
+ '2015_1181_1211',
179
+ '2015_1257_1277',
180
+ '2015_1181_1277',
181
+ '2015_1246_1458',
182
+ '2015_1181_1458']
183
+
184
+ In [12]: pd.Series(id_list, index=df.index)
185
+ Out[12]:
186
+ 1916 2015_1214_1264
187
+ 1917 2015_1140_1279
188
+ 1918 2015_1129_1173
189
+ 1919 2015_1316_1352
190
+ 1920 2015_1112_1411
191
+ 1978 2015_1181_1211
192
+ 1979 2015_1257_1277
193
+ 1980 2015_1181_1277
194
+ 1981 2015_1246_1458
195
+ 1982 2015_1181_1458
196
+ dtype: object
197
+ ```
198
+
199
+ ## 処理速度の比較
200
+
201
+ ![処理速度の比較](5661b66313ff2c73cf29f9e52b76e9e4.png)
202
+
203
+ その3(リストを使う方法)が最も速いようです。@can110氏の方法(`df.apply`を使った方法)はデータ数が少ないときは次いで速いですが、行数が増えるとかなり遅くなります。