text: def load_data(logfile=None):
  
      import datetime
      import time
      import numpy as np
      import csv
      from datetime import datetime
      from keras.preprocessing.sequence import pad_sequences
  
      vocabulary = list()
      
      csvfile = open(logfile, 'r')
      if "receipt" in logfile: # For Receipt Dataset
          logreader = csv.reader(csvfile, delimiter=',')
  
      elif "helpdesk" in logfile: 
          logreader = csv.reader(csvfile, delimiter=';') # For Helpdesk Dataset
  
      next(logreader, None)  # skip the headers
  
      lastcase = '' 
      casestarttime = None
      lasteventtime = None
      firstLine = True
  
      lines = [] #these are all the activity seq
      timeseqs = [] #time sequences (differences between two events)
      trace_start_list = []
  
      numcases = 0
      max_length = 0
      trace_start_index = 0
  
      for row in logreader:
          if "receipt" in logfile: # For Receipt Dataset 
              t = datetime.strptime(row[2], "%Y-%m-%d %H:%M:%S.%f")
          elif "helpdesk" in logfile: 
              t = datetime.strptime(row[2], "%d.%m.%Y-%H:%M:%S") # For Helpdesk Dataset
  
          if row[0]!=lastcase:  #'lastcase' is to save the last executed case for the loop
              casestarttime = t
              lasteventtime = t
              lastcase = row[0]
              if not firstLine:
                  lines.append(line)
                  timeseqs.append(times)
                  if len(line) > max_length:
                      max_length = len(line)
              line = []
              times = []
              numcases += 1
              if trace_start_index != 0:
                  trace_start_index-=1 # To remove index for last case which is not counted as a prefix
                  trace_start_list.append(trace_start_index)
              elif trace_start_index == 0:
                  trace_start_list.append(trace_start_index)
  
  
          if row[1] not in vocabulary:
              vocabulary.append(row[1])
          line.append(row[1])
          timesincelastevent = t - lasteventtime
          timediff = 86400 * timesincelastevent.days + timesincelastevent.seconds + timesincelastevent.microseconds/1000000
          # +1 avoid zero
          times.append(timediff+1)
          lasteventtime = t
          firstLine = False
          trace_start_index+=1
  
      lines.append(line)
      timeseqs.append(times)
  
      vocabulary = {key: idx for idx, key in enumerate(vocabulary)}
      divisor = np.mean([item for sublist in timeseqs for item in sublist]) #average time between events
      numcases += 1
      print("Num cases: ", numcases)
      elems_per_fold = int(round(numcases/3))
  
      if len(line) > max_length:
          max_length = len(line)
  
      X = []
      X1 = []
      y = []
      y_t = []
  
      categorical_features_name = []
      categorical_features_time = []
  
      max_length = 0
      prefix_sizes = []
      seqs = 0
      vocab = set()
  
      count = 0
  
      for seq, time in zip(lines, timeseqs):
          code = []
          code.append(vocabulary[seq[0]])
          code1 = []
          code1.append(np.log(time[0]+1))
  
          vocab.add(seq[0])
  
          for i in range(1,len(seq)):
              prefix_sizes.append(len(code))
  
              if len(code)>max_length:
                  max_length = len(code)
  
              # Building Activity Names and Time from Index for Explainability part
              sub_feature_name = []
              sub_feature_time = []
              vocabulary_clone = vocabulary.copy()
              for j in code[:]:
                  
                  for name, index in vocabulary_clone.items():
                      if index == j:
                          sub_feature_name.append(name)
                          sub_feature_time.append("Time corresponding to "+name)
  
              categorical_features_name.append(sub_feature_name)
              categorical_features_time.append(sub_feature_time)
  
              X.append(code[:])
              X1.append(code1[:])
              y.append(vocabulary[seq[i]])
              y_t.append(time[i]/divisor)
  
              code.append(vocabulary[seq[i]])
              code1.append(np.log(time[i]+1))
              seqs += 1
  
              vocab.add(seq[i])
              
      prefix_sizes = np.array(prefix_sizes)
      print("Num sequences:", seqs)
      vocab_size = len(vocab)
  
      X = np.array(X)
      X1 = np.array(X1)
      y = np.array(y)
      y_t = np.array(y_t)
  
      categorical_features_name = np.array(categorical_features_name)
      categorical_features_time = np.array(categorical_features_time)
  
      y_unique = np.unique(y)
      dict_y = {}
      i = 0
      for el in y_unique:
          dict_y[el] = i
          i += 1
      for i in range(len(y)):
          y[i] = dict_y[y[i]]
      y_unique = np.unique(y, return_counts=True)
      print("Classes: ", y_unique)
      n_classes = y_unique[0].shape[0]
  
      # Establishing vocabulary for classes by removing non-predicatable class from vocabulary (For Helpdesk Dataset)
      rebel = int
      vocabulary_class = {}
  
      # Finding where the class occurs which is not to be predicted
      for key,value in enumerate(dict_y):
          if (key!=value):
              rebel = key
              break
      
      # deleting that class from dictionary
      for name in vocabulary_clone.copy():
          if (vocabulary_clone[name] == rebel):
              vocabulary_clone.pop(name)
  
      vocabulary_class = vocabulary_clone.copy()
      for index,name in enumerate(vocabulary_class.copy()):
              vocabulary_class[name] = index
  
      # padding
      padded_X = pad_sequences(X, maxlen=max_length, padding='pre', dtype='float64')
      padded_X1 = pad_sequences(X1, maxlen=max_length, padding='pre', dtype='float64')
      padded_features = pad_sequences(categorical_features_name, maxlen=max_length, padding='pre', dtype=object, value="Zero Padded Feature") #Padding feature name for Padded feature
      padded_features_time = pad_sequences(categorical_features_time, maxlen=max_length, padding='pre', dtype=object, value="Zero Padded Feature") #Padding feature time for Padded feature
  
      return ( (padded_X, padded_X1), (y, y_t), vocab_size, max_length, n_classes, divisor, prefix_sizes, vocabulary, vocabulary_class, padded_features, padded_features_time, categorical_features_name, trace_start_list)
  