Kaggle competition: Quora Insincere Questions Classification
overall_embarked = dict(data_explore["Embarked"].value_counts())
 overall_embarked = sorted(overall_embarked.items())
 overall_embarked_values = [item[1] for item in overall_embarked]
overall_embarked_labels = [item[0] for item in overall_embarked]
survived_embarked = dict(data_explore_survived["Embarked"].value_counts())
 survived_embarked = sorted(survived_embarked.items())
 survived_embarked_values = [item[1] for item in survived_embarked]<count_values>
train_df = pd.read_csv('.. /input/train.csv')
 X_train = train_df["question_text"].fillna("dieter" ).values
test_df = pd.read_csv('.. /input/test.csv')
 X_test = test_df["question_text"].fillna("dieter" ).values
y = train_df["target"]
overall_pclass = dict(data_explore["Pclass"].value_counts())
 overall_pclass = sorted(overall_pclass.items())
 overall_pclass_labels = ["Upper Class", "Middle Class", "Lower Class"]
overall_pclass_values = [item[1] for item in overall_pclass]
survived_pclass = dict(data_explore_survived["Pclass"].value_counts())
 survived_pclass = sorted(survived_pclass.items())
 survived_pclass_values = [item[1] for item in survived_pclass]<count_values>
from keras.models import Model
from keras.layers import Input, Dense, Embedding, concatenate
from keras.layers import CuDNNGRU, Bidirectional, GlobalAveragePooling1D, GlobalMaxPooling1D, Conv1D
from keras.layers import Add, BatchNormalization, Activation, CuDNNLSTM, Dropout
from keras.layers import *
from keras.models import *
from keras.preprocessing import text, sequence
from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
import gc
from sklearn import metrics
from keras.optimizers import *
overall_family = dict(data_explore["Family"].value_counts())
 overall_family = sorted(overall_family.items())
 overall_family_labels = ["No", "Yes"]
overall_family_values = [item[1] for item in overall_family]
survived_family = dict(data_explore_survived["Family"].value_counts())
 survived_family = sorted(survived_family.items())
 survived_family_values = [item[1] for item in survived_family]<sort_values>
maxlen = 70
max_features = 50000
embed_size = 300
tokenizer = text.Tokenizer(num_words=max_features)
 tokenizer.fit_on_texts(list(X_train)+ list(X_test))
X_train = tokenizer.texts_to_sequences(X_train)
 X_test = tokenizer.texts_to_sequences(X_test)
 x_train = sequence.pad_sequences(X_train, maxlen=maxlen)
 x_test = sequence.pad_sequences(X_test, maxlen=maxlen )
corr_matrix['Survived'].sort_values(ascending=False )<import_modules>
def attention_3d_block(inputs):
TIME_STEPS = inputs.shape[1].value
SINGLE_ATTENTION_VECTOR = False
input_dim = int(inputs.shape[2])
 a = Permute(( 2, 1))(inputs)
 a = Reshape(( input_dim, TIME_STEPS))(a)
 a = Dense(TIME_STEPS, activation='softmax' )(a)
 if SINGLE_ATTENTION_VECTOR:
a = Lambda(lambda x: K.mean(x, axis=1))(a)
 a = RepeatVector(input_dim )(a)
 a_probs = Permute(( 2, 1))(a)
 output_attention_mul = Multiply()([inputs, a_probs])
 return output_attention_mul
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.base import BaseEstimator, TransformerMixin<prepare_x_and_y>
class AttLayer(Layer):
def __init__(self, attention_dim):
self.init = initializers.get('normal')
 self.supports_masking = True
self.attention_dim = attention_dim
super(AttLayer, self ).__init__()
def build(self, input_shape):
assert len(input_shape)== 3
self.W = K.variable(self.init(( input_shape[-1], self.attention_dim)))
 self.b = K.variable(self.init(( self.attention_dim,)))
 self.u = K.variable(self.init(( self.attention_dim, 1)))
 self.trainable_weights = [self.W, self.b, self.u]
super(AttLayer, self ).build(input_shape)
 def compute_mask(self, inputs, mask=None):
