Google+ Followers

2017年9月19日 星期二

[Python] 機器學習筆記 - 使用 Pandas 處理 CSV 格式、過濾資料與自身 Index 更新問題

使用 Pandas 套件進行分析資料時,它提供的功能包括便利的資料過濾:

import seaborn as sns
import pandas as pd

dataset = sns.load_dataset("tips")
print(dataset)
print(dataset.shape)
print(dataset.columns)

print("list total_bill > 30:")
print(dataset[ dataset['total_bill'] > 30 ] )


然而,預設 Pandas 會記錄原先的 raw index ,這也有不錯的功用,但有時希望照新的架構顯示,需要再多用 reset_index():

print("list total_bill > 30 and tip < 4:")
print(dataset[ (dataset['total_bill'] > 30) & (dataset['tip'] < 4) ] )

print("rebuild index:")
dataset = dataset[ (dataset['total_bill'] > 30) & (dataset['tip'] < 4) ]
dataset = dataset.reset_index()
print(dataset)


連續動作:

$ python pandas_study.py
     total_bill   tip     sex smoker   day    time  size
0         16.99  1.01  Female     No   Sun  Dinner     2
1         10.34  1.66    Male     No   Sun  Dinner     3
2         21.01  3.50    Male     No   Sun  Dinner     3
3         23.68  3.31    Male     No   Sun  Dinner     2
4         24.59  3.61  Female     No   Sun  Dinner     4
5         25.29  4.71    Male     No   Sun  Dinner     4
6          8.77  2.00    Male     No   Sun  Dinner     2
7         26.88  3.12    Male     No   Sun  Dinner     4
8         15.04  1.96    Male     No   Sun  Dinner     2
9         14.78  3.23    Male     No   Sun  Dinner     2
10        10.27  1.71    Male     No   Sun  Dinner     2
11        35.26  5.00  Female     No   Sun  Dinner     4
12        15.42  1.57    Male     No   Sun  Dinner     2
13        18.43  3.00    Male     No   Sun  Dinner     4
14        14.83  3.02  Female     No   Sun  Dinner     2
15        21.58  3.92    Male     No   Sun  Dinner     2
16        10.33  1.67  Female     No   Sun  Dinner     3
17        16.29  3.71    Male     No   Sun  Dinner     3
18        16.97  3.50  Female     No   Sun  Dinner     3
19        20.65  3.35    Male     No   Sat  Dinner     3
20        17.92  4.08    Male     No   Sat  Dinner     2
21        20.29  2.75  Female     No   Sat  Dinner     2
22        15.77  2.23  Female     No   Sat  Dinner     2
23        39.42  7.58    Male     No   Sat  Dinner     4
24        19.82  3.18    Male     No   Sat  Dinner     2
25        17.81  2.34    Male     No   Sat  Dinner     4
26        13.37  2.00    Male     No   Sat  Dinner     2
27        12.69  2.00    Male     No   Sat  Dinner     2
28        21.70  4.30    Male     No   Sat  Dinner     2
29        19.65  3.00  Female     No   Sat  Dinner     2
..          ...   ...     ...    ...   ...     ...   ...
214       28.17  6.50  Female    Yes   Sat  Dinner     3
215       12.90  1.10  Female    Yes   Sat  Dinner     2
216       28.15  3.00    Male    Yes   Sat  Dinner     5
217       11.59  1.50    Male    Yes   Sat  Dinner     2
218        7.74  1.44    Male    Yes   Sat  Dinner     2
219       30.14  3.09  Female    Yes   Sat  Dinner     4
220       12.16  2.20    Male    Yes   Fri   Lunch     2
221       13.42  3.48  Female    Yes   Fri   Lunch     2
222        8.58  1.92    Male    Yes   Fri   Lunch     1
223       15.98  3.00  Female     No   Fri   Lunch     3
224       13.42  1.58    Male    Yes   Fri   Lunch     2
225       16.27  2.50  Female    Yes   Fri   Lunch     2
226       10.09  2.00  Female    Yes   Fri   Lunch     2
227       20.45  3.00    Male     No   Sat  Dinner     4
228       13.28  2.72    Male     No   Sat  Dinner     2
229       22.12  2.88  Female    Yes   Sat  Dinner     2
230       24.01  2.00    Male    Yes   Sat  Dinner     4
231       15.69  3.00    Male    Yes   Sat  Dinner     3
232       11.61  3.39    Male     No   Sat  Dinner     2
233       10.77  1.47    Male     No   Sat  Dinner     2
234       15.53  3.00    Male    Yes   Sat  Dinner     2
235       10.07  1.25    Male     No   Sat  Dinner     2
236       12.60  1.00    Male    Yes   Sat  Dinner     2
237       32.83  1.17    Male    Yes   Sat  Dinner     2
238       35.83  4.67  Female     No   Sat  Dinner     3
239       29.03  5.92    Male     No   Sat  Dinner     3
240       27.18  2.00  Female    Yes   Sat  Dinner     2
241       22.67  2.00    Male    Yes   Sat  Dinner     2
242       17.82  1.75    Male     No   Sat  Dinner     2
243       18.78  3.00  Female     No  Thur  Dinner     2

