Kaggle competition: AI for Clinical Data Analytics HW2
<SOS> metric: dice Kaggle data source: ai-for-clinical-data-analytics-hw2<load_from_csv>
%matplotlib inline
df_train = pd.read_csv('.. /input/house-prices-advanced-regression-techniques/train.csv')
 df_test = pd.read_csv('.. /input/house-prices-advanced-regression-techniques/test.csv' )<drop_column>
train_image_folder = ".. /input/train-images/image/"
train_label_folder = ".. /input/train-labels/label/"
test_image_folder = ".. /input/test-images/image/"
train_list = os.listdir(train_image_folder)
 if 'hmvsa0loxh3ek2y8rzmcyb6zrrh9mwyp' in train_list:
train_list.remove('hmvsa0loxh3ek2y8rzmcyb6zrrh9mwyp')
 print('Train data:', len(train_list))
df_train = df_train.drop(df_train[(df_train.SalePrice >= 700000)].index)
 df_train = df_train.drop(df_train[(df_train.LotFrontage >= 200)].index)
 df_train = df_train.drop(df_train[(df_train.LotArea >= 100000)].index)
 df_train = df_train.drop(df_train[(df_train.OverallQual == 4)&(df_train.SalePrice > 200000)].index)
 df_train = df_train.drop(df_train[(df_train.OverallQual == 8)&(df_train.SalePrice > 500000)].index)
 df_train = df_train.drop(df_train[(df_train.OverallQual == 10)&(df_train.SalePrice < 300000)].index)
 df_train = df_train.drop(df_train[(df_train.OverallCond == 2)&(df_train.SalePrice > 300000)].index)
 df_train = df_train.drop(df_train[(df_train.OverallCond == 5)&(df_train.SalePrice > 700000)].index)
 df_train = df_train.drop(df_train[(df_train.OverallCond == 6)&(df_train.SalePrice > 700000)].index)
 df_train = df_train.drop(df_train[(df_train.YearBuilt <= 1900)&(df_train.SalePrice > 200000)].index)
 df_train = df_train.drop(df_train[(df_train.MasVnrArea >= 1200)].index)
 df_train = df_train.drop(df_train[(df_train.BsmtFinSF1 >= 3000)].index)
 df_train = df_train.drop(df_train[(df_train.BsmtFinSF2 >= 1200)].index)
 df_train = df_train.drop(df_train[(df_train.TotalBsmtSF >= 4000)].index)
 df_train = df_train.drop(df_train[(df_train['1stFlrSF'] >= 4000)].index)
 df_train = df_train.drop(df_train[(df_train.LowQualFinSF > 500)&(df_train.SalePrice > 400000)].index)
 df_train = df_train.drop(df_train[(df_train.GrLivArea >= 4000)].index)
 df_train = df_train.drop(df_train[(df_train.BedroomAbvGr >= 7)].index)
 df_train = df_train.drop(df_train[(df_train.KitchenAbvGr < 1)].index)
 df_train = df_train.drop(df_train[(df_train.TotRmsAbvGrd > 12)].index)
 df_train = df_train.drop(df_train[(df_train.Fireplaces > 2)].index)
 df_train = df_train.drop(df_train[(df_train.GarageCars > 3)].index)
 df_train = df_train.drop(df_train[(df_train.GarageArea > 1200)&(df_train.SalePrice < 300000)].index)
 df_train = df_train.drop(df_train[(df_train.WoodDeckSF > 700)].index)
 df_train = df_train.drop(df_train[(df_train.OpenPorchSF > 450)].index)
 df_train = df_train.drop(df_train[(df_train.EnclosedPorch > 450)].index)
 df_train = df_train.drop(df_train[(df_train['3SsnPorch'] > 350)].index )<string_transform>
def load_dicom_volume(src_dir, suffix='*.dcm'):

 encode_name = src_dir.split('/')[-1]
dicom_scans = [dicom.read_file(sp)\
for sp in glob.glob(os.path.join(src_dir, suffix)) ]
dicom_scans.sort(key=lambda s: float(s[(0x0020, 0x0032)][2]))
volume_image = np.stack([ds.pixel_array \
for ds in dicom_scans] ).astype(np.int16)
 return encode_name, volume_image
def load_label(label_fpath, transpose=False):
encode_name = label_fpath[-39: -7]
label_data = nib.load(label_fpath)
 label_array = label_data.get_fdata()
