@@ -29,15 +29,13 @@ class IsotonicRegressionSuite extends FunSuite with MLlibTestSparkContext with M
29
29
}
30
30
31
31
private def generateIsotonicInput (labels : Seq [Double ]): Seq [(Double , Double , Double )] = {
32
- labels.zip( 1 to labels.size).map(point => (point._1, point._2 .toDouble, 1d ))
32
+ Seq .tabulate( labels.size)(i => (labels(i), i .toDouble, 1d ))
33
33
}
34
34
35
35
private def generateIsotonicInput (
36
36
labels : Seq [Double ],
37
37
weights : Seq [Double ]): Seq [(Double , Double , Double )] = {
38
- labels.zip(1 to labels.size)
39
- .zip(weights)
40
- .map(point => (point._1._1, point._1._2.toDouble, point._2))
38
+ Seq .tabulate(labels.size)(i => (labels(i), i.toDouble, weights(i)))
41
39
}
42
40
43
41
private def runIsotonicRegression (
@@ -55,87 +53,123 @@ class IsotonicRegressionSuite extends FunSuite with MLlibTestSparkContext with M
55
53
}
56
54
57
55
test(" increasing isotonic regression" ) {
58
- val model = runIsotonicRegression(Seq (1 , 2 , 3 , 3 , 1 , 6 , 17 , 16 , 17 , 18 ), true )
59
- assert(model.predictions === Array (1 , 2 , 7d / 3 , 7d / 3 , 7d / 3 , 6 , 16.5 , 16.5 , 17 , 18 ))
56
+ /*
57
+ The following result could be re-produced with sklearn.
58
+
59
+ > from sklearn.isotonic import IsotonicRegression
60
+ > x = range(9)
61
+ > y = [1, 2, 3, 1, 6, 17, 16, 17, 18]
62
+ > ir = IsotonicRegression(x, y)
63
+ > print ir.predict(x)
64
+
65
+ array([ 1. , 2. , 2. , 2. , 6. , 16.5, 16.5, 17. , 18. ])
66
+ */
67
+ val model = runIsotonicRegression(Seq (1 , 2 , 3 , 1 , 6 , 17 , 16 , 17 , 18 ), true )
68
+
69
+ assert(Array .tabulate(9 )(x => model.predict(x)) === Array (1 , 2 , 2 , 2 , 6 , 16.5 , 16.5 , 17 , 18 ))
70
+
71
+ assert(model.boundaries === Array (0 , 1 , 3 , 4 , 5 , 6 , 7 , 8 ))
72
+ assert(model.predictions === Array (1 , 2 , 2 , 6 , 16.5 , 16.5 , 17.0 , 18.0 ))
73
+ assert(model.isotonic)
60
74
}
61
75
62
76
test(" isotonic regression with size 0" ) {
63
77
val model = runIsotonicRegression(Seq (), true )
78
+
64
79
assert(model.predictions === Array ())
65
80
}
66
81
67
82
test(" isotonic regression with size 1" ) {
68
83
val model = runIsotonicRegression(Seq (1 ), true )
84
+
69
85
assert(model.predictions === Array (1.0 ))
70
86
}
71
87
72
88
test(" isotonic regression strictly increasing sequence" ) {
73
89
val model = runIsotonicRegression(Seq (1 , 2 , 3 , 4 , 5 ), true )
90
+
74
91
assert(model.predictions === Array (1 , 2 , 3 , 4 , 5 ))
75
92
}
76
93
77
94
test(" isotonic regression strictly decreasing sequence" ) {
78
95
val model = runIsotonicRegression(Seq (5 , 4 , 3 , 2 , 1 ), true )
79
- assert(model.predictions === Array (3 , 3 , 3 , 3 , 3 ))
96
+
97
+ assert(model.boundaries === Array (0 , 4 ))
98
+ assert(model.predictions === Array (3 , 3 ))
80
99
}
81
100
82
101
test(" isotonic regression with last element violating monotonicity" ) {
83
102
val model = runIsotonicRegression(Seq (1 , 2 , 3 , 4 , 2 ), true )
84
- assert(model.predictions === Array (1 , 2 , 3 , 3 , 3 ))
103
+
104
+ assert(model.boundaries === Array (0 , 1 , 2 , 4 ))
105
+ assert(model.predictions === Array (1 , 2 , 3 , 3 ))
85
106
}
86
107
87
108
test(" isotonic regression with first element violating monotonicity" ) {
88
109
val model = runIsotonicRegression(Seq (4 , 2 , 3 , 4 , 5 ), true )
89
- assert(model.predictions === Array (3 , 3 , 3 , 4 , 5 ))
110
+
111
+ assert(model.boundaries === Array (0 , 2 , 3 , 4 ))
112
+ assert(model.predictions === Array (3 , 3 , 4 , 5 ))
90
113
}
91
114
92
115
test(" isotonic regression with negative labels" ) {
93
116
val model = runIsotonicRegression(Seq (- 1 , - 2 , 0 , 1 , - 1 ), true )
94
- assert(model.predictions === Array (- 1.5 , - 1.5 , 0 , 0 , 0 ))
117
+
118
+ assert(model.boundaries === Array (0 , 1 , 2 , 4 ))
119
+ assert(model.predictions === Array (- 1.5 , - 1.5 , 0 , 0 ))
95
120
}
96
121
97
122
test(" isotonic regression with unordered input" ) {
98
- val trainRDD = sc.parallelize(generateIsotonicInput(Seq (1 , 2 , 3 , 4 , 5 )).reverse).cache()
123
+ val trainRDD = sc.parallelize(generateIsotonicInput(Seq (1 , 2 , 3 , 4 , 5 )).reverse, 2 )
124
+
99
125
val model = new IsotonicRegression ().run(trainRDD)
100
126
assert(model.predictions === Array (1 , 2 , 3 , 4 , 5 ))
101
127
}
102
128
103
129
test(" weighted isotonic regression" ) {
104
130
val model = runIsotonicRegression(Seq (1 , 2 , 3 , 4 , 2 ), Seq (1 , 1 , 1 , 1 , 2 ), true )
105
- assert(model.predictions === Array (1 , 2 , 2.75 , 2.75 ,2.75 ))
131
+
132
+ assert(model.boundaries === Array (0 , 1 , 2 , 4 ))
133
+ assert(model.predictions === Array (1 , 2 , 2.75 , 2.75 ))
106
134
}
107
135
108
136
test(" weighted isotonic regression with weights lower than 1" ) {
109
137
val model = runIsotonicRegression(Seq (1 , 2 , 3 , 2 , 1 ), Seq (1 , 1 , 1 , 0.1 , 0.1 ), true )
110
- assert(model.predictions.map(round) === Array (1 , 2 , 3.3 / 1.2 , 3.3 / 1.2 , 3.3 / 1.2 ))
138
+
139
+ assert(model.boundaries === Array (0 , 1 , 2 , 4 ))
140
+ assert(model.predictions.map(round) === Array (1 , 2 , 3.3 / 1.2 , 3.3 / 1.2 ))
111
141
}
112
142
113
143
test(" weighted isotonic regression with negative weights" ) {
114
144
val model = runIsotonicRegression(Seq (1 , 2 , 3 , 2 , 1 ), Seq (- 1 , 1 , - 3 , 1 , - 5 ), true )
115
- assert(model.predictions === Array (1.0 , 10.0 / 6 , 10.0 / 6 , 10.0 / 6 , 10.0 / 6 ))
145
+
146
+ assert(model.boundaries === Array (0.0 , 1.0 , 4.0 ))
147
+ assert(model.predictions === Array (1.0 , 10.0 / 6 , 10.0 / 6 ))
116
148
}
117
149
118
150
test(" weighted isotonic regression with zero weights" ) {
119
151
val model = runIsotonicRegression(Seq [Double ](1 , 2 , 3 , 2 , 1 ), Seq [Double ](0 , 0 , 0 , 1 , 0 ), true )
120
- assert(model.predictions === Array (1 , 2 , 2 , 2 , 2 ))
152
+
153
+ assert(model.boundaries === Array (0.0 , 1.0 , 4.0 ))
154
+ assert(model.predictions === Array (1 , 2 , 2 ))
121
155
}
122
156
123
157
test(" isotonic regression prediction" ) {
124
158
val model = runIsotonicRegression(Seq (1 , 2 , 7 , 1 , 2 ), true )
125
159
160
+ assert(model.predict(- 2 ) === 1 )
126
161
assert(model.predict(- 1 ) === 1 )
127
- assert(model.predict(0 ) === 1 )
128
- assert(model.predict(1.5 ) === 1.5 )
129
- assert(model.predict(1.75 ) === 1.75 )
130
- assert(model.predict(2 ) === 2 )
131
- assert(model.predict(3 ) === 10d / 3 )
132
- assert(model.predict(10 ) === 10d / 3 )
162
+ assert(model.predict(0.5 ) === 1.5 )
163
+ assert(model.predict(0.75 ) === 1.75 )
164
+ assert(model.predict(1 ) === 2 )
165
+ assert(model.predict(2 ) === 10d / 3 )
166
+ assert(model.predict(9 ) === 10d / 3 )
133
167
}
134
168
135
169
test(" isotonic regression prediction with duplicate features" ) {
136
170
val trainRDD = sc.parallelize(
137
171
Seq [(Double , Double , Double )](
138
- (2 , 1 , 1 ), (1 , 1 , 1 ), (4 , 2 , 1 ), (2 , 2 , 1 ), (6 , 3 , 1 ), (5 , 3 , 1 ))).cache( )
172
+ (2 , 1 , 1 ), (1 , 1 , 1 ), (4 , 2 , 1 ), (2 , 2 , 1 ), (6 , 3 , 1 ), (5 , 3 , 1 )), 2 )
139
173
val model = new IsotonicRegression ().run(trainRDD)
140
174
141
175
assert(model.predict(0 ) === 1 )
@@ -147,7 +181,7 @@ class IsotonicRegressionSuite extends FunSuite with MLlibTestSparkContext with M
147
181
test(" antitonic regression prediction with duplicate features" ) {
148
182
val trainRDD = sc.parallelize(
149
183
Seq [(Double , Double , Double )](
150
- (5 , 1 , 1 ), (6 , 1 , 1 ), (2 , 2 , 1 ), (4 , 2 , 1 ), (1 , 3 , 1 ), (2 , 3 , 1 ))).cache( )
184
+ (5 , 1 , 1 ), (6 , 1 , 1 ), (2 , 2 , 1 ), (4 , 2 , 1 ), (1 , 3 , 1 ), (2 , 3 , 1 )), 2 )
151
185
val model = new IsotonicRegression ().setIsotonic(false ).run(trainRDD)
152
186
153
187
assert(model.predict(0 ) === 6 )
@@ -158,21 +192,22 @@ class IsotonicRegressionSuite extends FunSuite with MLlibTestSparkContext with M
158
192
159
193
test(" isotonic regression RDD prediction" ) {
160
194
val model = runIsotonicRegression(Seq (1 , 2 , 7 , 1 , 2 ), true )
161
- val testRDD = sc.parallelize(List (- 1.0 , 0.0 , 1.5 , 1.75 , 2.0 , 3.0 , 10.0 )).cache()
162
195
163
- assert(model.predict(testRDD).collect() === Array (1 , 1 , 1.5 , 1.75 , 2 , 10.0 / 3 , 10.0 / 3 ))
196
+ val testRDD = sc.parallelize(List (- 2.0 , - 1.0 , 0.5 , 0.75 , 1.0 , 2.0 , 9.0 ), 2 )
197
+ val predictions = testRDD.map(x => (x, model.predict(x))).collect().sortBy(_._1).map(_._2)
198
+ assert(predictions === Array (1 , 1 , 1.5 , 1.75 , 2 , 10.0 / 3 , 10.0 / 3 ))
164
199
}
165
200
166
201
test(" antitonic regression prediction" ) {
167
202
val model = runIsotonicRegression(Seq (7 , 5 , 3 , 5 , 1 ), false )
168
203
204
+ assert(model.predict(- 2 ) === 7 )
169
205
assert(model.predict(- 1 ) === 7 )
170
- assert(model.predict(0 ) === 7 )
171
- assert(model.predict(1.5 ) === 6 )
172
- assert(model.predict(1.75 ) === 5.5 )
173
- assert(model.predict(2 ) === 5 )
174
- assert(model.predict(3 ) === 4 )
175
- assert(model.predict(10 ) === 1 )
206
+ assert(model.predict(0.5 ) === 6 )
207
+ assert(model.predict(0.75 ) === 5.5 )
208
+ assert(model.predict(1 ) === 5 )
209
+ assert(model.predict(2 ) === 4 )
210
+ assert(model.predict(9 ) === 1 )
176
211
}
177
212
178
213
test(" model construction" ) {
0 commit comments