[244 rows x 7 columns]
(244, 7)
Index(['total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size'], dtype='object')
list total_bill > 30:
     total_bill    tip     sex smoker   day    time  size
11        35.26   5.00  Female     No   Sun  Dinner     4
23        39.42   7.58    Male     No   Sat  Dinner     4
39        31.27   5.00    Male     No   Sat  Dinner     3
44        30.40   5.60    Male     No   Sun  Dinner     4
47        32.40   6.00    Male     No   Sun  Dinner     4
52        34.81   5.20  Female     No   Sun  Dinner     4
56        38.01   3.00    Male    Yes   Sat  Dinner     4
59        48.27   6.73    Male     No   Sat  Dinner     4
83        32.68   5.00    Male    Yes  Thur   Lunch     2
85        34.83   5.17  Female     No  Thur   Lunch     4
95        40.17   4.73    Male    Yes   Fri  Dinner     4
102       44.30   2.50  Female    Yes   Sat  Dinner     3
112       38.07   4.00    Male     No   Sun  Dinner     3
141       34.30   6.70    Male     No  Thur   Lunch     6
142       41.19   5.00    Male     No  Thur   Lunch     5
156       48.17   5.00    Male     No   Sun  Dinner     6
167       31.71   4.50    Male     No   Sun  Dinner     4
170       50.81  10.00    Male    Yes   Sat  Dinner     3
173       31.85   3.18    Male    Yes   Sun  Dinner     2
175       32.90   3.11    Male    Yes   Sun  Dinner     2
179       34.63   3.55    Male    Yes   Sun  Dinner     2
180       34.65   3.68    Male    Yes   Sun  Dinner     4
182       45.35   3.50    Male    Yes   Sun  Dinner     3
184       40.55   3.00    Male    Yes   Sun  Dinner     2
187       30.46   2.00    Male    Yes   Sun  Dinner     5
197       43.11   5.00  Female    Yes  Thur   Lunch     4
207       38.73   3.00    Male    Yes   Sat  Dinner     4
210       30.06   2.00    Male    Yes   Sat  Dinner     3
212       48.33   9.00    Male     No   Sat  Dinner     4
219       30.14   3.09  Female    Yes   Sat  Dinner     4
237       32.83   1.17    Male    Yes   Sat  Dinner     2
238       35.83   4.67  Female     No   Sat  Dinner     3
list total_bill > 30 and tip < 4:
print index:
index: 56
index: 102
index: 173
index: 175
index: 179
index: 180
index: 182
index: 184
index: 187
index: 207
index: 210
index: 219
index: 237
rebuild index:
    index  total_bill   tip     sex smoker  day    time  size