if transpose:
label_array = np.transpose(label_array, axes=(2, 1, 0))
return encode_name, label_array
full = pd.concat([df_train, df_test], ignore_index = True)
 full.drop(['SalePrice'], axis=1, inplace=True)
 words_set = set()
for data in full['MiscFeature']:
if not pd.isnull(data):
for word in data.split(' '):
words_set.add(word)
 for feature in words_set:
count = 0
for data in full['MiscFeature']:
if not pd.isnull(data):
if feature in data:
count += 1
print("Category {}: {} samples".format(feature, count))<drop_column>
for encode in tqdm.tqdm(train_list):
_, volume_image = load_dicom_volume(os.path.join(train_image_folder, encode))
npz_folder = os.path.join(train_image_npz_folder, encode)
 if not os.path.exists(npz_folder):
os.mkdir(npz_folder)
 num_slice = volume_image.shape[0]
for _z in range(0, num_slice):
npz_path = os.path.join(npz_folder, "%03d.npz"%(_z))
np.savez_compressed(npz_path, image=volume_image[_z])
 del volume_image
def add_columns(dataframe):
add_categorical = ['Othr', 'TenC', 'Gar2', 'Shed']
for column in add_categorical:
data = dataframe['MiscVal'][dataframe['MiscFeature'] == column]
dataframe[column] = pd.Series(data, index = dataframe.index ).fillna(value=0)
 dataframe.drop(columns = ['MiscFeature'], inplace = True)
 dataframe.drop(columns = ['MiscVal'], inplace = True)
 add_columns(full)
 print("Full data shape is {}".format(full.shape))<define_variables>
for encode in tqdm.tqdm(train_list):
_, label_array = load_label(os.path.join(train_label_folder, encode + '.nii.gz'), transpose=True)
 npz_folder = os.path.join(train_label_npz_folder, encode)
 if not os.path.exists(npz_folder):
os.mkdir(npz_folder)
 num_slice = label_array.shape[0]
for _z in range(0, num_slice):
npz_path = os.path.join(npz_folder, "%03d.npz"%(_z))
np.savez_compressed(npz_path, label=label_array[_z])
 del label_array
categorical_features = [
'Alley',
'BldgType',
'BsmtCond',
'BsmtExposure',
'BsmtFinType1',
'BsmtFinType2',
'BsmtQual',
'CentralAir',
'Condition1',
'Condition2',
'Electrical',
'ExterCond',
'Exterior1st',
'Exterior2nd',
'ExterQual',
'Fence',
'FireplaceQu',
'Foundation',
'Functional',
'GarageCond',
'GarageFinish',
'GarageQual',
'GarageType',
'Heating',
'HeatingQC',
'HouseStyle',
'KitchenQual',
'LandContour',
'LandSlope',
'LotConfig',
'LotShape',
'MasVnrType',
'MSZoning',
'Neighborhood',
'PavedDrive',
'PoolQC',
'RoofMatl',
'RoofStyle',
'SaleCondition',
'SaleType',
'Street',
'Utilities'
]
numerical_features = [
'1stFlrSF',
'2ndFlrSF',
'3SsnPorch',
'BsmtFinSF1',
'BsmtFinSF2',
'BsmtFullBath',
'BsmtHalfBath',
'BsmtUnfSF',
'EnclosedPorch',
'Fireplaces',
'FullBath',
'GarageArea',
'GarageCars',
'GarageYrBlt',
'GrLivArea',
'HalfBath',
'LotArea',
'LotFrontage',
'LowQualFinSF',
'MasVnrArea',
'MoSold',
'MSSubClass',
'OpenPorchSF',
'OverallCond',
'OverallQual',
'PoolArea',
'ScreenPorch',
'TotalBsmtSF',
'TotRmsAbvGrd',
'WoodDeckSF',
'YearBuilt',
'YearRemodAdd',
'YrSold',
'BedroomAbvGr',
'KitchenAbvGr',
'Othr',
'TenC',
'Gar2',
'Shed'
]<feature_engineering>
K.tensorflow_backend._get_available_gpus()
def createAgeFeatures(dataframe):
dataframe['GarageAge'] = dataframe['GarageYrBlt'].apply(lambda x: 2019 - x)
 dataframe['RemodelAge'] = dataframe['YearRemodAdd'].apply(lambda x: 2019 - x)
 dataframe['HouseAge'] = dataframe['YearBuilt'].apply(lambda x: 2019 - x)
 def createPoolFeature(dataframe):