return mask
def call(self, x, mask=None):
uit = K.tanh(K.bias_add(K.dot(x, self.W), self.b))
ait = K.dot(uit, self.u)
 ait = K.squeeze(ait, -1)
 ait = K.exp(ait)
 if mask is not None:
ait *= K.cast(mask, K.floatx())
 ait /= K.cast(K.sum(ait, axis=1, keepdims=True)+ K.epsilon() , K.floatx())
 ait = K.expand_dims(ait)
 weighted_input = x * ait
output = K.sum(weighted_input, axis=1)
 return output
def compute_output_shape(self, input_shape):
return(input_shape[0], input_shape[-1] )
X = data.drop(columns=['Survived'], axis=1)
 y = data['Survived'].copy()
X.shape, X.columns<split>
def noise_measurement(train, noise_level):
noised_train = train.copy()
to_transform = np.random.random(train.shape)< noise_level
transform_y = np.random.randint(0, max_features, size=train.shape)
 noised_train[to_transform] = transform_y[to_transform]
return noised_train
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
 for train_index, test_index in split.split(X, y):
strat_train_set = data.iloc[train_index]
strat_test_set = data.iloc[test_index]
X_train = strat_train_set.drop('Survived', axis=1)
 y_train = strat_train_set['Survived'].copy()
X_test = strat_test_set.drop('Survived', axis=1)
 y_test = strat_test_set['Survived'].copy()
X_train.shape, X_test.shape<categorify>
EMBEDDING_FILE = '.. /input/embeddings/glove.840B.300d/glove.840B.300d.txt'
def get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')
 embeddings_index = dict(get_coefs(*o.split(" ")) for o in open(EMBEDDING_FILE))
all_embs = np.stack(embeddings_index.values())
 emb_mean,emb_std = all_embs.mean() , all_embs.std()
embed_size = all_embs.shape[1]
word_index = tokenizer.word_index
nb_words = min(max_features, len(word_index))
embedding_matrix_1 = np.random.normal(emb_mean, emb_std,(nb_words, embed_size))
for word, i in word_index.items() :
if i >= max_features: continue
embedding_vector = embeddings_index.get(word)
 if embedding_vector is not None: embedding_matrix_1[i] = embedding_vector
del embeddings_index; gc.collect()
def fill_with_mean(df, num_cols):
for col in num_cols:
total_null = df[col].isna().sum()
if total_null>0:
mean = df[col].mean()
std = df[col].std()
lower = mean - std
upper = mean + std
random_values = np.random.randint(lower, upper, total_null)
 df[col][np.isnan(df[col])] = random_values.copy()
return df<categorify>
EMBEDDING_FILE = '.. /input/embeddings/wiki-news-300d-1M/wiki-news-300d-1M.vec'
def get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')
 embeddings_index = dict(get_coefs(*o.split(" ")) for o in open(EMBEDDING_FILE)if len(o)>100)
 all_embs = np.stack(embeddings_index.values())
 emb_mean,emb_std = all_embs.mean() , all_embs.std()
embed_size = all_embs.shape[1]
word_index = tokenizer.word_index
nb_words = min(max_features, len(word_index))
embedding_matrix_2 = np.random.normal(emb_mean, emb_std,(nb_words, embed_size))
for word, i in word_index.items() :
if i >= max_features: continue
embedding_vector = embeddings_index.get(word)
 if embedding_vector is not None: embedding_matrix_2[i] = embedding_vector
del embeddings_index; gc.collect()
class AddCustomAttribute(BaseEstimator, TransformerMixin):

 def __init__(self):

 self.cat_imp=None
self.cat_encoder=None
self.scaler=None
def fit(self, X, y=None):
return self
def transform(self, X):
try:
X = fill_with_mean(X, ['Age', 'SibSp', 'Parch'])
 if self.cat_imp==None:
self.cat_imp = SimpleImputer(strategy="most_frequent")
 X['Sex'] = self.cat_imp.fit_transform(X[['Sex']])
 else:
X['Sex'] = self.cat_imp.transform(X[['Sex']])
 X['Person'] = X[['Age', 'Sex']].apply(self.get_person_type, axis=1)
 X['Family'] = X['SibSp'] + X['Parch']
