Project: s41467-025-62355-z | Function: generate_pair_comparisons (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Implements the core pairwise comparison generation algorithm that computes PGS differences (Δ) and phenotypic differences between individuals, which is fundamental for evaluating the known-to-total ratio κ and prediction accuracy

**KEY TERMS:** {
  "pgs": "polygenic scores for individuals",
  "phenotypes": "measured phenotypic values",
  "dpgs": "difference in PGS between paired individuals (Δ)",
  "dphenotype": "difference in phenotypes between pairs",
  "pairs": "indices of compared individual pairs"
}

**CONTEXT CODE:** import sys
import json
import io
import math
import argparse
import numpy as np
import pandas as pd
from scipy import special
from scipy.stats import linregress, norm

def load_phenotypes(dataset_directory, subset, phenotype):
	"""
	Loads a file containing the phenotypes of the subset, one phenotype value per line, following the order of the sample list file. Phenotypes are extracted from the UKB phenotype table according to the Data-Field of the specific phenotype
	"""
	file_path = f'{dataset_directory}/subsets/phenotypes_{subset}_{phenotype}.txt'
	return np.array(pd.read_csv(file_path, names=['phenotype'], delimiter=' ', skip_blank_lines=False)['phenotype'])

def load_sample_list(dataset_directory, subset):
	"""
	Loads a list of UKB sample IDs (needs to correspond with sample IDs in PRSice files), the order of which follows that of the phenotype value file
	"""
	file_path = f'{dataset_directory}/subsets/{subset}.txt'
	return np.array(pd.read_csv(file_path, names=['sample_id'], delimiter=' ')['sample_id'])

def load_pgs_scores(dataset_directory, gwas, phenotype, sample_ids):
	"""
	Loads polygenic scores (PGS) for a given phenotype and GWAS from a PRSice output file listing the PGS value per sample
	"""
	file_path = f'{dataset_directory}/prsice/{phenotype}/{gwas}.all_score'
	sample_scores = pd.read_csv(file_path, delimiter=' ', header=0, names=['FID', 'sample_id', 'PGS'], usecols=['sample_id', 'PGS'], index_col='sample_id')
	return np.array(sample_scores.loc[sample_ids]['PGS'])

def perform_regression(pgs_subset, phenotypes_subset):
	"""
	Performs linear regression on non-NaN phenotype and genotype data to infer the r^2 value for the subset
	"""
	valid_indices = ~np.isnan(phenotypes_subset)
	return linregress(pgs_subset[valid_indices], phenotypes_subset[valid_indices])

def generate_pair_comparisons(pgs, sample_ids, phenotypes, first_subset_size=0, unique_samples=0):
	raise NotImplementedError("generate_pair_comparisons function has been masked for testing purposes")

def infer_rbar(dpgs, phenotypic_difference, r_bar_range, r_bar_preset=[], bootstrap_p=0, kappa_bins=51):
	raise NotImplementedError("infer_rbar function has been masked for testing purposes")

def run(params):
	try:
		r_bar_range = np.array(params['r_bar_range'].split(','), dtype=float)
		r_bar_preset = [] if params['r_bar_preset'] == '' else np.array(params['r_bar_preset'].split(','), dtype=float)
	except ValueError as e:
		raise ValueError(f"Error parsing range or preset values: {e}")
	phenotype_values = load_phenotypes(params['dataset_directory'], params['subset'], params['phenotype'])
	sample_ids = load_sample_list(params['dataset_directory'], params['subset'])
	pgs = load_pgs_scores(params['dataset_directory'], params['gwas'], params['phenotype'], sample_ids)
	dpgs, phenotypic_difference, pair_indices = generate_pair_comparisons(pgs, sample_ids, phenotype_values, params['first_subset_size'], params['unique_samples'])
	r_bar, kappa_data, dpgs, dpgs_norm = infer_rbar(dpgs, phenotypic_difference, r_bar_range, r_bar_preset, params['bootstrap'])
	
	return r_bar, kappa_data

def save_results(params, results):
	prefix = params['prefix']
	r_bar, kappa_data = results
	np.savetxt(f'{prefix}_kappa_P.csv', kappa_data['data_points'], delimiter=',', header='kappa,P,n', comments='')
	if params['bootstrap'] == 1:
		with open(f'{prefix}_kappa_P_bootstrap.json', 'w') as file:
			file.write(json.dumps(kappa_data['bootstrap_results']))
	np.savetxt(f'{prefix}_kappa_hist.csv', kappa_data['kappa_hist'], delimiter=',', header='kappa,density', comments='')
	np.savetxt(f'{prefix}_p_hist.csv', kappa_data['p_hist'], delimiter=',', header='P,density', comments='')
	print(f'Best fit r_bar value: {r_bar}')

def setup_parser():
	parser = argparse.ArgumentParser(description='Infer kappa from PRSice data')
	parser.add_argument('--dataset-directory', required=True, help='The directory containing the PRSice results (/prsice) and lists of sample IDs and phenotypes (/subsets)')
	parser.add_argument('--subset', required=True, help='The label of the subset of sample IDs to use')
	parser.add_argument('--gwas', required=True, help='The label of the GWAS that appears in the PRSice result filename')
	parser.add_argument('--phenotype', required=True, help='The label of the phenotype, that appears in the PRSice result filename, and the file containing the phenotypes')
	parser.add_argument('--prefix', required=False, default='ukb_result', help='The prefix of the output files')
	parser.add_argument('--first-subset-size', type=int, required=False, default=0, help='By default we compute all comparisons between samples within the first and second half of the samples separately. This manually sets the point at which to split the subset')
	parser.add_argument('--unique-samples', type=int, required=False, default=0, help='Whether we should use all comparisons or use the order of samples in the subset file (1=use pairs from file)')
	parser.add_argument('--r-bar-range', required=False, default='0.1,0.5', help='A comma-delimited range of \bar{r} values to use for inference')
	parser.add_argument('--r-bar-preset', required=False, default='', help='Instead of inferring \bar{r}, use a pre-defined value')
	parser.add_argument('--bootstrap', required=False, type=int, default=0, help='Whether to run bootstrapping on the P values to generate CIs (1=run bootstrapping)')
	return parser

def main():
	parser = setup_parser()
	params = vars(parser.parse_args())
	results = run(params)
	save_results(params, results)

if __name__ == '__main__':
	main()

# python3 prsice_infer_kappa.py --prefix=eur_height --dataset-directory=../ukbb/data --subset=eur --gwas=EUR-subset --phenotype=height --r-bar-preset=0.43


Complete the function implementation replacing "raise NotImplementedError".