dataframe['Pool'] = dataframe['PoolArea'].apply(lambda x: x != 0 ).map({True: 1, False: 0})
 def handleNumericalFeatures(dataframe):
createAgeFeatures(dataframe)
 createPoolFeature(dataframe)
 handleNumericalFeatures(full)
 print("Full data shape is {}".format(full.shape))<categorify>
map_image_list = sorted(glob.glob(os.path.join(train_image_npz_folder, '*/*.npz')))
 map_label_list = sorted(glob.glob(os.path.join(train_label_npz_folder, '*/*.npz')))
 map_df = pd.DataFrame(data={'image': map_image_list, 'label': map_label_list})
 map_df.head()
def mapSimpleMapping(dataframe):
dataframe['ExterCond'] = dataframe['ExterCond'].map({
'Ex' : 2,
'Gd' : 1,
'TA' : 0,
'Fa' : -1,
'Po' : -2
})
 dataframe['ExterQual'] = dataframe['ExterQual'].map({
'Ex' : 2,
'Gd' : 1,
'TA' : 0,
'Fa' : -1,
'Po' : -2
})
 dataframe['HeatingQC'] = dataframe['HeatingQC'].map({
'Ex' : 2,
'Gd' : 1,
'TA' : 0,
'Fa' : -1,
'Po' : -2
})
 dataframe['KitchenQual'] = dataframe['KitchenQual'].map({
'Ex' : 2,
'Gd' : 1,
'TA' : 0,
'Fa' : -1,
'Po' : -2
})
 dataframe['PavedDrive'] = dataframe['PavedDrive'].map({
'Y' : 1,
'P' : 0.5,
'N' : 0,
})
 dataframe['Street'] = dataframe['Street'].map({
'Grvl' : -1,
'Pave' : 1,
})
 def mapSimpleWithNan(dataframe):
dataframe['BsmtCond'] = dataframe['BsmtCond'].map({
'Ex' : 4,
'Gd' : 3,
'TA' : 2,
'Fa' : 1,
'Po' : 0,
'NA' : -1
} ).fillna(-1)
 dataframe['BsmtExposure'] = dataframe['BsmtExposure'].map({
'Gd' : 3,
'Av' : 2,
'Mn' : 1,
'No' : 0,
'NA' : -1
} ).fillna(-1)
 dataframe['BsmtQual'] = dataframe['BsmtQual'].map({
'Ex' : 4,
'Gd' : 3,
'TA' : 2,
'Fa' : 1,
'Po' : 0,
'NA' : -1
} ).fillna(-1)
 dataframe['FireplaceQu'] = dataframe['FireplaceQu'].map({
'Ex' : 4,
'Gd' : 3,
'TA' : 2,
'Fa' : 1,
'Po' : 0,
'NA' : -1
} ).fillna(-1)
 dataframe['GarageCond'] = dataframe['GarageCond'].map({
'Ex' : 4,
'Gd' : 3,
'TA' : 2,
'Fa' : 1,
'Po' : 0,
'NA' : -1
} ).fillna(-1)
 dataframe['GarageFinish'] = dataframe['GarageFinish'].map({
'Fin' : 2,
'RFn' : 1,
'Unf' : 0,
'NA' : -1
} ).fillna(-1)
 dataframe['GarageQual'] = dataframe['GarageQual'].map({
'Ex' : 4,
'Gd' : 3,
'TA' : 2,
'Fa' : 1,
'Po' : 0,
'NA' : -1
} ).fillna(-1)
 dataframe['PoolQC'] = dataframe['PoolQC'].map({
'Ex' : 3,
'Gd' : 2,
'TA' : 1,
'Fa' : 0,
'NA' : -1
} ).fillna(-1)
 def mapBoolean(dataframe):
dataframe['CentralAir'] = dataframe['CentralAir'].map({
'N' : 0,
'Y' : 1,
})
 def handleMappedCategorical(dataframe):
mapSimpleMapping(dataframe)
 mapSimpleWithNan(dataframe)
 mapBoolean(dataframe)
 handleMappedCategorical(full )<define_variables>