X['Family'].loc[X['Family'] > 0] = 1
X['Family'].loc[X['Family'] == 0] = 0
if self.scaler==None:
self.scaler = StandardScaler()
X['Age'] = self.scaler.fit_transform(X[['Age']])
 else:
X['Age'] = self.scaler.transform(X[['Age']])
 if self.cat_encoder==None:
self.cat_encoder = OneHotEncoder(handle_unknown='ignore')
 X_new = self.cat_encoder.fit_transform(X[['Person', 'Family']])
 else:
X_new = self.cat_encoder.transform(X[['Person', 'Family']])
 X_new = pd.DataFrame(X_new.toarray())
 X_new.index = X.index
X = pd.concat([X, X_new], axis=1)
 X = X.drop(columns=['Sex', 'Person', 'SibSp', 'Parch', 'Family'], axis=1)
 except:
print("Error generated in AddCustomAttribute!!!")
 return X
@staticmethod
def get_person_type(passanger):
sex_enc = dict({'child':0, 'female':1, 'male':2})
 age, sex = passanger
return 'child' if age < 16 else sex<categorify>
EMBEDDING_FILE = '.. /input/embeddings/paragram_300_sl999/paragram_300_sl999.txt'
def get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')
 embeddings_index = dict(get_coefs(*o.split(" ")) for o in open(EMBEDDING_FILE, encoding="utf8", errors='ignore')if len(o)>100)
 all_embs = np.stack(embeddings_index.values())
 emb_mean,emb_std = all_embs.mean() , all_embs.std()
embed_size = all_embs.shape[1]
word_index = tokenizer.word_index
nb_words = min(max_features, len(word_index))
embedding_matrix_3 = np.random.normal(emb_mean, emb_std,(nb_words, embed_size))
for word, i in word_index.items() :
if i >= max_features: continue
embedding_vector = embeddings_index.get(word)
 if embedding_vector is not None: embedding_matrix_3[i] = embedding_vector
del embeddings_index; gc.collect()
class FillWithMeanSD(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def fit(self, X, y=None):
return self
def transform(self, X):
try:
num_cols = X.columns
for col in num_cols:
total_null_fare = X[col].isna().sum()
if total_null_fare>0:
mean = X[col].mean()
std = X[col].std()
lower = mean - std
upper = mean + std
random_values = np.random.randint(lower, upper, total_null_fare)
 X[col][np.isnan(X[col])] = random_values.copy()
except:
print("Error generated in FillWithSD!!!")
 return X<categorify>
embedding_matrix = np.mean([embedding_matrix_1, embedding_matrix_2, embedding_matrix_3], axis=0)
 del embedding_matrix_1, embedding_matrix_2, embedding_matrix_3
gc.collect()
np.shape(embedding_matrix )
cat_pipeline = Pipeline([('cat_imputer', SimpleImputer(strategy="most_frequent")) , 
('cat_encoder', OneHotEncoder())])
 num_pipeline = Pipeline([('num_imputer', FillWithMeanSD()), 
('scaler', StandardScaler())])
 pre_process = ColumnTransformer([('drop_attrs', 'drop', ['PassengerId', 'Name', 'Ticket', 'Cabin']), 
('num_pipeline', num_pipeline, ['Pclass', 'Fare']), 
('cat_pipeline', cat_pipeline, ['Embarked']), 
('custom_attr', AddCustomAttribute() , ['Age', 'Sex', 'SibSp', 'Parch'])],
remainder='passthrough' )<define_variables>
X_tra, X_val, y_tra, y_val = train_test_split(x_train, y, test_size = 0.1, random_state=42 )
feature_columns = ['Pclass', 'Fare', 'C', 'Q', 'S', 'Age', 'person_child', 'person_female', 'person_male',
'family_no', 'family_yes']<choose_model_class>
def model1() :
inp = Input(shape=(maxlen,))
embed = Embedding(max_features, embed_size * 1, weights=[embedding_matrix], trainable=False )(inp)
 embed = SpatialDropout1D(0.1 )(embed)
 filter_sizes = [1,2,3,5]
num_filters = 64
conv_0 = Conv1D(num_filters, filter_sizes[0], padding='valid', kernel_initializer='normal', activation='relu' )(embed)
 conv_1 = Conv1D(num_filters, filter_sizes[1], padding='valid', kernel_initializer='normal', activation='relu' )(embed)
 conv_2 = Conv1D(num_filters, filter_sizes[2], padding='valid', kernel_initializer='normal', activation='relu' )(embed)
 conv_3 = Conv1D(num_filters, filter_sizes[3], padding='valid', kernel_initializer='normal', activation='relu' )(embed)
 maxpool_0 = MaxPool1D(pool_size=(maxlen - filter_sizes[0] + 1), strides=(1), padding='valid' )(conv_0)
 maxpool_1 = MaxPool1D(pool_size=(maxlen - filter_sizes[1] + 1), strides=(1), padding='valid' )(conv_1)
 maxpool_2 = MaxPool1D(pool_size=(maxlen - filter_sizes[2] + 1), strides=(1), padding='valid' )(conv_2)
 maxpool_3 = MaxPool1D(pool_size=(maxlen - filter_sizes[3] + 1), strides=(1), padding='valid' )(conv_3)
 concatenated_tensor = Concatenate(axis=1 )([maxpool_0, maxpool_1, maxpool_2, maxpool_3])
 flatten = Flatten()(concatenated_tensor)
 x = flatten
x = Dropout(0.5 )(x)
 x = Dense(128, activation='relu' )(x)
 outp = Dense(1, activation="sigmoid" )(x)
 model = Model(inputs=inp, outputs=outp)
 model.compile(loss='binary_crossentropy',
optimizer=Adam(lr=1e-3, decay=1e-6),
metrics=['accuracy'])
 return model
kf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42 )<train_on_grid>
MODEL1 = model1()
MODEL1.summary()
batch_size = 2048
epochs = 4
hist = MODEL1.fit(X_tra, y_tra, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val), verbose=True)
 MODEL1.save('./model1.h5' )