0      56       38.01  3.00    Male    Yes  Sat  Dinner     4
1     102       44.30  2.50  Female    Yes  Sat  Dinner     3
2     173       31.85  3.18    Male    Yes  Sun  Dinner     2
3     175       32.90  3.11    Male    Yes  Sun  Dinner     2
4     179       34.63  3.55    Male    Yes  Sun  Dinner     2
5     180       34.65  3.68    Male    Yes  Sun  Dinner     4
6     182       45.35  3.50    Male    Yes  Sun  Dinner     3
7     184       40.55  3.00    Male    Yes  Sun  Dinner     2
8     187       30.46  2.00    Male    Yes  Sun  Dinner     5
9     207       38.73  3.00    Male    Yes  Sat  Dinner     4
10    210       30.06  2.00    Male    Yes  Sat  Dinner     3
11    219       30.14  3.09  Female    Yes  Sat  Dinner     4
12    237       32.83  1.17    Male    Yes  Sat  Dinner     2
print index:
index: 0
index: 1
index: 2
index: 3
index: 4
index: 5
index: 6
index: 7
index: 8
index: 9
index: 10
index: 11
index: 12

2017年9月15日 星期五

[Python] 機器學習筆記 - 使用 準確率/召回率 (Precision-Recall) 評估分析成果

研究所時,算是第一次接觸這名詞,老闆的研究領域是 Search Engines ,用來評估索引成果好不好。最近則打算用在機器學習的成果分析,卻想不起當時老闆用來解釋索引成果的案例,還是容易忘記 XD 網路上打滾一下,發現這篇寫的廣告投放實際案例很好懂,也不容易忘,建議可以逛一下:準確率(Precision)與召回率(Recall)

回到本文,單純紀錄如何用既有函式庫計算:

import numpy as np
from sklearn.metrics import average_precision_score, precision_score, recall_score

# Classification metrics can't handle a mix of binary and continuous targets
#y = np.array([0, 0, 1, 1])
#scores = np.array([0.1, 0.3, 0.2, 0.8])

y = [0, 0, 1, 1]
scores = [0, 1, 1, 1]

#print(precision_score(y, scores, average='macro'))
#print(recall_score(y, scores, average='macro'))
#print(average_precision_score(y, scores))
#import sys
#sys.exit(0)

print('precision: %0.2f, recall: %0.2f, score: %0.2f' % (
        precision_score(y, scores, average='macro'),
        recall_score(y, scores, average='macro'),
        average_precision_score(y, scores)
))


成果:

precision: 0.83, recall: 0.75, score: 0.67

需要更詳細的範例,請參考:http://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html

[Python] 機器學習筆記 - 使用 ROC 曲線 (receiver operating characteristic curve) 評估分析成果

roc curve

最近回想起兩年前走跳過的一場黑客松,當年的題目恰好是一個屬性的分類,就是一篇文章屬性給你,請告訴我它是不是 spam!所幸網路上還可以看到其他人的作品,逛了一下也順便研究別人的報告怎麼寫,其中有一組使用了 ROC 曲線來回報自己的分析成果,就來多多認識一下。

而 ROC 曲線是什麼?其實在 WIKI 或是 scikit-learn 文件(也引用WIKI資料)有很明確地解釋:
簡單的說,當畫出此圖後,若一開始就達左上角是最完美的,若一開始分析結果是斜線上方是好的,反之下方是差的。接下來,則是會去計算曲線下方的面積,產生一個介於 0~1 的數值,只要等於 0.5 就是跟隨機猜測一樣,代表此分析模型沒有預測價值;若大於 0.5 代表猜測是正向的,而小於 0.5 代表猜測的方向恰好相反;而 1 或 0 代表全部辨識正確或全部辨識錯誤。

因此,只需設法把模型預測結果畫一下 ROC 曲線,在算出個面積,就收工啦!

範例請參考 http://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html ,在此只筆記畫圖的部分:

import numpy as np
from sklearn.metrics import roc_curve, auc
y = np.array([0, 0, 1, 1])
scores = np.array([0.1, 0.4, 0.35, 0.8])
fpr, tpr, _ = roc_curve(y, scores)
roc_auc = auc(fpr, tpr)

import matplotlib as mpl
#mpl.use('Agg')
import matplotlib.pyplot as plt

fig = plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange', lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
#fig.savefig('/tmp/roc.png')
plt.show()

2017年9月14日 星期四

[MySQL] 從 JSON 抽取資料建立虛擬欄位 @ MySQL 5.7

同事反映 query 很慢,除了改進 SQL 語法外,也小試身手,對 JSON 資料抽出來建立虛擬欄位跟索引,順便筆記一下。

