Skip to content

Commit 2940758

Browse files
committed
modify tests
1 parent 8d6f715 commit 2940758

8 files changed

Lines changed: 62 additions & 40 deletions

File tree

lib/learn_kit/knn.ex

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,7 @@ defmodule LearnKit.Knn do
9797

9898
def classify(%Knn{data_set: data_set}, options \\ []) do
9999
try do
100-
unless Keyword.has_key?(options, :feature) do
101-
raise "Feature option is required"
102-
end
100+
unless Keyword.has_key?(options, :feature), do: raise "Feature option is required"
103101
# modification of options
104102
options = Keyword.merge([k: 3, algorithm: "brute", weight: "uniform"], options)
105103
# prediction

lib/learn_kit/knn/classify.ex

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ defmodule LearnKit.Knn.Classify do
22
@moduledoc """
33
Module for knn classify functions
44
"""
5+
6+
alias LearnKit.Math
7+
58
defmacro __using__(_opts) do
69
quote do
710
defp prediction(data_set, options) do
@@ -34,7 +37,8 @@ defmodule LearnKit.Knn.Classify do
3437
defp calc_feature_weights(features, options) do
3538
features
3639
|> Enum.map(fn feature ->
37-
Tuple.append(feature, calc_feature_weight(Keyword.get(options, :weight), elem(feature, 0)))
40+
feature
41+
|> Tuple.append(calc_feature_weight(Keyword.get(options, :weight), elem(feature, 0)))
3842
end)
3943
end
4044

@@ -78,9 +82,7 @@ defmodule LearnKit.Knn.Classify do
7882
features
7983
|> Enum.reduce([], fn feature, acc ->
8084
distance = feature |> calc_distance_between_features(current_feature)
81-
if distance == 0 do
82-
raise "Feature exists in train data set with label #{key}"
83-
end
85+
if distance == 0, do: raise "Feature exists in train data set with label #{key}"
8486
acc = [{distance, key} | acc]
8587
end)
8688
end
@@ -92,19 +94,15 @@ defmodule LearnKit.Knn.Classify do
9294
defp calc_distance_between_points(acc, feature_from_data_set, feature, current_index, size) when current_index <= size do
9395
Enum.at(feature_from_data_set, current_index) - Enum.at(feature, current_index)
9496
|> :math.pow(2)
95-
|> summ(acc)
97+
|> Math.summ(acc)
9698
|> calc_distance_between_points(feature_from_data_set, feature, current_index + 1, size)
9799
end
98100

99-
defp calc_distance_between_points(acc, _feature_from_data_set, _feature, _current_index, _size) do
101+
defp calc_distance_between_points(acc, _, _, _, _) do
100102
acc
101103
|> :math.sqrt
102104
end
103105

104-
defp summ(a, b) do
105-
a + b
106-
end
107-
108106
defp calc_feature_weight(weight, distance) do
109107
case weight do
110108
"uniform" -> 1
@@ -117,7 +115,7 @@ defmodule LearnKit.Knn.Classify do
117115
acc
118116
end
119117

120-
defp accumulate_weight_of_labels([{_distance, key, weight} | tail], acc) do
118+
defp accumulate_weight_of_labels([{_, key, weight} | tail], acc) do
121119
previous = if Keyword.has_key?(acc, key), do: Keyword.get(acc, key), else: 0
122120
acc = Keyword.put(acc, key, previous + weight)
123121
accumulate_weight_of_labels(tail, acc)

lib/learn_kit/math.ex

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ defmodule LearnKit.Math do
66
@type row :: [number]
77
@type matrix :: [row]
88

