SequenceFeature.kmer_composition
- SequenceFeature.kmer_composition(df_seq, k=1, list_parts=None, return_df=False, return_scales=False)[source]
Create the k-mer-composition (k-mer) baseline matrix for given sequences.
Builds the no-positional-split k-mer-composition baseline featurization: for each sequence the requested Parts are concatenated into one span and the fraction of each of the
20 ** kordered overlapping k-mers of adjacent canonical residues is computed, yielding the(n_seq, 20 ** k)matrixX. Columns are all length-kamino-acid strings inut.LIST_CANONICAL_AAorder (itertools.productorder:A, C, ..., Yfork=1;AA, AC, ..., YYfork=2; …) so column order is stable, and each row with at leastkcanonical residues sums to 1.k=1is amino-acid composition (AAC, identical toaa_composition()) andk=2dipeptide composition (DPC, identical todipeptide_composition()); higherkcaptures longer local sequential order. UnlikeSequenceFeature.feature_matrix(), which averages scales over a specific Part-Split, this method carries no positional information — it is a plain k-mer frequency count.Application. Use this to build a baseline feature set for a prediction model and compare it against a
CPPfeature_matrix()(the “composition baseline vs CPP” comparison), quantifying how much the positional Part-Split-Scale features add over a plain k-mer frequency encoding. Largerkencodes more local order at the cost of a20 ** k-wide, sparser matrix — reach forCPPwhen you need where-along-the-sequence information.Compositional descriptors (iFeature parity). These non-positional, fixed-length residue-frequency vectors are the classic composition descriptors of tools such as iFeature [Chen18]. The supported approaches:
AAC (amino-acid composition,
k=1) — the fraction of each of the 20 amino acids (20-D). The simplest composition; captures which residues, not order.DPC (dipeptide composition,
k=2) — the fraction of each ordered adjacent pair (400-D). Adds local sequential order (which residue follows which).k-mer (
k >= 3) — the general20 ** k-D extension to longer motifs; grows exponentially and sparsifies quickly, so it is most reliable at lowk.
Other iFeature-style descriptors (CTD — composition/transition/distribution of physicochemical groups, PAAC — pseudo amino-acid composition, DDE, …) are the natural follow-ups to complete the family. To turn any of these into a
CPPdf_feat(AAC positional; DPC/k-mer non-positional), seeCPP.run_composit().Added in version 1.1.0.
- Parameters:
df_seq (pd.DataFrame, shape (n_samples, n_seq_info)) – DataFrame containing an
entrycolumn with unique protein identifiers and sequence information in a distinct format: Position-based, Part-based, Sequence-based, or Sequence-TMD-based (the same input accepted bySequenceFeature.get_df_parts()).k (int, default=1) – k-mer length (
>= 1).1gives amino-acid composition (AAC, 20 columns),2the dipeptide composition (DPC, 400 columns),3tripeptides (8000),4tetrapeptides (160000). Capped at4because the20 ** kcolumn count grows exponentially.list_parts (str or list of str, optional) – Sequence Parts concatenated into the span (default
'tmd_jmd', the whole TMD-JMD span), passed toSequenceFeature.get_df_parts().return_df (bool, default=False) – If
True, return a labeledpd.DataFrame(rows indexed likedf_parts, one column per k-mer) instead of a plain array.return_scales (bool, default=False) – If
True, also return the CPP-ready(df_scales, df_cat)for the composition, i.e. the return becomes the 3-tuple(X, df_scales, df_cat). Fork=1(AAC)df_scalesis the(20, 20)one-hot identity scale set — pass it withdf_cattoCPP.run()(whole-partSegment(1,1)split) to obtain amino-acid composition as a realdf_feat/ feature map. Fork>=2df_scalesisNone(a k-mer is not a per-residue scale, so it cannot be a CPP scale) anddf_catcategorizes the k-mers by residue class for the composition map’s grouping / labels.
- Returns:
X – k-mer-composition matrix: per sequence, the fraction of each of the
20 ** kordered k-mers over the span residues (columns initertools.product(ut.LIST_CANONICAL_AA, repeat=k)order). A span with fewer thankcanonical residues has an all-NaNrow. Returned as apd.DataFrame(k-mer strings as columns) whenreturn_df=True. Whenreturn_scales=Truethe return is the 3-tuple(X, df_scales, df_cat)(df_scalesisNonefork>=2).- Return type:
array-like, shape (n_samples, 20 ** k)
See also
SequenceFeature.aa_composition(): thek=1amino-acid-composition special case.SequenceFeature.dipeptide_composition(): thek=2dipeptide-composition special case.SequenceFeature.scale_composition(): the scale-based composition baseline.SequenceFeature.feature_matrix(): the positional Part-Split-Scale feature matrix.
Examples
SequenceFeature.kmer_compositionbuilds a k-mer-composition baseline: for each sequence it concatenates the selected Parts into one span and returns the fraction of every ordered overlapping k-mer of adjacent canonical residues, a(n_seq, 20 ** k)matrixX. It carries no positional information (unlike :meth:CPP.run/ :meth:feature_matrix), so it is the natural baseline to compare CPP against.kselects the composition:k=1is amino-acid composition (AAC, 20 columns, identical to :meth:aa_composition),k=2dipeptide composition (DPC, 400 columns, identical to :meth:dipeptide_composition), and higherkcaptures longer local sequential order.import numpy as np import pandas as pd import aaanalysis as aa aa.options["verbose"] = False # Six short sequences (whole sequence used as the span; no flanks needed) df_seq = pd.DataFrame({ "entry": [f"P{i}" for i in range(6)], "sequence": ["ACDEFGHIKLMNPQRSTVWY", "MKKLLAACDE", "ACACACAC", "WYWYWYWY", "GGGGSSSS", "LLKKLLKK"], }) sf = aa.SequenceFeature() aa.display_df(df_seq, n_rows=10, show_shape=True)
DataFrame shape: (6, 2)
entry sequence 1 P0 ACDEFGHIKLMNPQRSTVWY 2 P1 MKKLLAACDE 3 P2 ACACACAC 4 P3 WYWYWYWY 5 P4 GGGGSSSS 6 P5 LLKKLLKK ``k`` — the composition order.
k=1gives AAC (20 columns): the fraction of each amino acid.X_aac = sf.kmer_composition(df_seq=df_seq, k=1, return_df=True) print(f"Shape: {X_aac.shape}") aa.display_df(X_aac.round(3), n_rows=10, show_shape=True)
Shape: (6, 20) DataFrame shape: (6, 20)
A C D E F G H I K L M N P Q R S T V W Y entry P0 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 0.050000 P1 0.200000 0.100000 0.100000 0.100000 0.000000 0.000000 0.000000 0.000000 0.200000 0.200000 0.100000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 P2 0.500000 0.500000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 P3 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.500000 P4 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.000000 0.000000 0.000000 0.000000 P5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.500000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 k=2gives DPC (400 columns): the fraction of each ordered adjacent residue pairAA, AC, ..., YY.X_dpc = sf.kmer_composition(df_seq=df_seq, k=2, return_df=True) print(f"Shape: {X_dpc.shape}") # Show only the non-zero dipeptide columns for readability nz = X_dpc.loc[:, (X_dpc.fillna(0) != 0).any(axis=0)] aa.display_df(nz.round(3), n_rows=10, show_shape=True)
Shape: (6, 400) DataFrame shape: (6, 30)
AA AC CA CD DE EF FG GG GH GS HI IK KK KL LA LK LL LM MK MN NP PQ QR RS SS ST TV VW WY YW entry P0 0.000000 0.053000 0.000000 0.053000 0.053000 0.053000 0.053000 0.000000 0.053000 0.000000 0.053000 0.053000 0.000000 0.053000 0.000000 0.000000 0.000000 0.053000 0.000000 0.053000 0.053000 0.053000 0.053000 0.053000 0.000000 0.053000 0.053000 0.053000 0.053000 0.000000 P1 0.111000 0.111000 0.000000 0.111000 0.111000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.111000 0.111000 0.111000 0.000000 0.111000 0.000000 0.111000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 P2 0.000000 0.571000 0.429000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 P3 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.571000 0.429000 P4 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.429000 0.000000 0.143000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.429000 0.000000 0.000000 0.000000 0.000000 0.000000 P5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.286000 0.143000 0.000000 0.286000 0.286000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 k=3gives tripeptide composition (8000 columns) — longer local order at the cost of a much wider, sparser matrix.kis capped at 4 (20 ** kgrows exponentially).X_k3 = sf.kmer_composition(df_seq=df_seq, k=3) print(f"k=3 shape: {X_k3.shape} (20**3 = {20**3} columns)") print(f"Each row sums to 1 (spans with >= 3 residues): " f"{np.allclose(np.nansum(X_k3, axis=1), 1.0)}")
k=3 shape: (6, 8000) (20**3 = 8000 columns) Each row sums to 1 (spans with >= 3 residues): True
``k=1`` and ``k=2`` are exactly the named baselines.
kmer_composition(k=1)equals :meth:aa_compositionandkmer_composition(k=2)equals :meth:dipeptide_composition— the named methods are convenience aliases for those two orders.same_aac = np.array_equal(sf.kmer_composition(df_seq=df_seq, k=1), sf.aa_composition(df_seq=df_seq), equal_nan=True) same_dpc = np.array_equal(sf.kmer_composition(df_seq=df_seq, k=2), sf.dipeptide_composition(df_seq=df_seq), equal_nan=True) print(f"k=1 == aa_composition: {same_aac}") print(f"k=2 == dipeptide_composition: {same_dpc}")
k=1 == aa_composition: True k=2 == dipeptide_composition: True
``list_parts`` — which span to count over. By default the whole
tmd_jmdspan is used; pass specific Parts (needs TMD/JMD columns) to restrict the composition to, e.g., the TMD only.df_seq_tmd = df_seq.assign(tmd_start=2, tmd_stop=7) # TMD within the shortest sequence (len 8) X_tmd = sf.kmer_composition(df_seq=df_seq_tmd, k=1, list_parts="tmd", return_df=True) aa.display_df(X_tmd.round(3), n_rows=10, show_shape=True)
DataFrame shape: (6, 20)
A C D E F G H I K L M N P Q R S T V W Y entry P0 0.000000 0.167000 0.167000 0.167000 0.167000 0.167000 0.167000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 P1 0.333000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.333000 0.333000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 P2 0.500000 0.500000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 P3 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.500000 P4 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.000000 0.000000 0.000000 0.000000 P5 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 0.500000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 ``return_df``. With
return_df=False(default) a plainnp.ndarrayis returned for direct use as a model matrixX; withreturn_df=Truea labeledDataFrame(one column per k-mer) is returned. A span with fewer thankcanonical residues has an all-NaNrow.X_arr = sf.kmer_composition(df_seq=df_seq, k=2) print(type(X_arr).__name__, X_arr.shape, X_arr.dtype)
ndarray (6, 400) float64
Getting CPP-ready scales / categories (``return_scales``). For the feature map you need a scale set + a category table, not the composition matrix
X.return_scales=Truemakes the return the 3-tuple(X, df_scales, df_cat). For k=1df_scalesis the 20×20 one-hot identity — feed it withdf_cattoaa.CPP(df_parts, df_scales=df_scales, df_cat=df_cat, split_kws=<Segment(1,1)>).run(...)to obtain amino-acid composition as a realdf_feat/ feature map. For k>=2df_scalesisNone(a k-mer is not a per-residue scale) anddf_catlabels each k-mer by its residue class.X, df_scales, df_cat = sf.kmer_composition(df_seq=df_seq, k=1, return_scales=True) print(f"k=1 df_scales (one-hot identity): {df_scales.shape}") aa.display_df(df_cat, n_rows=10, show_shape=True)
k=1 df_scales (one-hot identity): (20, 20) DataFrame shape: (20, 5)
scale_id category subcategory scale_name scale_description 1 A Nonpolar Nonpolar A Amino acid A indicator 2 C Polar Polar C Amino acid C indicator 3 D Negative Negative D Amino acid D indicator 4 E Negative Negative E Amino acid E indicator 5 F Aromatic Aromatic F Amino acid F indicator 6 G Nonpolar Nonpolar G Amino acid G indicator 7 H Positive Positive H Amino acid H indicator 8 I Nonpolar Nonpolar I Amino acid I indicator 9 K Positive Positive K Amino acid K indicator 10 L Nonpolar Nonpolar L Amino acid L indicator