Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/mllib-evaluation-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,21 +439,21 @@ $$rel_D(r) = \begin{cases}1 & \text{if $r \in D$}, \\ 0 & \text{otherwise}.\end{
Precision at k
</td>
<td>
$p(k)=\frac{1}{M} \sum_{i=0}^{M-1} {\frac{1}{k} \sum_{j=0}^{\text{min}(\left|D\right|, k) - 1} rel_{D_i}(R_i(j))}$
$p(k)=\frac{1}{M} \sum_{i=0}^{M-1} {\frac{1}{k} \sum_{j=0}^{\text{min}(\left|R_i\right|, k) - 1} rel_{D_i}(R_i(j))}$
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although we usually have k <= |D| and k <= |R_i|, I agree that this is technically what must have been meant. How about using Q here instead of |R_i|? it was already used in the following formula. You can change both, sure, either way, as long as they're consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the Q will vary with i, that is why I gave the notation |R_i|.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe; it could be the same for all users, or not. The documentation above this suggests there are equal numbers of recommended and relevant docs for each user (Q and N) but at least, it will almost never be true that |D_i| is the same for all users. Q could well be a constant.

But the implementation doesn't assume that and it's not necessary to, so I might even just remove the references to Q and N, or label them "Q_i" and "N_i" if you really want to be complete.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. updated.

</td>
<td>
<a href="https://en.wikipedia.org/wiki/Information_retrieval#Precision_at_K">Precision at k</a> is a measure of
<a href="https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Precision_at_K">Precision at k</a> is a measure of
how many of the first k recommended documents are in the set of true relevant documents averaged across all
users. In this metric, the order of the recommendations is not taken into account.
</td>
</tr>
<tr>
<td>Mean Average Precision</td>
<td>
$MAP=\frac{1}{M} \sum_{i=0}^{M-1} {\frac{1}{\left|D_i\right|} \sum_{j=0}^{Q-1} \frac{rel_{D_i}(R_i(j))}{j + 1}}$
$MAP=\frac{1}{M} \sum_{i=0}^{M-1} {\frac{1}{\left|R_i\right|} \sum_{j=0}^{\left|R_i\right|-1} \frac{rel_{D_i}(R_i(j))}{j + 1}}$
</td>
<td>
<a href="https://en.wikipedia.org/wiki/Information_retrieval#Mean_average_precision">MAP</a> is a measure of how
<a href="https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Mean_average_precision">MAP</a> is a measure of how
many of the recommended documents are in the set of true relevant documents, where the
order of the recommendations is taken into account (i.e. penalty for highly relevant documents is higher).
</td>
Expand All @@ -462,10 +462,10 @@ $$rel_D(r) = \begin{cases}1 & \text{if $r \in D$}, \\ 0 & \text{otherwise}.\end{
<td>Normalized Discounted Cumulative Gain</td>
<td>
$NDCG(k)=\frac{1}{M} \sum_{i=0}^{M-1} {\frac{1}{IDCG(D_i, k)}\sum_{j=0}^{n-1}
\frac{rel_{D_i}(R_i(j))}{\text{ln}(j+2)}} \\
\frac{rel_{D_i}(R_i(j))}{log_2(j+2)}} \\
\text{Where} \\
\hspace{5 mm} n = \text{min}\left(\text{max}\left(|R_i|,|D_i|\right),k\right) \\
\hspace{5 mm} IDCG(D, k) = \sum_{j=0}^{\text{min}(\left|D\right|, k) - 1} \frac{1}{\text{ln}(j+2)}$
\hspace{5 mm} IDCG(D, k) = \sum_{j=0}^{\text{min}(\left|D\right|, k) - 1} \frac{1}{log_2(j+2)}$
</td>
<td>
<a href="https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG">NDCG at k</a> is a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class RankingMetrics[T: ClassTag](predictionAndLabels: RDD[(Array[T], Array[T])]
}
i += 1
}
precSum / labSet.size
precSum / n
} else {
logWarning("Empty ground truth set, check input data")
0.0
Expand Down Expand Up @@ -138,6 +138,8 @@ class RankingMetrics[T: ClassTag](predictionAndLabels: RDD[(Array[T], Array[T])]
var dcg = 0.0
var i = 0
while (i < n) {
// Base of the log doesn't matter for calculating NDCG,
// if the relevance value is binary.
val gain = 1.0 / math.log(i + 2)
if (i < pred.length && labSet.contains(pred(i))) {
dcg += gain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void setUp() throws IOException {
public void rankingMetrics() {
@SuppressWarnings("unchecked")
RankingMetrics<?> metrics = RankingMetrics.of(predictionAndLabels);
Assert.assertEquals(0.355026, metrics.meanAveragePrecision(), 1e-5);
Assert.assertEquals(0.147989, metrics.meanAveragePrecision(), 1e-5);
Assert.assertEquals(0.75 / 3.0, metrics.precisionAt(4), 1e-5);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class RankingMetricsSuite extends SparkFunSuite with MLlibTestSparkContext {
assert(metrics.precisionAt(10) ~== 0.8/3 absTol eps)
assert(metrics.precisionAt(15) ~== 8.0/45 absTol eps)

assert(map ~== 0.355026 absTol eps)
assert(map ~== 0.147989 absTol eps)

assert(metrics.ndcgAt(3) ~== 1.0/3 absTol eps)
assert(metrics.ndcgAt(5) ~== 0.328788 absTol eps)
Expand Down
2 changes: 1 addition & 1 deletion python/pyspark/mllib/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class RankingMetrics(JavaModelWrapper):
>>> metrics.precisionAt(15)
0.17...
>>> metrics.meanAveragePrecision
0.35...
0.14...
>>> metrics.ndcgAt(3)
0.33...
>>> metrics.ndcgAt(10)
Expand Down