protpy 1.4.0__tar.gz → 1.4.2__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 (35) hide show
  1. {protpy-1.4.0/protpy.egg-info → protpy-1.4.2}/PKG-INFO +5 -4
  2. {protpy-1.4.0 → protpy-1.4.2}/docs/conf.py +1 -1
  3. {protpy-1.4.0 → protpy-1.4.2}/protpy/__init__.py +2 -2
  4. {protpy-1.4.0 → protpy-1.4.2}/protpy/autocorrelation.py +5 -5
  5. {protpy-1.4.0 → protpy-1.4.2}/protpy/composition.py +88 -96
  6. protpy-1.4.2/protpy/encode.py +631 -0
  7. {protpy-1.4.0 → protpy-1.4.2}/protpy/sequence_order.py +18 -12
  8. {protpy-1.4.0 → protpy-1.4.2/protpy.egg-info}/PKG-INFO +5 -4
  9. {protpy-1.4.0 → protpy-1.4.2}/protpy.egg-info/requires.txt +4 -3
  10. {protpy-1.4.0 → protpy-1.4.2}/pyproject.toml +5 -4
  11. {protpy-1.4.0 → protpy-1.4.2}/tests/test_autocorrelation.py +1 -1
  12. {protpy-1.4.0 → protpy-1.4.2}/tests/test_composition.py +12 -12
  13. protpy-1.4.2/tests/test_encode.py +947 -0
  14. {protpy-1.4.0 → protpy-1.4.2}/tests/test_protpy.py +2 -2
  15. protpy-1.4.0/protpy/encode.py +0 -203
  16. protpy-1.4.0/tests/test_encode.py +0 -304
  17. {protpy-1.4.0 → protpy-1.4.2}/LICENSE +0 -0
  18. {protpy-1.4.0 → protpy-1.4.2}/MANIFEST.in +0 -0
  19. {protpy-1.4.0 → protpy-1.4.2}/README.md +0 -0
  20. {protpy-1.4.0 → protpy-1.4.2}/protpy/_constants.py +0 -0
  21. {protpy-1.4.0 → protpy-1.4.2}/protpy/conjoint_triad.py +0 -0
  22. {protpy-1.4.0 → protpy-1.4.2}/protpy/ctd.py +0 -0
  23. {protpy-1.4.0 → protpy-1.4.2}/protpy/data/README.md +0 -0
  24. {protpy-1.4.0 → protpy-1.4.2}/protpy/data/grantham-physicochemical-distance-matrix.json +0 -0
  25. {protpy-1.4.0 → protpy-1.4.2}/protpy/data/schneider-wrede-physicochemical-distance-matrix.json +0 -0
  26. {protpy-1.4.0 → protpy-1.4.2}/protpy/utils.py +0 -0
  27. {protpy-1.4.0 → protpy-1.4.2}/protpy.egg-info/SOURCES.txt +0 -0
  28. {protpy-1.4.0 → protpy-1.4.2}/protpy.egg-info/dependency_links.txt +0 -0
  29. {protpy-1.4.0 → protpy-1.4.2}/protpy.egg-info/top_level.txt +0 -0
  30. {protpy-1.4.0 → protpy-1.4.2}/setup.cfg +0 -0
  31. {protpy-1.4.0 → protpy-1.4.2}/tests/__init__.py +0 -0
  32. {protpy-1.4.0 → protpy-1.4.2}/tests/test_conjoint_triad.py +0 -0
  33. {protpy-1.4.0 → protpy-1.4.2}/tests/test_ctd.py +0 -0
  34. {protpy-1.4.0 → protpy-1.4.2}/tests/test_sequence_order.py +0 -0
  35. {protpy-1.4.0 → protpy-1.4.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: protpy
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: Python package for generating various biochemical, physicochemical and structural descriptors/features of protein sequences.
5
5
  Author-email: AJ McKenna <amckenna41@qub.ac.uk>
6
6
  Maintainer-email: AJ McKenna <amckenna41@qub.ac.uk>
@@ -32,9 +32,10 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
32
  Requires-Python: >=3.9
33
33
  Description-Content-Type: text/markdown
34
34
  License-File: LICENSE
35
- Requires-Dist: aaindex>=1.2.0
36
- Requires-Dist: numpy>=2.4.4
37
- Requires-Dist: pandas>=3.0.2
35
+ Requires-Dist: aaindex>=1.3.1
36
+ Requires-Dist: numpy>=2.0.0
37
+ Requires-Dist: pandas>=2.0.2
38
+ Requires-Dist: tqdm>=4.0.0
38
39
  Requires-Dist: varname>=0.15.1
39
40
  Provides-Extra: test
40
41
  Requires-Dist: pytest; extra == "test"
@@ -13,7 +13,7 @@ sys.path.insert(0, os.path.abspath('..'))
13
13
  project = 'protpy'
14
14
  copyright = '2026, AJ McKenna'
15
15
  author = 'AJ McKenna'
16
- release = '1.4.0'
16
+ release = '1.4.2'
17
17
 
18
18
  # -- General configuration ---------------------------------------------------
19
19
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -4,7 +4,7 @@ from .conjoint_triad import *
4
4
  from .ctd import *
5
5
  from .sequence_order import *
6
6
  from .utils import get_descriptor_info, list_descriptors, print_descriptor_info
7
- from .encode import all_descriptors
7
+ from .encode import all_descriptors, encode_dataset, read_sequences_from_file
8
8
 
9
9
  #canonical amino acids available in the package
10
10
  amino_acids = ["A", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "P",
@@ -12,7 +12,7 @@ amino_acids = ["A", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "P",
12
12
 
13
13
  #protPy package metadata
14
14
  __name__ = 'protpy'
15
- __version__ = "1.4.0"
15
+ __version__ = "1.4.2"
16
16
  __description__ = "Python package for generating various biochemical, physicochemical and structural descriptors/features of protein sequences."
17
17
  __author__ = 'AJ McKenna: https://github.com/amckenna41'
18
18
  __authorEmail__ = 'amckenna41@qub.ac.uk'
@@ -131,10 +131,10 @@ def moreaubroto_autocorrelation(sequence: str, lag: int = 30,
131
131
 
132
132
  #iterate through list of properties, calculating autocorrelation values for the sequence, append to results dict
133
133
  for key in aai_properties:
134
- temp = 0
135
134
  for i in range(1, lag+1):
135
+ temp = 0 # reset per lag
136
136
  for j in range(len(sequence)-i):
137
- temp = temp + aai_properties[key][sequence[j]] * aai_properties[key][sequence[j+1]]
137
+ temp = temp + aai_properties[key][sequence[j]] * aai_properties[key][sequence[j+i]]
138
138
  if (len(sequence) - i == 0):
139
139
  moreaubroto_autocorrelation["MBAuto_" + key + "_" + str(i)] = round(
140
140
  temp / (len(sequence)), 3)
@@ -362,7 +362,7 @@ def geary_autocorrelation(sequence: str, lag: int = 30,
362
362
 
363
363
  def _std(array: list[float], ddof: int = 1) -> float:
364
364
  """
365
- Calculate the standard deviation of the array data, with associated means Delta Degrees
365
+ Calculate the standard deviation of the array data, with associated means Delta Degrees
366
366
  of Freedom (ddof).
367
367
 
368
368
  Parameters
@@ -377,5 +377,5 @@ def _std(array: list[float], ddof: int = 1) -> float:
377
377
  :result: np.array
378
378
  input array after standard deviation transformation.
379
379
  """
380
- return math.sqrt(sum([math.pow(i - sum(array) / len(array), 2) for i in array])
381
- / (len(array) - ddof))
380
+ mean = sum(array) / len(array)
381
+ return math.sqrt(sum(math.pow(v - mean, 2) for v in array) / (len(array) - ddof))
@@ -205,9 +205,10 @@ def tripeptide_composition(sequence: str) -> pd.DataFrame:
205
205
  =======
206
206
  :tripeptide_composition_df: pd.DataFrame
207
207
  pandas DataFrame of tripeptide composition for protein sequence. Dataframe will
208
- be of the shape 1 x 8000, where 8000 is the number of features calculated
209
- from the descriptor (20^3 for the 20 canonical amino acids) and 1 is the
210
- input sequence.
208
+ be of the shape 1 x 8000, where 8000 is the number of features calculated
209
+ from the descriptor (20^3 for the 20 canonical amino acids) and 1 is the
210
+ input sequence. Values are percentages (0–100), consistent with
211
+ dipeptide_composition.
211
212
  """
212
213
  #validate input protein sequence
213
214
  sequence = _validate_sequence(sequence)
@@ -221,9 +222,10 @@ def tripeptide_composition(sequence: str) -> pd.DataFrame:
221
222
  for k in amino_acids:
222
223
  tripeptides.append(i + j + k)
223
224
 
224
- #get frequency of each tripeptide in the sequence
225
+ #get fractional frequency of each tripeptide (percentage), consistent with dipeptide_composition
226
+ total_tripeptides = len(sequence) - 2
225
227
  for i in tripeptides:
226
- tripeptide_composition[i] = len(re.findall(i, sequence))
228
+ tripeptide_composition[i] = round(sequence.count(i) / total_tripeptides * 100, 3) if total_tripeptides > 0 else 0.0
227
229
 
228
230
  #transform values and columns to DataFrame
229
231
  tripeptide_composition_df = pd.DataFrame([list(tripeptide_composition.values())],
@@ -1185,30 +1187,23 @@ def pseudo_amino_acid_composition(sequence: str, lamda: int = 30, weight: float
1185
1187
  raise ValueError(f"Accession number not found in aaindex1: {prop}.")
1186
1188
  property_values.append(aaindex1[prop].values)
1187
1189
 
1188
- right_part = 0.0
1189
1190
  psuedo_aac = {}
1190
- rightpart = []
1191
-
1192
- #calculate correlation factor for protein sequence using propeties
1193
- for i in range(lamda):
1194
- right_part = right_part + sequence_order_correlation_factor(sequence, i+1, property_values)
1195
1191
 
1196
1192
  #calculate amino acid composition
1197
1193
  aa_comp = amino_acid_composition(sequence)
1198
-
1199
- #compute first 20 pseudo amino acid descriptor components based on property_values,
1200
- #append descriptor values to dict
1201
- temp = 1 + weight + right_part
1202
- for index, i in enumerate(amino_acids):
1203
- psuedo_aac["PAAC_" + str(index + 1)] = round(aa_comp[i].values[0] / temp, 3)
1204
1194
 
1205
- #calculate correlation factor for protein sequence using propeties
1206
- for i in range(lamda):
1207
- rightpart.append(sequence_order_correlation_factor(sequence, i + 1, property_values))
1195
+ #compute correlation factors once; reuse for both the first-20 and last-lamda features
1196
+ rightpart = [sequence_order_correlation_factor(sequence, i + 1, property_values)
1197
+ for i in range(lamda)]
1208
1198
 
1209
- #compute last 20+lambda pseudo amino acid descriptor components based on property_values,
1210
- #append descriptor values to dict
1199
+ #shared normalization denominator: 1 + w * Σθ_k (Chou 2001)
1211
1200
  temp = 1 + weight * sum(rightpart)
1201
+
1202
+ #compute first 20 pseudo amino acid descriptor components (weighted AAComp)
1203
+ for index, i in enumerate(amino_acids):
1204
+ psuedo_aac["PAAC_" + str(index + 1)] = round(aa_comp[i].values[0] / temp, 3)
1205
+
1206
+ #compute last lamda pseudo amino acid descriptor components (sequence-order correlations)
1212
1207
  for index in range(20, 20 + lamda):
1213
1208
  psuedo_aac["PAAC_" + str(index + 1)] = round(
1214
1209
  weight * rightpart[index - 20] / temp * 100, 3)
@@ -1293,25 +1288,21 @@ def normalize_property(properties: dict[str, float]) -> dict[str, float]:
1293
1288
  """
1294
1289
  Normalize physicochemical/structural property values using
1295
1290
  their mean and standard deviation.
1296
-
1291
+
1297
1292
  Parameters
1298
1293
  ==========
1299
1294
  :properties: dict
1300
- dictionary of amino acid values for a physicochemical property.
1301
-
1295
+ dictionary of amino acid values for a physicochemical property.
1296
+
1302
1297
  Returns
1303
1298
  =======
1304
1299
  :normalized_vals: dict
1305
1300
  dict of normalized property values.
1306
1301
  """
1307
- normalized_vals = {}
1308
-
1309
- #iterate over all property values, calculate their mean and standard dev
1310
- for i, j in properties.items():
1311
- mean = sum(properties.values()) / len(properties.values())
1312
- normalized_vals[i] = (j - mean) / _std(properties.values(), mean, ddof=0)
1313
-
1314
- return normalized_vals
1302
+ vals = list(properties.values())
1303
+ mean = sum(vals) / len(vals)
1304
+ std = _std(vals, mean, ddof=0)
1305
+ return {aa: (v - mean) / std for aa, v in properties.items()}
1315
1306
 
1316
1307
  def _std(prop: list[float], mean: float, ddof: int = 1) -> float:
1317
1308
  """
@@ -1339,7 +1330,7 @@ def _std(prop: list[float], mean: float, ddof: int = 1) -> float:
1339
1330
  ######################## Amphiphilic Pseudo Amino Acid Composition ########################
1340
1331
 
1341
1332
  def amphiphilic_pseudo_amino_acid_composition(sequence: str, lamda: int = 30, weight: float = 0.5,
1342
- properties: list[dict[str, float]] = [hydrophobicity_, hydrophilicity_]) -> pd.DataFrame:
1333
+ properties: list[dict[str, float]] | None = None) -> pd.DataFrame:
1343
1334
  """
1344
1335
  Amphiphillic pseudo amino acid composition (APAAComp) has the same form as the amino
1345
1336
  acid composition, but contains much more information that is related to the
@@ -1358,59 +1349,59 @@ def amphiphilic_pseudo_amino_acid_composition(sequence: str, lamda: int = 30, we
1358
1349
  rank of correlation. Number of calculable descriptors depends on lambda value.
1359
1350
  :weight: float
1360
1351
  weighting factor.
1361
- :properties: list (default=[hydrophobicity, hydrophilicity])
1362
- list of dicts of physicochemical/structural property values for amino acids.
1352
+ :properties: list[dict] | None (default=None → [hydrophobicity_, hydrophilicity_])
1353
+ list of property dicts mapping each amino acid to a float value.
1354
+ When None the default hydrophobicity and hydrophilicity scales are used.
1363
1355
 
1364
1356
  Returns
1365
- =======
1357
+ =======
1366
1358
  :amp_pseudo_amino_acid_composition_df: pd.Dataframe
1367
- output dataframe of calculated amphiphilic pseudo amino acid composition
1368
- descriptors for input sequence. Dataframe will be of the shape 1 x N, where
1369
- N is the number of features calculated from the descriptor (20 + 2*lambda)
1370
- and 1 is the input sequence. By default, the shape will be 1 x 80
1371
- (using default lamda=30).
1359
+ output dataframe of calculated amphiphilic pseudo amino acid composition
1360
+ descriptors for input sequence. Dataframe will be of the shape 1 x N, where
1361
+ N is 20 + n_props * lamda (n_props = number of properties supplied).
1362
+ With the default two properties and lamda=30 the shape is 1 x 80.
1372
1363
  """
1364
+ if properties is None:
1365
+ properties = [hydrophobicity_, hydrophilicity_]
1366
+
1373
1367
  #validate input protein sequence
1374
1368
  sequence = _validate_sequence(sequence)
1375
1369
 
1376
1370
  #set lamda to its default value of 30 if <0, or > sequence len or not an int
1377
1371
  if ((lamda < 0) or (lamda > len(sequence)) or not isinstance(lamda, int)):
1378
- lamda = 30
1372
+ lamda = 30
1379
1373
 
1380
1374
  #validate weight, set default weight of 0.5 if invalid value input
1381
1375
  if ((weight < 0) or not (isinstance(weight, (float, int)))):
1382
1376
  weight = 0.5
1383
1377
 
1384
- #cast properties to list
1385
- if not (isinstance(properties, list)):
1378
+ #cast properties to list
1379
+ if not isinstance(properties, list):
1386
1380
  properties = [properties]
1387
1381
 
1382
+ n_props = len(properties)
1388
1383
  amp_pseudo_amino_acid_composition = {}
1389
1384
 
1390
- #calculate correlation factor in protein sequence
1391
- rightpart = 0.0
1385
+ #compute all per-lag correlation factors in a single pass:
1386
+ #rightpart = [p0_lag1, p1_lag1, p0_lag2, p1_lag2, ..., p{n-1}_lag{lamda}]
1387
+ rightpart: list[float] = []
1392
1388
  for i in range(lamda):
1393
- rightpart = rightpart + sum(
1394
- amphiphilic_sequence_order_correlation_factor(sequence, k=i + 1))
1395
-
1389
+ rightpart.extend(
1390
+ amphiphilic_sequence_order_correlation_factor(sequence, k=i + 1, properties=properties))
1391
+
1396
1392
  #calculate amino acid composition
1397
1393
  aa_composition = amino_acid_composition(sequence)
1398
1394
 
1399
- #compute first 20 pseudo amino acid descriptor components based on properties
1400
- temp = 1 + weight * rightpart
1401
- for index, i in enumerate(amino_acids):
1402
- amp_pseudo_amino_acid_composition["APAAC_" + str(index + 1)] = round(aa_composition[i].values[0] / temp, 3)
1395
+ #shared normalization denominator: 1 + w * Σ(all correlation factors)
1396
+ temp = 1 + weight * sum(rightpart)
1403
1397
 
1404
- #calculate correlation factor in protein sequence
1405
- rightpart = []
1406
- for i in range(lamda):
1407
- temp = amphiphilic_sequence_order_correlation_factor(sequence, k=i + 1)
1408
- rightpart.append(temp[0])
1409
- rightpart.append(temp[1])
1398
+ #compute first 20 pseudo amino acid descriptor components (weighted AAComp)
1399
+ for index, i in enumerate(amino_acids):
1400
+ amp_pseudo_amino_acid_composition["APAAC_" + str(index + 1)] = round(
1401
+ aa_composition[i].values[0] / temp, 3)
1410
1402
 
1411
- #compute remaining (20 + 2 * lamda) amphiphillic composition values
1412
- temp = 1 + weight * sum(rightpart)
1413
- for index in range(20, 20 + 2 * lamda):
1403
+ #compute remaining n_props * lamda amphiphilic composition values
1404
+ for index in range(20, 20 + n_props * lamda):
1414
1405
  amp_pseudo_amino_acid_composition["APAAC_" + str(index + 1)] = round(
1415
1406
  weight * rightpart[index - 20] / temp * 100, 3)
1416
1407
 
@@ -1420,9 +1411,10 @@ def amphiphilic_pseudo_amino_acid_composition(sequence: str, lamda: int = 30, we
1420
1411
 
1421
1412
  return amp_pseudo_amino_acid_composition_df
1422
1413
 
1423
- def amphiphilic_sequence_order_correlation_factor(sequence: str, k: int = 1) -> list[float]:
1424
- """
1425
- Calculate Amphipillic sequence order correlation factor for sequence
1414
+ def amphiphilic_sequence_order_correlation_factor(sequence: str, k: int = 1,
1415
+ properties: list[dict[str, float]] | None = None) -> list[float]:
1416
+ """
1417
+ Calculate Amphiphilic sequence order correlation factor for sequence
1426
1418
  with gap=k.
1427
1419
 
1428
1420
  Parameters
@@ -1431,34 +1423,36 @@ def amphiphilic_sequence_order_correlation_factor(sequence: str, k: int = 1) ->
1431
1423
  protein sequence.
1432
1424
  :k: int (default=1)
1433
1425
  gap between amino acids in the sequence.
1426
+ :properties: list[dict] | None (default=None → [hydrophobicity_, hydrophilicity_])
1427
+ list of property dicts. Pre-normalized once per call.
1434
1428
 
1435
1429
  Returns
1436
1430
  =======
1437
- :correlation_factor: list
1438
- list of correlation factors for both hydrophobicity and hydrophillicty.
1431
+ :correlation_factor: list[float]
1432
+ one correlation factor per property.
1439
1433
  """
1440
- correlation_factor_hydrophobicity = []
1441
- correlation_factor_hydrophilicity = []
1434
+ if properties is None:
1435
+ properties = [hydrophobicity_, hydrophilicity_]
1442
1436
 
1443
- #iterate over sequence, calculating correlation factors using both properties
1444
- for i in range(len(sequence) - k):
1445
- aa1 = sequence[i]
1446
- aa2 = sequence[i + k]
1447
- corelation_function = amphiphilic_correllation_function(aa1, aa2)
1448
- correlation_factor_hydrophobicity.append(corelation_function[0])
1449
- correlation_factor_hydrophilicity.append(corelation_function[1])
1437
+ #pre-normalize all properties once rather than inside every pair evaluation
1438
+ normalized_props = [normalize_property(prop) for prop in properties]
1439
+ n_props = len(properties)
1440
+ accumulators: list[list[float]] = [[] for _ in range(n_props)]
1450
1441
 
1451
- #append hydrophobicity and hydrophilicity values to array
1452
- correlation_factor = []
1453
- correlation_factor.append(round(sum(correlation_factor_hydrophobicity) / (len(sequence) - k), 3))
1454
- correlation_factor.append(round(sum(correlation_factor_hydrophilicity) / (len(sequence) - k), 3))
1442
+ #iterate over sequence pairs with the given gap k
1443
+ for i in range(len(sequence) - k):
1444
+ aa1, aa2 = sequence[i], sequence[i + k]
1445
+ for p_idx, norm in enumerate(normalized_props):
1446
+ accumulators[p_idx].append(round(norm[aa1] * norm[aa2], 3))
1455
1447
 
1456
- return correlation_factor
1448
+ denom = len(sequence) - k
1449
+ return [round(sum(acc) / denom, 3) for acc in accumulators]
1457
1450
 
1458
- def amphiphilic_correllation_function(Ri: str = "S", Rj: str = "D") -> tuple[float, float]:
1451
+ def amphiphilic_correllation_function(Ri: str = "S", Rj: str = "D",
1452
+ normalized_props: list[dict[str, float]] | None = None) -> list[float]:
1459
1453
  """
1460
- Calculate correlation value based on hydrophobicity and hydrophillicity
1461
- property values for input amino acids Ri and Rj in sequence.
1454
+ Calculate correlation value based on physicochemical property values
1455
+ for input amino acids Ri and Rj.
1462
1456
 
1463
1457
  Parameters
1464
1458
  ==========
@@ -1466,18 +1460,16 @@ def amphiphilic_correllation_function(Ri: str = "S", Rj: str = "D") -> tuple[flo
1466
1460
  1st amino acid.
1467
1461
  :Rj: str
1468
1462
  2nd amino acid.
1463
+ :normalized_props: list[dict] | None
1464
+ pre-normalized property dicts. Defaults to normalized hydrophobicity
1465
+ and hydrophilicity when None.
1469
1466
 
1470
1467
  Returns
1471
1468
  =======
1472
- :theta1, theta2: float
1473
- correlation values for input property values.
1469
+ :thetas: list[float]
1470
+ one correlation value per property.
1474
1471
  """
1475
- #normalize properties
1476
- _hydrophobicity = normalize_property(hydrophobicity_)
1477
- _hydrophilicity = normalize_property(hydrophilicity_)
1478
-
1479
- #calculate correlation using hydrophobicity & hydrophilicty properties
1480
- theta1 = round(_hydrophobicity[Ri] * _hydrophobicity[Rj], 3)
1481
- theta2 = round(_hydrophilicity[Ri] * _hydrophilicity[Rj], 3)
1482
-
1483
- return theta1, theta2
1472
+ if normalized_props is None:
1473
+ normalized_props = [normalize_property(hydrophobicity_),
1474
+ normalize_property(hydrophilicity_)]
1475
+ return [round(prop[Ri] * prop[Rj], 3) for prop in normalized_props]