CREATE TABLE `my_data` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `data` text,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


這邊 data column 是 text 型態,主因是這 DB server 從 5.6 升上來的 XD 且當初讓 data 有很多彈性,不一定是 json 格式。

但,要抽取成虛擬欄位時,建議要保持 data 是 json 格式,就先整理一下資料:

mysql> UPDATE my_data SET data = '{}' WHERE data IS NULL OR data = ''

假想 data 的數值為 {"keyword":"value"},因此抽出 keyword 虛擬欄位來用:

mysql> ALTER TABLE my_data ADD keyword VARCHAR(64) AS (JSON_UNQUOTE(data->>"$. keyword"));
mysql> ALTER TABLE my_data ADD INDEX (keyword);


如此一來,可以改對 keyword 欄位查詢了,可以再加快一點,而 table 狀態更新為:

CREATE TABLE `my_data ` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `data` text,
  `keyword` varchar(64) GENERATED ALWAYS AS (json_unquote(json_unquote(json_extract(`data`,'$. keyword')))) VIRTUAL,
  PRIMARY KEY (`id`),
  KEY `keyword ` (`keyword `),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2017年8月31日 星期四

[Python] 機器學習筆記 - sklearn.preprocessing 之 LabelEncoder, OneHotEncoder

最近挑一些資料來練習分析,想要用矩陣乘法,第一個念頭就是用 Hash table 把 keyword 轉成數值,接著要符合ㄧ些數學式子,又把數值擴展成 nx1 維,直到強者大大推坑看一些文件,我才發現這種招數很常使用,都有 library/framework 可以直接套用,順便把之前隨手寫的程式架構整理一下

先說一下 Hash table 的用法,就單純掃過所有數值,對所有數值建立查表方式,可以掃過一輪資料時,順便把標記都處理完畢:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

dataset = sns.load_dataset("tips")
print(dataset)
print(dataset.shape)
print(dataset.columns)
# Index(['total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size'], dtype='object')

dataset_formated = None

# 土炮模式
fields_lookup = {}

print(dataset.columns)
for index, row in dataset.iterrows():
row_formated = np.empty([])

#for fieldname in dataset.columns:
for fieldname in [ 'day', 'smoker', 'time', 'sex', 'size' ]:
#print(field)

field_value = None
if fieldname not in fields_lookup:
fields_lookup[fieldname] = {}
if row[fieldname] not in fields_lookup[fieldname]:
fields_lookup[fieldname][ row[fieldname] ] = len(fields_lookup[fieldname])

# field value from hash table
field_data = np.zeros(1, dtype=np.int)
field_data[0] = fields_lookup[fieldname][ row[fieldname] ]

# handle row
row_formated = np.append( row_formated, field_data.reshape(1, -1) )

# handle data
if dataset_formated is None:
dataset_formated = np.zeros([ dataset.shape[0], row_formated.reshape(1, -1).size ], dtype=np.int)
dataset_formated[index] = row_formated.reshape(1, -1)
#print(row_formated)
#print(row_formated.reshape(1, -1))

print(fields_lookup)
print(dataset_formated)


如此一來就完成編碼,也完成資料格式轉換:

{'day': {'Sun': 0, 'Sat': 1, 'Thur': 2, 'Fri': 3}, 'smoker': {'No': 0, 'Yes': 1}, 'time': {'Dinner': 0, 'Lunch': 1}, 'sex': {'Female': 0, 'Male': 1}, 'size': {2: 0, 3: 1, 4: 2, 1: 3, 6: 4, 5: 5}}

然而,對於部分演算法可能拿編碼的整數進行運算,或是想要更精準把整數擴展成選擇結果,那解法就是擴展欄位,例如有 5 種結果,就擴展成 5 個欄位,選到的標 1 ,沒選到標 0,土炮處理方式就麻煩了點,需要先掃一次建立 hash table,接著第二次在重建數據:

# build hash table only
for index, row in dataset.iterrows():
#for fieldname in dataset.columns:
for fieldname in [ 'day', 'smoker', 'time', 'sex', 'size' ]:
#print(field)
if fieldname not in fields_lookup:
fields_lookup[fieldname] = {}
if row[fieldname] not in fields_lookup[fieldname]:
fields_lookup[fieldname][ row[fieldname] ] = len(fields_lookup[fieldname])

