G2PInsight 1.1.2__tar.gz → 1.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/__init__.py +1 -1
  2. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/modeltraining.py +24 -12
  3. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/plink_ld.py +2 -2
  4. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/preprocess.py +18 -0
  5. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight.egg-info/PKG-INFO +17 -9
  6. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight.egg-info/requires.txt +1 -1
  7. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/PKG-INFO +17 -9
  8. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/README.md +15 -7
  9. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/pyproject.toml +3 -2
  10. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/__init__.py +0 -0
  11. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/font_utils.py +0 -0
  12. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/gemma_gwas.py +0 -0
  13. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/software/gemma-0.98.5-linux-static-AMD64 +0 -0
  14. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/software/plink +0 -0
  15. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/bin/visualization.py +0 -0
  16. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight/main.py +0 -0
  17. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight.egg-info/SOURCES.txt +0 -0
  18. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight.egg-info/dependency_links.txt +0 -0
  19. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight.egg-info/entry_points.txt +0 -0
  20. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/G2PInsight.egg-info/top_level.txt +0 -0
  21. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/LICENSE +0 -0
  22. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/MANIFEST.in +0 -0
  23. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/setup.cfg +0 -0
  24. {g2pinsight-1.1.2 → g2pinsight-1.1.4}/setup.py +0 -0
@@ -1,3 +1,3 @@
1
- __version__ = '1.1.2'
1
+ __version__ = '1.1.4'
2
2
  __author__ = 'chenrf'
3
3
  __email__ = '12024128035@stu.ynu.edu.cn'