9+
@doc """
10+
Sum of 2 numbers
11+
12+
## Examples
13+
14+
iex> LearnKit.Math.summ(1, 2)
15+
3
16+
17+
"""
18+
@spec summ(number, number) :: number
19+
20+
def summ(a, b) do
21+
a + b
22+
end
23+
924
@doc """
1025
Calculate the mean from a list of numbers
1126
@@ -125,8 +140,8 @@ defmodule LearnKit.Math do
125140
defp swap_rows_cols([head | _]) when head == [], do: []
126141

127142
defp swap_rows_cols(rows) do
128-
firsts = Enum.map(rows, fn(x) -> hd(x) end)
129-
others = Enum.map(rows, fn(x) -> tl(x) end)
143+
firsts = Enum.map(rows, fn x -> hd(x) end)
144+
others = Enum.map(rows, fn x -> tl(x) end)
130145
[firsts | swap_rows_cols(others)]
131146
end
132147

@@ -194,8 +209,7 @@ defmodule LearnKit.Math do
194209
size = length(x)
195210

196211
Enum.zip(x, y)
197-
|> Enum.map(fn {xi, yi} -> (xi - mean_x) * (yi - mean_y) end)
198-
|> Enum.sum
212+
|> Enum.reduce(0, fn {xi, yi}, acc -> acc + (xi - mean_x) * (yi - mean_y) end)
199213
|> division(size - 1)
200214
end
201215

@@ -214,15 +228,9 @@ defmodule LearnKit.Math do
214228
mean_x = mean(x)
215229
mean_y = mean(y)
216230

217-
divider = Enum.zip(x, y)
218-
|> Enum.map(fn {xi, yi} -> (xi - mean_x) * (yi - mean_y) end)
219-
|> Enum.sum
220-
denom_x = x
221-
|> Enum.map(fn xi -> :math.pow(xi - mean_x, 2) end)
222-
|> Enum.sum
223-
denom_y = y
224-
|> Enum.map(fn yi -> :math.pow(yi - mean_y, 2) end)
225-
|> Enum.sum
231+
divider = Enum.zip(x, y) |> Enum.reduce(0, fn {xi, yi}, acc -> acc + (xi - mean_x) * (yi - mean_y) end)
232+
denom_x = x |> Enum.reduce(0, fn xi, acc -> acc + :math.pow(xi - mean_x, 2) end)
233+
denom_y = y |> Enum.reduce(0, fn yi, acc -> acc + :math.pow(yi - mean_y, 2) end)
226234

227235
divider / :math.sqrt(denom_x * denom_y)
228236
end

lib/learn_kit/naive_bayes/gaussian/classify.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defmodule LearnKit.NaiveBayes.Gaussian.Classify do
77
# classify data
88
# returns data like [label1: 0.03592747361085857, label2: 0.00399309643713954]
99
defp classify_data(fit_data, feature) do
10-
labels_count = length(Keyword.keys(fit_data))
10+
labels_count = fit_data |> Keyword.keys |> length
1111
fit_data
1212
|> Enum.map(fn {label, fit_results} ->
1313
{label, class_probability(labels_count, feature, fit_results)}
@@ -23,7 +23,7 @@ defmodule LearnKit.NaiveBayes.Gaussian.Classify do
2323
end
2424

2525
# multiply together the feature probabilities for all of the features in a label for given values
26-
defp feature_mult([], _fit_results, acc, _index), do: acc
26+
defp feature_mult([], _, acc, _), do: acc
2727

2828
defp feature_mult([head | tail], fit_results, acc, index) do
2929
acc = acc * feature_probability(index, head, fit_results)
@@ -38,7 +38,7 @@ defmodule LearnKit.NaiveBayes.Gaussian.Classify do
3838
if fit_result.mean == value, do: 1.0, else: 0.0
3939
else
4040
# calculate the gaussian probability
41-
exp = - :math.pow((value - fit_result.mean), 2) / (2 * fit_result.variance)
41+
exp = - :math.pow(value - fit_result.mean, 2) / (2 * fit_result.variance)
4242
:math.exp(exp) / :math.sqrt(2 * :math.pi * fit_result.variance)
4343
end
4444
end

lib/learn_kit/regression/linear.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ defmodule LearnKit.Regression.Linear do
8787
end
8888

8989
defp define_method_for_fit(options) do
90-
cond do
91-
Keyword.get(options, :method) == "gradient descent" -> "gradient descent"
92-
true -> ""
90+
case Keyword.get(options, :method) do
91+
"gradient descent" -> "gradient descent"
92+
_ -> ""
9393
end
9494
end
9595

lib/learn_kit/regression/linear/calculations.ex

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,12 @@ defmodule LearnKit.Regression.Linear.Calculations do
3030
defp total_sum_of_squares(list) do
3131
mean_list = Math.mean(list)
3232
list
33-
|> Enum.map(fn x -> :math.pow(x - mean_list, 2) end)
34-
|> Enum.sum
33+
|> Enum.reduce(0, fn x, acc -> acc + :math.pow(x - mean_list, 2) end)
3534
end
3635

3736
defp sum_of_squared_errors(coefficients, factors, results) do
3837
Enum.zip(factors, results)
39-
|> Enum.map(fn {xi, yi} -> squared_prediction_error(coefficients, xi, yi) end)
40-
|> Enum.sum
38+
|> Enum.reduce(0, fn {xi, yi}, acc -> acc + squared_prediction_error(coefficients, xi, yi) end)
4139
end
4240

4341
defp squared_prediction_error(coefficients, x, y) do
@@ -78,9 +76,7 @@ defmodule LearnKit.Regression.Linear.Calculations do
7876
end
7977

8078
defp check_value(data, min_value, theta, min_theta, iterations_with_no_improvement, alpha) do
81-
value = data
82-
|> Enum.map(fn {xi, yi} -> squared_prediction_error(theta, xi, yi) end)
83-
|> Enum.sum
79+
value = data |> Enum.reduce(0, fn {xi, yi}, acc -> acc + squared_prediction_error(theta, xi, yi) end)
8480
cond do
8581
value < min_value ->
8682
[theta, value, 0, 0.0001]

test/learn_kit/math_test.exs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ defmodule LearnKit.MathTest do
33

44
alias LearnKit.Math
55

6+
test "calculate sum" do
7+
assert 3 = Math.summ(1, 2)
8+
end
9+
610
test "calculate mean" do
711
assert 2.0 = Math.mean([1, 2, 3])
812
end
@@ -34,4 +38,16 @@ defmodule LearnKit.MathTest do
3438
test "calculate correlation" do
3539
assert 0.9672471299049061 = Math.correlation([1, 2, 3], [14, 17, 25])
3640
end
41+
42+
test "transposing a matrix" do
43+
assert [[1, 3, 5], [2, 4, 6]] = Math.transpose([[1, 2], [3, 4], [5, 6]])
44+
end
45+
46+
test "scalar multiplication with matrix" do
47+
assert [50, 60] = Math.scalar_multiply(10, [5, 6])
48+
end
49+
50+
test "vector subtraction" do
51+
assert [5, 45, 20] = Math.vector_subtraction([40, 50, 60], [35, 5, 40])
52+
end
3753
end

test/learn_kit/regression/linear_test.exs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ defmodule LearnKit.Regression.LinearTest do
2929
assert coefficients == [-1.5, 4.0]
3030
end
3131

32+
test "fit data set with gradient descent", state do
33+
%Linear{coefficients: coefficients} = state[:predictor] |> Linear.fit([method: "gradient descent"])
34+
35+
assert [-1.5, 4.0] = coefficients |> Enum.map(fn x -> Float.round(x, 2) end)
36+
end
37+
3238
test "return prediction using the linear model", state do
3339
predictor = state[:predictor] |> Linear.fit
3440

0 commit comments

Comments
 (0)