求F#中类似Scikit-Learn PolynomialFeatures的通用实现
Great question! While there’s no official out-of-the-box implementation in FsLab that mirrors Scikit-Learn’s PolynomialFeatures exactly, building a generic version yourself is straightforward with F#'s functional toolkit. Let’s walk through how to create one that matches the behavior you described (e.g., input [x; y] with degree 2 outputs [1; x; y; x²; xy; y²]).
Step 1: Generate Exponent Combinations
First, we need a helper function to generate all valid exponent tuples for our features. For n features and a target degree d, we want all non-negative integer lists of length n where the sum of elements is ≤ d (this includes the constant term where all exponents are 0).
let generateExponents (featureCount: int) (degree: int) = let rec helper current remainingDegree = match current.Length with | len when len = featureCount -> if remainingDegree >= 0 then [List.rev current] else [] | _ -> [0 .. remainingDegree] |> List.collect (fun d -> helper (d :: current) (remainingDegree - d)) helper [] degree
Step 2: Build the Core Polynomial Features Function
Next, we’ll use the exponent combinations to compute the polynomial terms for a single feature vector. We multiply each feature by its corresponding exponent and aggregate the product for each term.
let polynomialFeatures (degree: int) (features: float array) = let exponents = generateExponents features.Length degree exponents |> List.map (fun exp -> Array.zip features exp |> Array.fold (fun acc (f, e) -> acc * (f ** float e)) 1.0) |> List.toArray
Test the Implementation
Let’s verify with your example:
// Test sample: [x; y] = [2.0; 3.0], degree 2 let sampleFeatures = [|2.0; 3.0|] polynomialFeatures 2 sampleFeatures // Output: [|1.0; 2.0; 3.0; 4.0; 6.0; 9.0|]
This matches exactly the output you expected from Scikit-Learn’s PolynomialFeatures!
Optional: Add Scikit-Learn Style Parameters
If you want to mirror Scikit-Learn’s API more closely (like toggling the constant term), you can modify the function to include an includeBias parameter:
let polynomialFeatures (degree: int) (includeBias: bool) (features: float array) = let rawExponents = generateExponents features.Length degree // Filter out the constant term (all exponents 0) if includeBias is false let exponents = if includeBias then rawExponents else rawExponents |> List.filter (fun exp -> exp |> List.sum > 0) exponents |> List.map (fun exp -> Array.zip features exp |> Array.fold (fun acc (f, e) -> acc * (f ** float e)) 1.0) |> List.toArray
Batch Processing Support
To handle multiple samples at once (like a matrix of features), add a simple wrapper:
let polynomialFeaturesBatch (degree: int) (includeBias: bool) (samples: float array array) = samples |> Array.map (polynomialFeatures degree includeBias)
This implementation is fully generic—works for any number of features and any degree you need. It fits naturally into FsLab’s data science workflow!
内容的提问来源于stack exchange,提问作者Jose Vu