lgr_grid_parm=[{'solver':['liblinear', 'lbfgs'], 'C':list(np.linspace(0.01, 1, 15)) , 'penalty':['l1', 'l2'], 'class_weight':[None, 'balanced']}]
lgr_grid_search = GridSearchCV(LogisticRegression(random_state=42, n_jobs=-1),
lgr_grid_parm, cv=kf, scoring="accuracy", return_train_score=True, n_jobs=-1)
 lgr_grid_search.fit(X_train_transformed, y_train )<find_best_params>
pred_val_y_1 = MODEL1.predict([X_val], batch_size=1024, verbose=1)
 thresholds = []
for thresh in np.arange(0.1, 0.501, 0.01):
thresh = np.round(thresh, 2)
 res = metrics.f1_score(y_val,(pred_val_y_1 > thresh ).astype(int))
thresholds.append([thresh, res])
 print("F1 score at threshold {0} is {1}".format(thresh, res))
thresholds.sort(key=lambda x: x[1], reverse=True)
 best_thresh_1 = thresholds[0][0]
print("Best threshold: ", best_thresh_1)
 y_pred_1 = MODEL1.predict(x_test, batch_size=1024, verbose=True )
lgr_grid_search.best_params_, lgr_grid_search.best_score_<choose_model_class>
def model2() :
inp = Input(shape=(maxlen,))
embed = Embedding(max_features, embed_size * 1, weights=[embedding_matrix], trainable=False )(inp)
 x = embed
x = SpatialDropout1D(0.1 )(x)
 x = Bidirectional(CuDNNLSTM(64, return_sequences=True))(x)
 x = attention_3d_block(x)
 x = Bidirectional(CuDNNLSTM(64, return_sequences=True))(x)
 x = AttLayer(maxlen )(x)
 x = Dropout(0.3 )(x)
 x = Dense(128, activation='relu' )(x)
 outp = Dense(1, activation="sigmoid" )(x)
 model = Model(inputs=inp, outputs=outp)
 model.compile(loss='binary_crossentropy',
optimizer=Adam(lr=1e-3, decay=1e-6),
metrics=['accuracy'])
 return model