class LungSliceModelGenerator(kutils.Sequence):
'Generates data for Keras'
def __init__(self, mapping_df, batch_size, shuffle=True):
'Initialization'
self.mapping_df = mapping_df
self.data_num = mapping_df.shape[0]
self.batch_size = batch_size
self.shuffle = shuffle
self.on_epoch_end()
def __len__(self):
'Denotes the number of batches per epoch'
return int(np.floor(self.data_num / self.batch_size))
def __getitem__(self, index):
'Generate one batch of data'
batch_mapping_df = \
self.mapping_df.iloc[index*self.batch_size:(index+1)*self.batch_size]
X, y = self.__data_generation(batch_mapping_df)
 return X, y
def on_epoch_end(self):
'Updates indexes after each epoch'
if self.shuffle:
self.mapping_df = self.mapping_df.sample(frac=1 ).reset_index(drop=True)
 def __data_generation(self, batch_mapping_df):
'Generates data containing batch_size samples'
X = np.zeros(( self.batch_size, 512, 512, 1))
y = np.zeros(( self.batch_size, 512, 512, 1))
cnt = 0
for i, row in batch_mapping_df.iterrows() :
X[cnt, :, :, 0] = np.load(row['image'])['image']
y[cnt, :, :, 0] = np.load(row['label'])['label']
cnt += 1
return X, y
check_plot_features = [
'Alley',
'BldgType',
'BsmtFinType1',
'BsmtFinType2',
'Condition1',
'Condition2',
'Electrical',
'Exterior1st',
'Exterior2nd',
'Fence',
'Foundation',
'Functional',
'GarageType',
'Heating',
'HouseStyle',
'LandContour',
'LandSlope',
'LotConfig',
'LotShape',
'MasVnrType',
'MSZoning',
'RoofMatl',
'RoofStyle',
'SaleCondition',
'SaleType'
] 
<categorify>
batch_size = 16
slice_generator = LungSliceModelGenerator(map_df, batch_size=batch_size )
one_hots = ['BldgType', 'BsmtFinType1', 'BsmtFinType2', 'Condition1', 'Condition2', 'Exterior1st', 'Exterior2nd',
'Foundation', 'GarageType', 'Heating', 'HouseStyle', 'LandContour', 'LandSlope', 'LotConfig',
'MasVnrType', 'MSZoning', 'RoofMatl', 'RoofStyle', 'SaleCondition', 'SaleType']
def doOneHot(dataframe):
try:
for category in one_hots:
df = pd.Categorical(dataframe[category])
 dfDummies = pd.get_dummies(df, prefix = category)
 dataframe = pd.concat([dataframe, dfDummies], axis=1)
 if category not in ['Condition1', 'Condition2']:
dataframe.drop(columns = [category], inplace = True)
 return dataframe
except KeyError:
print("Oops! Category {} not found! Probably this has already been done...".format(category))
return dataframe
full = doOneHot(full)
 print("Full data shape is {}".format(full.shape))<categorify>
def _dice_coefficient(threshold = 0.3):
def hard_dice_coefficient(y_true, y_pred, smooth=1.0):
y_true_f = K.flatten(K.cast(y_true > threshold, dtype=float))
y_pred_f = K.flatten(K.cast(y_pred > threshold, dtype=float))
intersection = K.sum(y_true_f * y_pred_f)
 return(2.* intersection + smooth)/(K.sum(y_true_f)+ K.sum(y_pred_f)+ smooth)
 return hard_dice_coefficient
def dice_coefficient_loss(y_true, y_pred):
return 1 - _dice_coefficient()(y_true, y_pred )
def handleAlley(dataframe):
dataframe['Alley'] = dataframe['Alley'].map({'Grvl' : 0, 'Pave' : 1})
 def handleConditions(dataframe):
handler = {
'Normal' : 0,
'RRNn' : 1,
'RRNe' : 1,
'PosN' : 2,
'Artery' : 3,
'Feedr' : 3,
'RRAn' : 3,
'PosA' : 3,
'RRAe' : 3
}
dataframe['Condition1'] = dataframe['Condition1'].map(handler)
 dataframe['Condition2'] = dataframe['Condition2'].map(handler)
 def handleElectrical(dataframe):
handler = {'Mix' : 0, 'FuseP' : 1, 'FuseF' : 2, 'FuseA' : 3, 'SBrkr' : 4}
dataframe['Electrical'] = dataframe['Electrical'].map(handler)
 def handleFunctional(dataframe):