print(fields_lookup)

# build new matrix
for index, row in dataset.iterrows():
row_formated = np.empty([])

for fieldname in [ 'day', 'smoker', 'time', 'sex', 'size' ]:
# field value from hash table
field_data = np.zeros([len(fields_lookup[fieldname]), 1], dtype=np.int)
field_data[ fields_lookup[fieldname][row[fieldname]] ][0] = 1

# handle row
row_formated = np.append( row_formated, field_data.reshape(1, -1) )

#print(row_formated)

# handle data
if dataset_formated is None:
dataset_formated = np.zeros([ dataset.shape[0], row_formated.reshape(1, -1).size ], dtype=np.int)
dataset_formated[index] = row_formated.reshape(1, -1)
#print(row_formated)
#print(row_formated.reshape(1, -1))

print(dataset_formated)


回到常用的方式 - LabelEncoder:

from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder

dataset_encode = dataset.copy()
labels = {}

for i, field in enumerate(dataset.columns):
if field == 'tip' or field == 'total_bill':
continue
labels[field] = list(set(dataset[field].unique()))
label_encoder = LabelEncoder()
label_encoder.fit(labels[field])

# original
#print(dataset_encode.iloc[:,i])
#print(dataset_encode[field])

# encode
#feature = label_encoder.transform(dataset_encode.iloc[:,i])
#feature = feature.reshape(dataset.shape[0], 1)
# https://stackoverflow.com/questions/24458645/label-encoding-across-multiple-columns-in-scikit-learn
dataset_encode[field] = label_encoder.fit_transform(dataset_encode[field])

#print(dataset_encode[field])

print(dataset_encode)


輸出:

     total_bill   tip  sex  smoker  day  time  size
0         16.99  1.01    0       0    2     0     1
1         10.34  1.66    1       0    2     0     2
2         21.01  3.50    1       0    2     0     2
3         23.68  3.31    1       0    2     0     1
4         24.59  3.61    0       0    2     0     3
5         25.29  4.71    1       0    2     0     3
6          8.77  2.00    1       0    2     0     1
7         26.88  3.12    1       0    2     0     3
8         15.04  1.96    1       0    2     0     1
9         14.78  3.23    1       0    2     0     1
10        10.27  1.71    1       0    2     0     1
11        35.26  5.00    0       0    2     0     3
12        15.42  1.57    1       0    2     0     1
13        18.43  3.00    1       0    2     0     3
14        14.83  3.02    0       0    2     0     1
15        21.58  3.92    1       0    2     0     1
16        10.33  1.67    0       0    2     0     2
17        16.29  3.71    1       0    2     0     2
18        16.97  3.50    0       0    2     0     2
19        20.65  3.35    1       0    1     0     2
20        17.92  4.08    1       0    1     0     1
21        20.29  2.75    0       0    1     0     1
22        15.77  2.23    0       0    1     0     1
23        39.42  7.58    1       0    1     0     3
24        19.82  3.18    1       0    1     0     1
25        17.81  2.34    1       0    1     0     3
26        13.37  2.00    1       0    1     0     1
27        12.69  2.00    1       0    1     0     1
28        21.70  4.30    1       0    1     0     1
29        19.65  3.00    0       0    1     0     1
..          ...   ...  ...     ...  ...   ...   ...
214       28.17  6.50    0       1    1     0     2
215       12.90  1.10    0       1    1     0     1
216       28.15  3.00    1       1    1     0     4
217       11.59  1.50    1       1    1     0     1
218        7.74  1.44    1       1    1     0     1
219       30.14  3.09    0       1    1     0     3
220       12.16  2.20    1       1    0     1     1
221       13.42  3.48    0       1    0     1     1
222        8.58  1.92    1       1    0     1     0
223       15.98  3.00    0       0    0     1     2
224       13.42  1.58    1       1    0     1     1
225       16.27  2.50    0       1    0     1     1
226       10.09  2.00    0       1    0     1     1
227       20.45  3.00    1       0    1     0     3
228       13.28  2.72    1       0    1     0     1
229       22.12  2.88    0       1    1     0     1
230       24.01  2.00    1       1    1     0     3
231       15.69  3.00    1       1    1     0     2
232       11.61  3.39    1       0    1     0     1
233       10.77  1.47    1       0    1     0     1
234       15.53  3.00    1       1    1     0     1
235       10.07  1.25    1       0    1     0     1
236       12.60  1.00    1       1    1     0     1
237       32.83  1.17    1       1    1     0     1
238       35.83  4.67    0       0    1     0     2
239       29.03  5.92    1       0    1     0     2
240       27.18  2.00    0       1    1     0     1
241       22.67  2.00    1       1    1     0     1
242       17.82  1.75    1       0    1     0     1
243       18.78  3.00    0       0    3     0     1