train_models = []
train_models.append(['Logistic Regression', lgr_grid_search.best_params_, lgr_grid_search.best_score_] )<find_best_params>
MODEL2 = model2()
MODEL2.summary()
batch_size = 2048
epochs = 5
hist = MODEL2.fit(X_tra, y_tra, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val), verbose=True)
 MODEL2.save('./model2.h5' )
best_lgr_clf = lgr_grid_search.best_estimator_
best_lgr_clf<train_on_grid>
pred_val_y_2 = MODEL2.predict([X_val], batch_size=1024, verbose=1)
 thresholds = []
for thresh in np.arange(0.1, 0.501, 0.01):
thresh = np.round(thresh, 2)
 res = metrics.f1_score(y_val,(pred_val_y_2 > thresh ).astype(int))
thresholds.append([thresh, res])
 print("F1 score at threshold {0} is {1}".format(thresh, res))
thresholds.sort(key=lambda x: x[1], reverse=True)
 best_thresh_2 = thresholds[0][0]
print("Best threshold: ", best_thresh_2)
 y_pred_2 = MODEL2.predict(x_test, batch_size=1024, verbose=True )
svc_grid_parm=[{'C':list(np.linspace(0.01, 1, 20)) , 'penalty':['l1', 'l2'], 'class_weight':[None, 'balanced']}]
svc_grid_search = GridSearchCV(LinearSVC(loss="hinge", random_state=42), svc_grid_parm, cv=kf, scoring="accuracy",
return_train_score=True, n_jobs=-1)
 svc_grid_search.fit(X_train_transformed, y_train )<find_best_params>
def model3() :
filters = 64
inp = Input(shape=(maxlen,))
embed = Embedding(max_features, embed_size * 1, weights=[embedding_matrix], trainable=False )(inp)
 x = embed
x = SpatialDropout1D(0.1 )(x)
 x = Conv1D(filters, 1, activation='relu', padding='valid', kernel_initializer='normal' )(x)
 x = Dropout(0.1 )(x)
 x = Conv1D(filters, 2, activation='relu', padding='valid', kernel_initializer='normal' )(x)
 x = Dropout(0.1 )(x)
 x = Conv1D(filters, 3, activation='relu', padding='valid', kernel_initializer='normal' )(x)
 x = Dropout(0.1 )(x)
 x = Conv1D(filters, 5, activation='relu', padding='valid', kernel_initializer='normal' )(x)
 x = Dropout(0.1 )(x)
 x = Flatten()(x)
 x = Dropout(0.3 )(x)
 x = Dense(128, activation='relu' )(x)
 outp = Dense(1, activation="sigmoid" )(x)
 model = Model(inputs=inp, outputs=outp)
 model.compile(loss='binary_crossentropy',
optimizer=Adam(lr=1e-3, decay=1e-6),
metrics=['accuracy'])
 return model
svc_grid_search.best_params_, svc_grid_search.best_score_<find_best_params>
MODEL3 = model3()
MODEL3.summary()
batch_size = 2048
epochs = 10
hist = MODEL3.fit(X_tra, y_tra, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val), verbose=True)
 MODEL3.save('./model3.h5' )
best_svc_clf = svc_grid_search.best_estimator_
best_svc_clf<train_on_grid>
pred_val_y_3 = MODEL3.predict([X_val], batch_size=1024, verbose=1)
 thresholds = []
for thresh in np.arange(0.1, 0.501, 0.01):
thresh = np.round(thresh, 2)
 res = metrics.f1_score(y_val,(pred_val_y_3 > thresh ).astype(int))
thresholds.append([thresh, res])
 print("F1 score at threshold {0} is {1}".format(thresh, res))
thresholds.sort(key=lambda x: x[1], reverse=True)
 best_thresh_3 = thresholds[0][0]
print("Best threshold: ", best_thresh_3)
 y_pred_3 = MODEL3.predict(x_test, batch_size=1024, verbose=True )
rf_grid_parm=[{'n_estimators':[50, 100, 200, 300], 'max_depth':[6, 8, 16],
'class_weight':['balanced', 'balanced_subsample', None]}]
rf_grid_search = GridSearchCV(RandomForestClassifier(random_state=42, n_jobs=-1), rf_grid_parm, cv=kf,
scoring="accuracy", return_train_score=True, n_jobs=-1)
 rf_grid_search.fit(X_train_transformed, y_train )<find_best_params>