handler = {'Typ' : 0, 'Min1' : -1, 'Min2' : -2, 'Mod' : -3, 'Maj1' : -4, 'Maj2' : -5, 'Sev' : -6, 'Sal' : -7}
dataframe['Functional'] = dataframe['Functional'].map(handler)
 def handleLotShape(dataframe):
handler = {'Reg' : 0, 'IR1' : -1, 'IR2' : -2, 'IR3' : -3}
dataframe['LotShape'] = dataframe['LotShape'].map(handler)
 def handlePostOneHots(dataframe):
handleAlley(dataframe)
 handleConditions(dataframe)
 handleElectrical(dataframe)
 handleFunctional(dataframe)
 handleLotShape(dataframe)
 handlePostOneHots(full)
 print("Full data shape is {}".format(full.shape))<categorify>
def unet(pretrained_weights=None, input_size=[512, 512, 1], depth=3, init_filter=8,
filter_size=3, padding='same', pool_size=[2, 2], strides=[2, 2]):
inputs = klayers.Input(input_size)
 current_layer = inputs
encoding_layers = []
for d in range(depth + 1):
num_filters = init_filter * 2 ** d
conv = klayers.Conv2D(num_filters, filter_size, padding=padding, kernel_initializer='he_normal' )(current_layer)
 conv = klayers.BatchNormalization()(conv)
 conv = klayers.Activation('relu' )(conv)
 conv = klayers.Conv2D(num_filters * 2, filter_size, padding=padding, kernel_initializer='he_normal' )(conv)
 conv = klayers.BatchNormalization()(conv)
 conv = klayers.Activation('relu' )(conv)
 encoding_layers.append(conv)
 pool = klayers.MaxPooling2D(pool_size=pool_size )(conv)
 if d == depth:
current_layer = conv
else:
current_layer = pool
for d in range(depth, 0, -1):
num_filters = init_filter * 2 ** d
up = klayers.Deconvolution2D(num_filters * 2, pool_size, strides=strides )(current_layer)
 crop_layer = encoding_layers[d - 1]
up_shape = np.array(up._keras_shape[1:-1])
 conv_shape = np.array(crop_layer._keras_shape[1:-1])
 crop_left =(conv_shape - up_shape)// 2
crop_right =(conv_shape - up_shape)// 2 +(conv_shape - up_shape)% 2
crop_sizes = tuple(zip(crop_left, crop_right))
crop = klayers.Cropping2D(cropping=crop_sizes )(crop_layer)
 up = klayers.Concatenate(axis=-1 )([crop, up])
 conv = klayers.Conv2D(num_filters, filter_size, padding=padding, kernel_initializer='he_normal' )(up)
 conv = klayers.BatchNormalization()(conv)
 conv = klayers.Activation('relu' )(conv)
 conv = klayers.Conv2D(num_filters, filter_size, padding=padding, kernel_initializer='he_normal' )(conv)
 conv = klayers.BatchNormalization()(conv)
 conv = klayers.Activation('relu' )(conv)
 current_layer = conv
outputs = klayers.Conv2D(1, 1, padding=padding, kernel_initializer='he_normal' )(current_layer)
 outputs = klayers.Activation('sigmoid' )(outputs)
 model = Model(inputs=inputs, outputs=outputs)
 if(pretrained_weights):
model.load_weights(pretrained_weights)
 return model
def handleFence(dataframe):
dataframe['FencePrivacy'] = dataframe['Fence'].map({'MnPrv' : 0, 'GdPrv': 1} ).fillna(-1)
 dataframe['FenceWood'] = dataframe['Fence'].map({'MnWw' : 0, 'GdWo': 1} ).fillna(-1)
 dataframe.drop(columns = ['Fence'], inplace = True)
 return dataframe
full = handleFence(full)
 print("Full data shape is {}".format(full.shape))<categorify>
model = unet(depth=3)
 model.compile(optimizer=Adam(lr=1e-3), loss='binary_crossentropy', metrics=[_dice_coefficient(0.5)])
 model.summary()
