Current section
Files
Jump to
Current section
Files
lib/datasets.ex
defmodule Datasets do
@moduledoc """
Datasets module to generate and graph sample data
"""
defmodule Point do
defstruct [:x, :y, :group]
@moduledoc """
Point containing an x and y coordinate and a group
"""
end
defimpl Inspect, for: Point do
def inspect(%Point{x: x, y: y, group: group}, _) do
"<(#{x}, #{y}) - group:#{group}>"
end
end
@doc """
Make two interleaving half circles
Returns an list with count `samples` of the form {x: XX, y: YY, group: :inner | :outer}
`samples` - count of samples to return (defaults to 100)
`shuffle` - if the inner and outer circle data should be suffled (defaults to true)
`noise` - standard deviation of noise to add to each point (defaults to nil)
`random_state` - random seed
"""
def make_moons(samples \\ 100, shuffle \\ true, noise \\ nil, random_state \\ 0) do
samples_outer = div(samples, 2)
samples_inner = samples - samples_outer
:random.seed(random_state)
outer = Enum.map(linspace(0, :math.pi, samples_outer), fn angle ->
%Point{x: :math.cos(angle), y: :math.sin(angle), group: :outer}
end)
inner = Enum.map(linspace(0, :math.pi, samples_inner), fn angle ->
%Point{x: 1.0 - :math.cos(angle), y: 1.0 - :math.sin(angle) - 0.5, group: :inner}
end)
points = case shuffle do
true -> [outer | inner] |> List.flatten |> Enum.shuffle
false -> [outer | inner] |> List.flatten
end
unless is_nil(noise) do
points = Enum.map(points, fn point ->
%Point{x: x, y: y, group: group} = point
%Point{x: x + Statistics.Distributions.Normal.rand(0.0, noise), y: y + Statistics.Distributions.Normal.rand(0.0, noise), group: group}
end)
end
points
end
defp linspace(start, stop, number) do
increment = (stop - start) / (number - 1)
for x <- 0..number - 1, do: start + x * increment
end
end