def model4() :
inp = Input(shape=(maxlen,))
embed = Embedding(max_features, embed_size * 1, weights=[embedding_matrix], trainable=False )(inp)
 x = embed
x = SpatialDropout1D(0.1 )(x)
 x = Bidirectional(CuDNNGRU(64, return_sequences=True))(x)
 x = attention_3d_block(x)
 x = Bidirectional(CuDNNGRU(64, return_sequences=True))(x)
 x = AttLayer(64 )(x)
 x = Dropout(0.3 )(x)
 x = Dense(128, activation='relu' )(x)
 outp = Dense(1, activation="sigmoid" )(x)
 model = Model(inputs=inp, outputs=outp)
 model.compile(loss='binary_crossentropy',
optimizer=Adam(lr=1e-3, decay=1e-6),
metrics=['accuracy'])
 return model
rf_grid_search.best_params_, rf_grid_search.best_score_<find_best_params>
MODEL4 = model4()
MODEL4.summary()
batch_size = 2048
epochs = 5
hist = MODEL4.fit(X_tra, y_tra, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val), verbose=True)
 MODEL4.save('./model4.h5' )
best_rf_clf = rf_grid_search.best_estimator_
best_rf_clf<define_search_space>
pred_val_y_4 = MODEL4.predict([X_val], batch_size=1024, verbose=1)
 thresholds = []
for thresh in np.arange(0.1, 0.501, 0.01):
thresh = np.round(thresh, 2)
 res = metrics.f1_score(y_val,(pred_val_y_4 > thresh ).astype(int))
thresholds.append([thresh, res])
 print("F1 score at threshold {0} is {1}".format(thresh, res))
thresholds.sort(key=lambda x: x[1], reverse=True)
 best_thresh_4 = thresholds[0][0]
print("Best threshold: ", best_thresh_4)
 y_pred_4 = MODEL4.predict(x_test, batch_size=1024, verbose=True )
xgb_grid_parm=[{'n_estimators':[50, 100, 200], 'max_depth':[4, 8, 16, 24], 'subsample':[0.5, 0.75, 1.0],
'colsample_bytree':[0.5, 0.75, 1.0], 'gamma':[0, 0.25, 0.5, 0.75, 1.0]}]
xgb_grid_search = GridSearchCV(XGBClassifier(objective='binary:logistic', learning_rate=0.1, random_state=42,
n_jobs=-1), xgb_grid_parm, cv=kf, scoring="accuracy",
return_train_score=True, n_jobs=-1)
 xgb_grid_search.fit(X_train_transformed, y_train )<find_best_params>
pred_val_y =(2.5*pred_val_y_1 + 2.5*pred_val_y_2 + 2.5*pred_val_y_3 + 2.5*pred_val_y_4)/10
thresholds = []
for thresh in np.arange(0.1, 0.501, 0.01):
thresh = np.round(thresh, 2)
 res = metrics.f1_score(y_val,(pred_val_y > thresh ).astype(int))
thresholds.append([thresh, res])
 print("F1 score at threshold {0} is {1}".format(thresh, res))
thresholds.sort(key=lambda x: x[1], reverse=True)
 best_thresh = thresholds[0][0]
print("Best threshold: ", best_thresh )
xgb_grid_search.best_params_, xgb_grid_search.best_score_<find_best_params>
y_pred =(2.5*y_pred_1 + 2.5*y_pred_2 + 2.5*y_pred_3 + 2.5*y_pred_4)/10
y_te =(y_pred[:,0] > best_thresh ).astype(np.int)
 submit_df = pd.DataFrame({"qid": test_df["qid"], "prediction": y_te})
 submit_df.to_csv("submission.csv", index=False )
<define_variables><EOS> 
def create_download_link(df, title = "Download CSV file", filename = "data.csv"):
csv = df.to_csv(index =False)
 b64 = base64.b64encode(csv.encode())
 payload = b64.decode()
html = '<a download="{filename}" href="data:text/csv;base64,{payload}" target="_blank">{title}</a>'
html = html.format(payload=payload,title=title,filename=filename)
 return HTML(html)
 create_download_link(submit_df )