@@ -848,7 +848,7 @@ def resolve_training_hyperparameters(model_type: str, task_type: str, X_train: p
848
848
  scoring = 'neg_mean_squared_error'
849
849
  base_model = init_model(model_type, task_type, random_state=random_state, cpu_cores=cpu_cores)
850
850
  search = RandomizedSearchCV(estimator=base_model, param_distributions=param_grid, n_iter=n_iter, cv=cv_splitter, scoring=scoring, n_jobs=DEFAULT_N_JOBS, random_state=random_state, verbose=0)
851
- search.fit(X_search, y_search)
851
+ search.fit(_features_for_estimator(model_type, X_search), y_search)
852
852
  tuned_model = search.best_estimator_
853
853
  return (tuned_model, tuned_model.get_params())
854
854
  TRAIN_TEST_HOLDOUT_RATIO = 0.20
@@ -907,16 +907,25 @@ def resolve_holdout_split_from_metadata(X: pd.DataFrame, y: pd.Series, metadata:
907
907
  return holdout_from_sample_split(X, y, sample_split)
908
908
  logger.warning('Metadata missing sample_split; falling back to local reproducible 80/20 split. Re-run preprocess to fix the split at feature-selection time.')
909
909
  return split_train_test_holdout(X, y, task_type=task_type, test_ratio=TRAIN_TEST_HOLDOUT_RATIO, random_state=random_state)
910
+ def _is_catboost_model(model: Any) -> bool:
911
+ return isinstance(model, (CatBoostClassifier, CatBoostRegressor))
912
+ def _features_for_estimator(model_or_type: Any, X: Any) -> Any:
913
+ """CatBoost+pandas2: old CatBoost calls DataFrame.iteritems (removed); use ndarray."""
914
+ use_numpy = model_or_type == 'CatBoost' if isinstance(model_or_type, str) else _is_catboost_model(model_or_type)
915
+ if use_numpy and isinstance(X, (pd.DataFrame, pd.Series)):
916
+ return np.asarray(X)
917
+ return X
910
918
  def _predict_with_optional_proba(model: Any, X: pd.DataFrame, task_type: str) -> Tuple[np.ndarray, Optional[np.ndarray]]:
911
- y_pred = model.predict(X)
919
+ X_in = _features_for_estimator(model, X)
920
+ y_pred = model.predict(X_in)
912
921
  y_prob = None
913
922
  if task_type != 'classification':
914
923
  return (y_pred, None)
915
924
  try:
916
925
  if hasattr(model, 'predict_proba'):
917
- y_prob = model.predict_proba(X)
926
+ y_prob = model.predict_proba(X_in)
918
927
  elif hasattr(model, 'decision_function'):
919
- decision_scores = model.decision_function(X)
928
+ decision_scores = model.decision_function(X_in)
920
929
  from sklearn.utils.extmath import softmax
921
930
  if len(decision_scores.shape) == 1:
922
931
  prob_neg = 1 / (1 + np.exp(decision_scores))
@@ -933,7 +942,7 @@ def _fit_model_with_params(model_type: str, task_type: str, X_train: pd.DataFram
933
942
  model.set_params(**best_params)
934
943
  except ValueError as e:
935
944
  pass
936
- model.fit(X_train, y_train)
945
+ model.fit(_features_for_estimator(model_type, X_train), y_train)
937
946
  return model
938
947
  def evaluate_model(y_true: pd.Series, y_pred: np.ndarray, y_prob: np.ndarray, task_type: str) -> Dict:
939
948
  metrics = {}
@@ -1091,14 +1100,16 @@ def _run_one_cv_fold(fold_idx: int, n_folds: int, train_idx: np.ndarray, val_idx
1091
1100
  y_pred_fold = None
1092
1101
  y_prob_fold = None
1093
1102
  try:
1094
- model_fold.fit(X_train_fold, y_train_fold)
1095
- y_pred_fold = model_fold.predict(X_val_fold)
1103
+ X_tr = _features_for_estimator(model_type, X_train_fold)
1104
+ X_va = _features_for_estimator(model_type, X_val_fold)
1105
+ model_fold.fit(X_tr, y_train_fold)
1106
+ y_pred_fold = model_fold.predict(X_va)
1096
1107
  if task_type == 'classification':
1097
1108
  try:
1098
1109
  if hasattr(model_fold, 'predict_proba'):
1099
- y_prob_fold = model_fold.predict_proba(X_val_fold)
1110
+ y_prob_fold = model_fold.predict_proba(X_va)
1100
1111
  elif hasattr(model_fold, 'decision_function'):
1101
- decision_scores = model_fold.decision_function(X_val_fold)
1112
+ decision_scores = model_fold.decision_function(X_va)
1102
1113
  from sklearn.utils.extmath import softmax
1103
1114
  if len(decision_scores.shape) == 1:
1104
1115
  prob_neg = 1 / (1 + np.exp(decision_scores))
@@ -1279,7 +1290,7 @@ def calculate_shap_values(model: Any, model_type: str, feature_names: List[str],
1279
1290
  y_shap = y_shap.loc[X_input.index]
1280
1291
  if model_type in ['LightGBM', 'XGBoost', 'CatBoost', 'RandomForest']:
1281
1292
  explainer = shap.TreeExplainer(model)
1282
- shap_values = explainer.shap_values(X_input)
1293
+ shap_values = explainer.shap_values(_features_for_estimator(model_type, X_input))
1283
1294
  elif model_type == 'Logistic':
1284
1295
  explainer = shap.LinearExplainer(model, X_input)
1285
1296
  shap_values = explainer.shap_values(X_input)
@@ -2008,8 +2019,9 @@ def predict_with_model(input_path: str, model_path: str, output_dir: str, task_t
2008
2019
  non_zero_counts = (X_aligned != 0).sum(axis=1)
2009
2020
  if (non_zero_counts == 0).all():
2010
2021
  logger.error(f' ERROR: All feature values are zero! This will result in constant predictions.\n Matched features: {matched_count}\n Missing features: {missing_count}\n Please check if chr_pos keys match between training and prediction data.')
2011
- y_pred = model.predict(X_aligned)
2012
- y_prob = model.predict_proba(X_aligned) if resolved_task_type == 'classification' and hasattr(model, 'predict_proba') else None
2022
+ X_pred = _features_for_estimator(model, X_aligned)
2023
+ y_pred = model.predict(X_pred)
2024
+ y_prob = model.predict_proba(X_pred) if resolved_task_type == 'classification' and hasattr(model, 'predict_proba') else None
2013
2025
  unique_predictions = len(np.unique(y_pred))
2014
2026
  if unique_predictions == 1:
2015
2027
  logger.error(f" ERROR: All predictions are the same value: {y_pred[0]}\n This usually indicates one of the following issues:\n 1. chr_pos keys don't match between training and prediction data\n 2. All feature values are zero (check matched features: {matched_count})\n 3. Model is predicting a constant value for all samples\n Please check the feature alignment logs above.")
@@ -161,9 +161,9 @@ def run_ld_filtering(input_path: str, output_prefix: str, ld_window_kb: int=50,
161
161
  return 1
162
162
  if not check_prune_file_exists(output_prefix):
163
163
  return 1
164
+ # Prune may use --keep (e.g. train-only LD), but the final bed must keep
165
+ # all input samples so held-out test IDs remain in the training matrix.
164
166
  extract_args = input_args + ['--extract', f'{output_prefix_abs}.prune.in', '--make-bed', '--allow-extra-chr', '--allow-no-sex', '--threads', str(threads), '--out', output_prefix_abs]
165
- if keep_samples_file:
166
- extract_args.extend(['--keep', keep_samples_file])
167
167
  if not run_plink_command(plink_executable, extract_args, 'Extracting SNPs to generate bed/bim/fam'):
168
168
  return 1
169
169
  bed_file = Path(f'{output_prefix_abs}.bed')
@@ -1019,6 +1019,23 @@ def _validate_ids_file_pair(train_ids_file: Optional[str], test_ids_file: Option
1019
1019
  has_test = test_ids_file is not None
1020
1020
  if has_train ^ has_test:
1021
1021
  raise ValueError('Both --train-ids-file and --test-ids-file must be provided together')
1022
+ def _reconcile_sample_split_with_matrix(sample_split: Dict[str, Any], matrix_sample_ids: List[str]) -> Dict[str, Any]:
1023
+ """Keep sample_split IDs that actually appear in the exported training matrix."""
1024
+ matrix_set = {str(s) for s in matrix_sample_ids}
1025
+ train_ids = [str(s) for s in sample_split.get('train_ids') or [] if str(s) in matrix_set]
1026
+ test_ids = [str(s) for s in sample_split.get('test_ids') or [] if str(s) in matrix_set]
1027
+ dropped_train = len(sample_split.get('train_ids') or []) - len(train_ids)
1028
+ dropped_test = len(sample_split.get('test_ids') or []) - len(test_ids)
1029
+ if dropped_train or dropped_test:
1030
+ logger.warning(f'sample_split vs matrix: dropped {dropped_train} train / {dropped_test} test ID(s) absent from the genotype matrix')
1031
+ if not train_ids or not test_ids:
1032
+ raise RuntimeError(f'After building the training matrix, sample_split is invalid (n_train={len(train_ids)}, n_test={len(test_ids)}). Re-run preprocess; if using -f 3/4, ensure LD export keeps all samples.')
1033
+ out = dict(sample_split)
1034
+ out['train_ids'] = train_ids
1035
+ out['test_ids'] = test_ids
1036
+ out['n_train'] = len(train_ids)
1037
+ out['n_test'] = len(test_ids)
1038
+ return out
1022
1039
  def resolve_sample_split(sample_ids: List[str], pheno_df: pd.DataFrame, task_type: str, train_ids_file: Optional[str]=None, test_ids_file: Optional[str]=None, test_ratio: float=TRAIN_TEST_HOLDOUT_RATIO, random_state: int=DEFAULT_SPLIT_RANDOM_STATE) -> Dict[str, Any]:
1023
1040
  _validate_ids_file_pair(train_ids_file, test_ids_file)
1024
1041
  sample_ids_str = [str(s) for s in sample_ids]
@@ -1247,6 +1264,7 @@ def run_preprocess(genotype_path: str, genotype_format: GenotypeFormat, phenotyp
1247
1264
  actual_train_file = matrix_output.train_file
1248
1265
  includes_phenotype_column = matrix_output.includes_phenotype_column
1249
1266
  n_snp_features = matrix_output.n_snp_features
1267
+ sample_split = _reconcile_sample_split_with_matrix(sample_split, matrix_output.sample_ids)
1250
1268
  generate_metadata(output_prefix=str(stage_output_dir / output_prefix), plink_prefix=gwas_genotype_prefix, train_file=actual_train_file, valid_samples=matrix_output.sample_ids, genotype_format=genotype_format, task_type=task_type, preprocess_tmp_dir=tmp_dir, filter_snps=filter_snps, feature_selection_mode=feature_selection_mode, gwas_pvalue=gwas_pvalue, ld_window_kb=ld_window_kb, ld_window=ld_window, ld_window_r2=ld_window_r2, n_feature_columns=n_snp_features, includes_phenotype_column=includes_phenotype_column, sample_split=sample_split)
1251
1269
  logger.info(f'Preprocess completed: {len(matrix_output.sample_ids):,} samples × {n_snp_features:,} SNPs (mode={feature_selection_mode}, split={sample_split["mode"]})')
1252
1270
  gc.collect()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: G2PInsight
3
- Version: 1.1.2
3
+ Version: 1.1.4
4
4
  Summary: Genome-wide association analysis toolkit
5
5
  Author-email: chenrf <2010288571@qq.com>
6
6
  License: MIT
@@ -38,7 +38,7 @@ Requires-Dist: lightgbm<4.0.0,>=3.3; python_version < "3.13"
38
38
  Requires-Dist: lightgbm>=4.0; python_version >= "3.13"
39
39
  Requires-Dist: xgboost<2.1,>=1.6; python_version < "3.13"
40
40
  Requires-Dist: xgboost>=2.1; python_version >= "3.13"
41
- Requires-Dist: catboost<2.0,>=1.0
41
+ Requires-Dist: catboost<2.0,>=1.2
42
42
  Requires-Dist: shap>=0.40; python_version < "3.13"
43
43
  Requires-Dist: shap>=0.48; python_version >= "3.13"
44
44
  Requires-Dist: plotly>=5.0
@@ -183,26 +183,26 @@ wget -r -np -nH --cut-dirs=1 -R "index.html*" https://pr-nxy.ynu.edu.cn/G2PInsig
183
183
  **Alternative — `git clone`:** the same files are in the GitHub repo under `data/` (~53 MB VCF; clone may be slow on some networks).
184
184
 
185
185
  ```bash
186
- # 1. Preprocess
186
+ # 1. Preprocess → test/preprocess/preprocess/preprocess_metadata.json
187
187
  G2PInsight preprocess --vcf data/genotype.vcf -p data/pheno.txt -o test/preprocess
188
188
  ```
189
189
  ```bash
190
- # 2. Train (check metadata exists first)
190
+ # 2. Train → test/train/train/LightGBM/
191
191
  G2PInsight train -j test/preprocess/preprocess/preprocess_metadata.json -m LightGBM -o test/train
192
192
  ```
193
193
  ```bash
194
- # 3. Visualize
194
+ # 3. Visualize → test/plot/visualize/lightgbm_*
195
195
  G2PInsight visualize \
196
- -i test/train/LightGBM/LightGBM_shap_values.txt \
197
- -I test/train/LightGBM/LightGBM_plotting_data.json \
198
- -o results/plot/lightgbm
196
+ -i test/train/train/LightGBM/LightGBM_shap_values.txt \
197
+ -I test/train/train/LightGBM/LightGBM_plotting_data.json \
198
+ -o test/plot/lightgbm
199
199
  ```
200
200
 
201
201
  **Larger SNP sets** — use preprocess feature selection (`-f 4`), then train conservatively:
202
202
 
203
203
  ```bash
204
204
  G2PInsight preprocess --vcf data/genotype.vcf -p data/pheno.txt -o test/preprocess -f 4
205
- G2PInsight train-all -j test/preprocess/preprocess/preprocess_metadata.json -o test/train/ \
205
+ G2PInsight train-all -j test/preprocess/preprocess/preprocess_metadata.json -o test/train \
206
206
  --parallel_models 1 --threads 4
207
207
  ```
208
208
 
@@ -535,6 +535,14 @@ Default is `--shap_dependence_top 50`. Use `0` only if you need all SNPs (can be
535
535
 
536
536
  Your env has an old `bed-reader` (0.2.x). Upgrade: `pip install -U 'bed-reader>=1.0'`. Current G2PInsight also accepts the older `fam_filepath` API as a fallback.
537
537
 
538
+ ### train / train-all: test IDs from metadata missing in matrix
539
+
540
+ Usually from an older preprocess with **`-f 3` / `-f 4`**: LD used train-only `--keep` and the final `.bed` dropped test samples while metadata still listed them. Fixed in current source — **re-run preprocess**, then train again.
541
+
542
+ ### train-all / CatBoost: `DataFrame` has no attribute `iteritems`
543
+
544
+ Old CatBoost + **pandas 2.x** (removed `iteritems`). Current G2PInsight passes numpy arrays into CatBoost. Temporary workaround: `pip install -U 'catboost>=1.2,<2'` or `pip install 'pandas>=1.3,<2'`.
545
+
538
546
  ### train: XGBoost “Mismatched version … Python package … Shared object”
539
547
 
540
548
  Usually **conda + pip mixed installs**: e.g. conda left `libxgboost.so` 2.0.x while pip upgraded the Python package to 3.x. Fix in the same env:
@@ -2,7 +2,7 @@ scikit-learn>=1.0
2
2
  joblib>=1.0
3
3
  matplotlib>=3.5
4
4
  Pillow<12.3,>=8
5
- catboost<2.0,>=1.0
5
+ catboost<2.0,>=1.2
6
6
  plotly>=5.0
7
7
  kaleido<1,>=0.2
8
8
  seaborn>=0.11
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: G2PInsight
3
- Version: 1.1.2
3
+ Version: 1.1.4
4
4
  Summary: Genome-wide association analysis toolkit
5
5
  Author-email: chenrf <2010288571@qq.com>
6
6
  License: MIT
@@ -38,7 +38,7 @@ Requires-Dist: lightgbm<4.0.0,>=3.3; python_version < "3.13"
38
38
  Requires-Dist: lightgbm>=4.0; python_version >= "3.13"
39
39
  Requires-Dist: xgboost<2.1,>=1.6; python_version < "3.13"
40
40
  Requires-Dist: xgboost>=2.1; python_version >= "3.13"
41
- Requires-Dist: catboost<2.0,>=1.0
41
+ Requires-Dist: catboost<2.0,>=1.2
42
42
  Requires-Dist: shap>=0.40; python_version < "3.13"
43
43
  Requires-Dist: shap>=0.48; python_version >= "3.13"
44
44
  Requires-Dist: plotly>=5.0
@@ -183,26 +183,26 @@ wget -r -np -nH --cut-dirs=1 -R "index.html*" https://pr-nxy.ynu.edu.cn/G2PInsig
183
183
  **Alternative — `git clone`:** the same files are in the GitHub repo under `data/` (~53 MB VCF; clone may be slow on some networks).
184
184
 
185
185
  ```bash
186
- # 1. Preprocess
186
+ # 1. Preprocess → test/preprocess/preprocess/preprocess_metadata.json
187
187
  G2PInsight preprocess --vcf data/genotype.vcf -p data/pheno.txt -o test/preprocess
188
188
  ```
189
189
  ```bash
190
- # 2. Train (check metadata exists first)
190
+ # 2. Train → test/train/train/LightGBM/
191
191
  G2PInsight train -j test/preprocess/preprocess/preprocess_metadata.json -m LightGBM -o test/train
192
192
  ```
193
193
  ```bash
194
- # 3. Visualize
194
+ # 3. Visualize → test/plot/visualize/lightgbm_*
195
195
  G2PInsight visualize \
196
- -i test/train/LightGBM/LightGBM_shap_values.txt \
197
- -I test/train/LightGBM/LightGBM_plotting_data.json \
198
- -o results/plot/lightgbm
196
+ -i test/train/train/LightGBM/LightGBM_shap_values.txt \
197
+ -I test/train/train/LightGBM/LightGBM_plotting_data.json \
198
+ -o test/plot/lightgbm
199
199
  ```
200
200
 
201
201
  **Larger SNP sets** — use preprocess feature selection (`-f 4`), then train conservatively:
202
202
 
203
203
  ```bash
204
204
  G2PInsight preprocess --vcf data/genotype.vcf -p data/pheno.txt -o test/preprocess -f 4
205
- G2PInsight train-all -j test/preprocess/preprocess/preprocess_metadata.json -o test/train/ \
205
+ G2PInsight train-all -j test/preprocess/preprocess/preprocess_metadata.json -o test/train \
206
206
  --parallel_models 1 --threads 4
207
207
  ```
208
208
 
@@ -535,6 +535,14 @@ Default is `--shap_dependence_top 50`. Use `0` only if you need all SNPs (can be
535
535
 
536
536
  Your env has an old `bed-reader` (0.2.x). Upgrade: `pip install -U 'bed-reader>=1.0'`. Current G2PInsight also accepts the older `fam_filepath` API as a fallback.
537
537
 
538
+ ### train / train-all: test IDs from metadata missing in matrix
539
+
540
+ Usually from an older preprocess with **`-f 3` / `-f 4`**: LD used train-only `--keep` and the final `.bed` dropped test samples while metadata still listed them. Fixed in current source — **re-run preprocess**, then train again.
541
+
542
+ ### train-all / CatBoost: `DataFrame` has no attribute `iteritems`
543
+
544
+ Old CatBoost + **pandas 2.x** (removed `iteritems`). Current G2PInsight passes numpy arrays into CatBoost. Temporary workaround: `pip install -U 'catboost>=1.2,<2'` or `pip install 'pandas>=1.3,<2'`.
545
+
538
546
  ### train: XGBoost “Mismatched version … Python package … Shared object”
539
547
 
540
548
  Usually **conda + pip mixed installs**: e.g. conda left `libxgboost.so` 2.0.x while pip upgraded the Python package to 3.x. Fix in the same env:
@@ -134,26 +134,26 @@ wget -r -np -nH --cut-dirs=1 -R "index.html*" https://pr-nxy.ynu.edu.cn/G2PInsig
134
134
  **Alternative — `git clone`:** the same files are in the GitHub repo under `data/` (~53 MB VCF; clone may be slow on some networks).
135
135
 
136
136
  ```bash
137
- # 1. Preprocess
137
+ # 1. Preprocess → test/preprocess/preprocess/preprocess_metadata.json
138
138
  G2PInsight preprocess --vcf data/genotype.vcf -p data/pheno.txt -o test/preprocess
139
139
  ```
140
140
  ```bash
141
- # 2. Train (check metadata exists first)
141
+ # 2. Train → test/train/train/LightGBM/
142
142
  G2PInsight train -j test/preprocess/preprocess/preprocess_metadata.json -m LightGBM -o test/train
143
143
  ```
144
144
  ```bash
145
- # 3. Visualize
145
+ # 3. Visualize → test/plot/visualize/lightgbm_*
146
146
  G2PInsight visualize \
147
- -i test/train/LightGBM/LightGBM_shap_values.txt \
148
- -I test/train/LightGBM/LightGBM_plotting_data.json \
149
- -o results/plot/lightgbm
147
+ -i test/train/train/LightGBM/LightGBM_shap_values.txt \
148
+ -I test/train/train/LightGBM/LightGBM_plotting_data.json \
149
+ -o test/plot/lightgbm
150
150
  ```
151
151
 
152
152
  **Larger SNP sets** — use preprocess feature selection (`-f 4`), then train conservatively:
153
153
 
154
154
  ```bash
155
155
  G2PInsight preprocess --vcf data/genotype.vcf -p data/pheno.txt -o test/preprocess -f 4
156
- G2PInsight train-all -j test/preprocess/preprocess/preprocess_metadata.json -o test/train/ \
156
+ G2PInsight train-all -j test/preprocess/preprocess/preprocess_metadata.json -o test/train \
157
157
  --parallel_models 1 --threads 4
158
158
  ```
159
159
 
@@ -486,6 +486,14 @@ Default is `--shap_dependence_top 50`. Use `0` only if you need all SNPs (can be
486
486
 
487
487
  Your env has an old `bed-reader` (0.2.x). Upgrade: `pip install -U 'bed-reader>=1.0'`. Current G2PInsight also accepts the older `fam_filepath` API as a fallback.
488
488
 
489
+ ### train / train-all: test IDs from metadata missing in matrix
490
+
491
+ Usually from an older preprocess with **`-f 3` / `-f 4`**: LD used train-only `--keep` and the final `.bed` dropped test samples while metadata still listed them. Fixed in current source — **re-run preprocess**, then train again.
492
+
493
+ ### train-all / CatBoost: `DataFrame` has no attribute `iteritems`
494
+
495
+ Old CatBoost + **pandas 2.x** (removed `iteritems`). Current G2PInsight passes numpy arrays into CatBoost. Temporary workaround: `pip install -U 'catboost>=1.2,<2'` or `pip install 'pandas>=1.3,<2'`.
496
+
489
497
  ### train: XGBoost “Mismatched version … Python package … Shared object”
490
498
 
491
499
  Usually **conda + pip mixed installs**: e.g. conda left `libxgboost.so` 2.0.x while pip upgraded the Python package to 3.x. Fix in the same env:
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "G2PInsight"
10
- version = "1.1.2"
10
+ version = "1.1.4"
11
11
  description = "Genome-wide association analysis toolkit"
12
12
  readme = "README.md"
13
13
  # Cap below 3.14: pandas/numpy for 3.14+ only ship manylinux_2_24+ wheels.
@@ -61,7 +61,8 @@ dependencies = [
61
61
  "lightgbm>=4.0; python_version >= '3.13'",
62
62
  "xgboost>=1.6,<2.1; python_version < '3.13'",
63
63
  "xgboost>=2.1; python_version >= '3.13'",
64
- "catboost>=1.0,<2.0",
64
+ # >=1.2: pandas 2.x removed DataFrame.iteritems; older CatBoost still calls it.
65
+ "catboost>=1.2,<2.0",
65
66
  "shap>=0.40; python_version < '3.13'",
66
67
  "shap>=0.48; python_version >= '3.13'",
67
68
  "plotly>=5.0",
File without changes
File without changes
File without changes
File without changes