[244 rows x 7 columns]


若想保留之前的欄位,也可用添加新欄位的方式:

dataset_encode[field+"-encode"] = label_encoder.fit_transform(dataset_encode[field])

而 OneHotEncoder 則是因為產出的維度會變大,要再設法把新產出來的數值再添加回去:

from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder

dataset_encode = dataset.copy()
labels = {}

for i, field in enumerate(dataset.columns):
if field == 'tip' or field == 'total_bill':
continue

# original
#print(dataset_encode.iloc[:,i])
#print(dataset_encode[field])

# LabelEncode
labels[field] = list(set(dataset[field].unique()))
label_encoder = LabelEncoder()
label_encoder.fit(labels[field])

# https://stackoverflow.com/questions/24458645/label-encoding-across-multiple-columns-in-scikit-learn
dataset_encode[field+"-LabelEncode"] = label_encoder.fit_transform(dataset_encode[field])
#dataset_encode[field] = label_encoder.fit_transform(dataset_encode[field])

# OneHotEncode
feature = label_encoder.transform(dataset_encode[field])
feature = feature.reshape(dataset.shape[0], 1)
# http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
onehot_encoder = OneHotEncoder(sparse=False,n_values=len(labels[field]))
onehot_result = onehot_encoder.fit_transform(feature)
#dataset_encode[field+"-OneHotEncode"] = onehot_encoder.fit_transform(feature)
#onehot_encoder[ ["A","B"] ] = onehot_result

for index in range(len(labels[field])):
dataset_encode[field+"-OneHotEncode-"+str(index)] = onehot_result[:,index]

#print(dataset_encode[field])

print(dataset_encode.head(5))


如此一來,結果會是這樣:

   total_bill   tip     sex smoker  day    time  size  sex-LabelEncode  \
0       16.99  1.01  Female     No  Sun  Dinner     2                0
1       10.34  1.66    Male     No  Sun  Dinner     3                1
2       21.01  3.50    Male     No  Sun  Dinner     3                1
3       23.68  3.31    Male     No  Sun  Dinner     2                1
4       24.59  3.61  Female     No  Sun  Dinner     4                0

   sex-OneHotEncode-0  sex-OneHotEncode-1         ...           \
0                 1.0                 0.0         ...          
1                 0.0                 1.0         ...          
2                 0.0                 1.0         ...          
3                 0.0                 1.0         ...          
4                 1.0                 0.0         ...          

   time-LabelEncode  time-OneHotEncode-0  time-OneHotEncode-1  \
0                 0                  1.0                  0.0
1                 0                  1.0                  0.0
2                 0                  1.0                  0.0
3                 0                  1.0                  0.0
4                 0                  1.0                  0.0

   size-LabelEncode  size-OneHotEncode-0  size-OneHotEncode-1  \
0                 1                  0.0                  1.0
1                 2                  0.0                  0.0
2                 2                  0.0                  0.0
3                 1                  0.0                  1.0
4                 3                  0.0                  0.0

   size-OneHotEncode-2  size-OneHotEncode-3  size-OneHotEncode-4  \
0                  0.0                  0.0                  0.0
1                  1.0                  0.0                  0.0
2                  1.0                  0.0                  0.0
3                  0.0                  0.0                  0.0
4                  0.0                  1.0                  0.0

   size-OneHotEncode-5
0                  0.0
1                  0.0
2                  0.0
3                  0.0
4                  0.0