def handleUtilities(dataframe):
dataframe['Electricity'] = dataframe['Utilities'].map({'AllPub' : 1, 'NoSewr' : 1, 'NoSeWa' : 1, 'ELO' : 1} ).fillna(0)
 dataframe['Gas'] = dataframe['Utilities'].map({'AllPub' : 1, 'NoSewr' : 1, 'NoSeWa' : 1, 'ELO' : 0} ).fillna(0)
 dataframe['Water'] = dataframe['Utilities'].map({'AllPub' : 1, 'NoSewr' : 1, 'NoSeWa' : 0, 'ELO' : 0} ).fillna(0)
 dataframe['Septic Tank'] = dataframe['Utilities'].map({'AllPub' : 1, 'NoSewr' : 0, 'NoSeWa' : 0, 'ELO' : 0} ).fillna(0)
 dataframe.drop(columns = ['Utilities'], inplace = True)
 return dataframe
full = handleUtilities(full)
 print("Full data shape is {}".format(full.shape))<categorify>
model_folder = os.path.join('./model', 'sample-code')
 if not os.path.exists(model_folder):
os.makedirs(model_folder)
 callbacks = []
callbacks.append(ModelCheckpoint(os.path.join(model_folder, 'model-{epoch:03d}.h5'),
save_best_only=False,
period=5))
lat_dict = {}
lon_dict = {}
for i in range(len(geo_heatmap['Neighborhood'])) :
neighborhood = geo_heatmap['Neighborhood'][i]
lat = geo_heatmap['Latitude'][i]
lon = geo_heatmap['Longitude'][i]
lat_dict[neighborhood] = lat
lon_dict[neighborhood] = lon
def add_lat_lon_columns(df):
df ['Latitude'] = df['Neighborhood'].map(lat_dict)
 df ['Longitude'] = df['Neighborhood'].map(lon_dict)
 df.drop(columns=['Neighborhood'], inplace=True)
 add_lat_lon_columns(full)
 print("Full data shape is {}".format(full.shape))<sort_values>
history = model.fit_generator(slice_generator,
epochs=15,
verbose=1,
callbacks=callbacks )
missing_values = full.isnull().sum()
missing_values[missing_values>0].sort_values(ascending = False )<sort_values>
def retrieve_pred_str(src_dir, model, threshold=0.4):
encode_name = src_dir.split('/')[-1]
_, test_volume = load_dicom_volume(src_dir, suffix='*.dcm')
 pred_label = model.predict(np.expand_dims(test_volume, axis=-1))
pred_label = np.transpose(pred_label[:, :, :, 0], axes=(2, 1, 0))
pred_label =(pred_label > threshold ).astype(np.int)
 label_flatten = pred_label.flatten()
label_flatten_idx = np.where(label_flatten == 1)[0]
label_str = ''
if label_flatten_idx.size > 0:
prev_idx = label_flatten_idx[0]
idx_start = label_flatten_idx[0]
cnt = 1
for _idx in label_flatten_idx[1:]:
if _idx == prev_idx+1:
cnt += 1
else:
label_str += str(idx_start)+ ' ' + str(cnt)+ ' '
cnt = 1
idx_start = _idx
prev_idx = _idx
label_str = label_str.rstrip(' ')
 return(encode_name, label_str )
full['KitchenQual'] = full['KitchenQual'].fillna(0)
 missing_values = full.isnull().sum()
missing_values[missing_values>0].sort_values(ascending = False )<filter>
sample_submission = np.genfromtxt('.. /input/sample_submission.csv',
delimiter=',',
dtype='str',
skip_header = 1 )
full[full['GarageArea'].isnull() ]<feature_engineering>
test_encode_list = sample_submission[:, 0]
new = full.iloc[2576].copy()
new['GarageArea'] = 0
new['GarageCars'] = 0
new['GarageCond'] = -1
new['GarageFinish'] = -1
new['GarageQual'] = -1
full.iloc[2576] = new.copy()
missing_values = full.isnull().sum()
missing_values[missing_values>0].sort_values(ascending = False )<sort_values>
pred_pair_list = []
for encode_name in tqdm.tqdm(test_encode_list, total=len(test_encode_list)) : 
(encode, label_str)= retrieve_pred_str(os.path.join(test_image_folder, encode_name), model, threshold=0.4)
 pred_pair_list.append(( encode, label_str))
<filter><EOS> 
solution_path = './sample-code_pred.csv'
with open(solution_path, 'w')as f:
f.write('encode,pixel_value
')
 for _pair in pred_pair_list:
encode = _pair[0]
label_str = _pair[1]
f.write(encode + ',' + label_str + '
' )