This solution works well, but it is not perfect. It needs to be improved to get more accurate values:
# Step 1: Data Loading and Exploration

# Import necessary libraries
import pandas as pd
import numpy as np

# For data visualization
import matplotlib.pyplot as plt
import seaborn as sns

# For modeling
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import recall_score
from lightgbm import LGBMClassifier

# Suppress warnings
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)

train = pd.read_csv('/content/train_share.tsv', sep='\t', encoding='utf-8')
test = pd.read_csv('/content/test_share.tsv', sep='\t', encoding='utf-8')

# Print the shapes of the datasets
print(f'Training data shape: {train.shape}')
print(f'Test data shape: {test.shape}')

# Display the first few rows of the training data
train.head()
  test['target'] = -1  # Temporarily add target column to test data
combined = pd.concat([train, test], axis=0, ignore_index=True)

# Clean the feature names to remove special characters
import re

def clean_column_names(df):
    df.columns = [re.sub(r'[^\w]', '_', col) for col in df.columns]
    return df

combined = clean_column_names(combined)

# Now define the features
features = [col for col in combined.columns if col != 'target']

# Proceed with handling missing values, encoding, etc.
# Handle missing values
# We can fill missing numerical values with the median and categorical with the mode
for col in features:
    if combined[col].dtype == 'object':
        combined[col] = combined[col].fillna(combined[col].mode()[0])
    else:
        combined[col] = combined[col].fillna(combined[col].median())
    
# Encode categorical variables using Label Encoding
le = LabelEncoder()
for col in features:
    if combined[col].dtype == 'object':
        combined[col] = le.fit_transform(combined[col])

# Split the data back into train and test sets
train_processed = combined[combined['target'] != -1].reset_index(drop=True)
test_processed = combined[combined['target'] == -1].reset_index(drop=True)

# Drop the temporary target column from test data
test_processed = test_processed.drop('target', axis=1)

# Separate features and target variable from training data
X = train_processed[features]
y = train_processed['target']

# Features for test data
X_test = test_processed[features]
  #!pip install lightgbm==3.3.2
# Step 3: Model Selection and Training
# Since the metric is recall@15%, we'll define a custom evaluation metric

def recall_at_k(y_true, y_prob, k):
    # y_true: true binary labels
    # y_prob: predicted probabilities
    # k: cutoff percentage (e.g., 0.15 for top 15%)
    threshold = np.quantile(y_prob, 1 - k)
    y_pred = np.where(y_prob >= threshold, 1, 0)
    recall = recall_score(y_true, y_pred)
    return recall

# Use Stratified K-Fold cross-validation due to imbalance
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

# Placeholder for out-of-fold predictions
oof_preds = np.zeros(X.shape[0])

# Placeholder for test predictions
test_preds = np.zeros(X_test.shape[0])

# LightGBM parameters (you can tune these parameters)
lgb_params = {
    'learning_rate': 0.01,
    'n_estimators': 1000,
    'objective': 'binary',
    'metric': 'binary_logloss',
    'random_state': 42,
    'n_jobs': -1
}

# Training with cross-validation
for fold, (train_idx, val_idx) in enumerate(skf.split(X, y)):
    print(f'Fold {fold + 1}')
    X_train, X_val = X.loc[train_idx], X.loc[val_idx]
    y_train, y_val = y.loc[train_idx], y.loc[val_idx]
    
    model = LGBMClassifier(**lgb_params)
    model.fit(
        X_train, y_train,
        eval_set=[(X_val, y_val)],
        early_stopping_rounds=100,
        verbose=100
    )
    
    # Predict on validation set
    val_preds = model.predict_proba(X_val)[:, 1]
    oof_preds[val_idx] = val_preds
    
    # Predict on test set
    test_fold_preds = model.predict_proba(X_test)[:, 1]
    test_preds += test_fold_preds / skf.n_splits
    
    # Evaluate recall@15% on validation set
    recall = recall_at_k(y_val, val_preds, 0.15)
    print(f'Recall@15% for fold {fold + 1}: {recall:.4f}\n')

# Overall OOF Recall@15%
overall_recall = recall_at_k(y, oof_preds, 0.15)
print(f'Overall Recall@15%: {overall_recall:.4f}')
  # Step 4: Prediction

# The test_preds array contains the average predictions over the folds
# Now, we prepare the submission file

# Assuming the test data has an 'id' column (replace with actual ID column name if different)
submission = pd.DataFrame({
    'id': X_test.index,  # Replace 'id' with the actual ID column name in test.csv
    'target': test_preds
})

# Ensure the submission file has the correct format
submission.head()

# Step 5: Submission

# Save the submission file
submission.to_csv('submission.csv', index=False)