Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/ntp_snippets/user_classifier.h" | 5 #include "components/ntp_snippets/user_classifier.h" |
| 6 | 6 |
| 7 #include <float.h> | 7 #include <float.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <string> | 10 #include <string> |
| 11 | 11 |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "components/ntp_snippets/features.h" | |
| 14 #include "components/ntp_snippets/pref_names.h" | 15 #include "components/ntp_snippets/pref_names.h" |
| 15 #include "components/prefs/pref_registry_simple.h" | 16 #include "components/prefs/pref_registry_simple.h" |
| 16 #include "components/prefs/pref_service.h" | 17 #include "components/prefs/pref_service.h" |
| 18 #include "components/variations/variations_associated_data.h" | |
| 17 | 19 |
| 18 namespace ntp_snippets { | 20 namespace ntp_snippets { |
| 19 | 21 |
| 20 namespace { | 22 namespace { |
| 21 | 23 |
| 22 // TODO(jkrcal): Make all of this configurable via variations_service. | |
| 23 | |
| 24 // The discount factor for computing the discounted-average metrics. Must be | 24 // The discount factor for computing the discounted-average metrics. Must be |
| 25 // strictly larger than 0 and strictly smaller than 1! | 25 // strictly larger than 0 and strictly smaller than 1! |
| 26 const double kDiscountFactorPerDay = 0.25; | 26 const double kDiscountFactorPerDay = 0.25; |
| 27 const char kDiscountFactorPerDayParam[] = | |
| 28 "user_classifier_discount_factor_per_day"; | |
| 27 | 29 |
| 28 // Never consider any larger interval than this (so that extreme situations such | 30 // Never consider any larger interval than this (so that extreme situations such |
| 29 // as losing your phone or going for a long offline vacation do not skew the | 31 // as losing your phone or going for a long offline vacation do not skew the |
| 30 // average too much). | 32 // average too much). |
| 31 const double kMaxHours = 7 * 24; | 33 const double kMaxHours = 7 * 24; |
| 34 const char kMaxHoursParam[] = | |
| 35 "user_classifier_max_hours"; | |
|
Marc Treib
2016/09/22 12:29:05
fits on the previous line
jkrcal
2016/09/22 13:26:15
Done.
| |
| 32 | 36 |
| 33 // Ignore events within |kMinHours| hours since the last event (|kMinHours| is | 37 // Ignore events within |kMinHours| hours since the last event (|kMinHours| is |
| 34 // the length of the browsing session where subsequent events of the same type | 38 // the length of the browsing session where subsequent events of the same type |
| 35 // do not count again). | 39 // do not count again). |
| 36 const double kMinHours = 0.5; | 40 const double kMinHours = 0.5; |
| 41 const char kMinHoursParam[] = | |
| 42 "user_classifier_min_hours"; | |
|
Marc Treib
2016/09/22 12:29:05
here too
jkrcal
2016/09/22 13:26:15
Done.
| |
| 37 | 43 |
| 38 // Classification constants. | 44 // Classification constants. |
| 39 const double kFrequentUserScrollsAtLeastOncePerHours = 24; | 45 const double kActiveConsumerScrollsAtLeastOncePerHours = 24; |
| 40 const double kOccasionalUserOpensNTPAtMostOncePerHours = 72; | 46 const char kActiveConsumerScrollsAtLeastOncePerHoursParam[] = |
| 47 "user_classifier_active_consumer_scrolls_at_least_once_per_hours"; | |
| 41 | 48 |
| 49 const double kActiveConsumerOpensNTPAtLeastOncePerHours = 24; | |
| 50 const char kActiveConsumerOpensNTPAtLeastOncePerHoursParam[] = | |
| 51 "user_classifier_active_consumer_opens_ntp_at_least_once_per_hours"; | |
| 52 | |
| 53 const double kRareUserOpensNTPAtMostOncePerHours = 72; | |
| 54 const char kRareUserOpensNTPAtMostOncePerHoursParam[] = | |
| 55 "user_classifier_rare_user_opens_ntp_at_most_once_per_hours"; | |
| 56 | |
| 57 // Histograms for logging the estimated average hours to next event. | |
| 42 const char kHistogramAverageHoursToOpenNTP[] = | 58 const char kHistogramAverageHoursToOpenNTP[] = |
| 43 "NewTabPage.UserClassifier.AverageHoursToOpenNTP"; | 59 "NewTabPage.UserClassifier.AverageHoursToOpenNTP"; |
| 44 const char kHistogramAverageHoursToShowSuggestions[] = | 60 const char kHistogramAverageHoursToShowSuggestions[] = |
| 45 "NewTabPage.UserClassifier.AverageHoursToShowSuggestions"; | 61 "NewTabPage.UserClassifier.AverageHoursToShowSuggestions"; |
| 46 const char kHistogramAverageHoursToUseSuggestions[] = | 62 const char kHistogramAverageHoursToUseSuggestions[] = |
| 47 "NewTabPage.UserClassifier.AverageHoursToUseSuggestions"; | 63 "NewTabPage.UserClassifier.AverageHoursToUseSuggestions"; |
| 48 | 64 |
| 49 // The enum used for iteration. | 65 // The enum used for iteration. |
| 50 const UserClassifier::Metric kMetrics[] = { | 66 const UserClassifier::Metric kMetrics[] = { |
| 51 UserClassifier::Metric::NTP_OPENED, | 67 UserClassifier::Metric::NTP_OPENED, |
| 52 UserClassifier::Metric::SUGGESTIONS_SHOWN, | 68 UserClassifier::Metric::SUGGESTIONS_SHOWN, |
| 53 UserClassifier::Metric::SUGGESTIONS_USED}; | 69 UserClassifier::Metric::SUGGESTIONS_USED}; |
| 54 | 70 |
| 55 // The summary of the prefs. | 71 // The summary of the prefs. |
| 56 const char* kMetricKeys[] = { | 72 const char* kMetricKeys[] = { |
| 57 prefs::kUserClassifierAverageNTPOpenedPerHour, | 73 prefs::kUserClassifierAverageNTPOpenedPerHour, |
| 58 prefs::kUserClassifierAverageSuggestionsShownPerHour, | 74 prefs::kUserClassifierAverageSuggestionsShownPerHour, |
| 59 prefs::kUserClassifierAverageSuggestionsUsedPerHour}; | 75 prefs::kUserClassifierAverageSuggestionsUsedPerHour}; |
| 60 const char* kLastTimeKeys[] = {prefs::kUserClassifierLastTimeToOpenNTP, | 76 const char* kLastTimeKeys[] = {prefs::kUserClassifierLastTimeToOpenNTP, |
| 61 prefs::kUserClassifierLastTimeToShowSuggestions, | 77 prefs::kUserClassifierLastTimeToShowSuggestions, |
| 62 prefs::kUserClassifierLastTimeToUseSuggestions}; | 78 prefs::kUserClassifierLastTimeToUseSuggestions}; |
| 63 | 79 |
| 64 // Default lengths of the intervals for new users for the metrics. | 80 // Default lengths of the intervals for new users for the metrics. |
| 65 const double kDefaults[] = {24, 36, 48}; | 81 const double kDefaults[] = {24, 36, 48}; |
| 82 const char* kDefaultParams[] = { | |
|
Marc Treib
2016/09/22 12:29:05
I think these could use a bit more descriptive nam
jkrcal
2016/09/22 13:26:14
Done.
| |
| 83 "user_classifier_default_interval_ntp_opened", | |
| 84 "user_classifier_default_interval_suggestions_shown", | |
| 85 "user_classifier_default_interval_suggestions_used"}; | |
| 66 | 86 |
| 67 static_assert(arraysize(kMetrics) == | 87 static_assert(arraysize(kMetrics) == |
| 68 static_cast<int>(UserClassifier::Metric::COUNT) && | 88 static_cast<int>(UserClassifier::Metric::COUNT) && |
| 69 arraysize(kMetricKeys) == | 89 arraysize(kMetricKeys) == |
| 70 static_cast<int>(UserClassifier::Metric::COUNT) && | 90 static_cast<int>(UserClassifier::Metric::COUNT) && |
| 71 arraysize(kLastTimeKeys) == | 91 arraysize(kLastTimeKeys) == |
| 72 static_cast<int>(UserClassifier::Metric::COUNT) && | 92 static_cast<int>(UserClassifier::Metric::COUNT) && |
| 73 arraysize(kDefaults) == | 93 arraysize(kDefaults) == |
| 74 static_cast<int>(UserClassifier::Metric::COUNT), | 94 static_cast<int>(UserClassifier::Metric::COUNT), |
|
Marc Treib
2016/09/22 12:29:05
Add kDefaultParams?
jkrcal
2016/09/22 13:26:15
Done.
| |
| 75 "Fill in info for all metrics."); | 95 "Fill in info for all metrics."); |
| 76 | 96 |
| 97 double GetParamValue(const char* param_name, double default_value) { | |
| 98 std::string param_value_str = variations::GetVariationParamValueByFeature( | |
| 99 kArticleSuggestionsFeature, param_name); | |
| 100 double param_value = 0; | |
| 101 if (!base::StringToDouble(param_value_str, ¶m_value)) { | |
| 102 LOG_IF(WARNING, !param_value_str.empty()) | |
| 103 << "Invalid variation parameter for " << param_name; | |
| 104 return default_value; | |
| 105 } | |
| 106 return param_value; | |
| 107 } | |
| 108 | |
| 77 // Computes the discount rate. | 109 // Computes the discount rate. |
| 78 double GetDiscountRatePerHour() { | 110 double GetDiscountRatePerHour() { |
| 111 double discount_factor_per_day = | |
| 112 GetParamValue(kDiscountFactorPerDayParam, kDiscountFactorPerDay); | |
| 79 // Compute discount_rate_per_hour such that | 113 // Compute discount_rate_per_hour such that |
| 80 // kDiscountFactorPerDay = 1 - e^{-discount_rate_per_hour * 24}. | 114 // discount_factor_per_day = 1 - e^{-discount_rate_per_hour * 24}. |
| 81 return std::log(1.0 / (1.0 - kDiscountFactorPerDay)) / 24.0; | 115 return std::log(1.0 / (1.0 - discount_factor_per_day)) / 24.0; |
| 116 } | |
| 117 | |
| 118 double GetDefaultEstimate(UserClassifier::Metric metric) { | |
|
Marc Treib
2016/09/22 12:29:05
GetDefaultEstimateHoursBetweenEvents or GetInitial
jkrcal
2016/09/22 13:26:15
Done. GetInitialHoursBetweenEvents to match the co
| |
| 119 return GetParamValue(kDefaultParams[static_cast<int>(metric)], | |
| 120 kDefaults[static_cast<int>(metric)]); | |
| 121 } | |
| 122 | |
| 123 double GetMinHours() { | |
| 124 return GetParamValue(kMinHoursParam, kMinHours); | |
| 125 } | |
| 126 | |
| 127 double GetMaxHours() { | |
| 128 return GetParamValue(kMaxHoursParam, kMaxHours); | |
| 82 } | 129 } |
| 83 | 130 |
| 84 // Returns the new value of the metric using its |old_value|, assuming | 131 // Returns the new value of the metric using its |old_value|, assuming |
| 85 // |hours_since_last_time| hours have passed since it was last discounted. | 132 // |hours_since_last_time| hours have passed since it was last discounted. |
| 86 double DiscountMetric(double old_value, | 133 double DiscountMetric(double old_value, |
| 87 double hours_since_last_time, | 134 double hours_since_last_time, |
| 88 double discount_rate_per_hour) { | 135 double discount_rate_per_hour) { |
| 89 // Compute the new discounted average according to the formula | 136 // Compute the new discounted average according to the formula |
| 90 // avg_events := e^{-discount_rate_per_hour * hours_since} * avg_events | 137 // avg_events := e^{-discount_rate_per_hour * hours_since} * avg_events |
| 91 return std::exp(-discount_rate_per_hour * hours_since_last_time) * old_value; | 138 return std::exp(-discount_rate_per_hour * hours_since_last_time) * old_value; |
| 92 } | 139 } |
| 93 | 140 |
| 94 // Compute the number of hours between two events for the given metric value | 141 // Compute the number of hours between two events for the given metric value |
| 95 // assuming the events were equally distributed. | 142 // assuming the events were equally distributed. |
| 96 double GetEstimateHoursBetweenEvents(double metric_value, | 143 double GetEstimateHoursBetweenEvents(double metric_value, |
| 97 double discount_rate_per_hour) { | 144 double discount_rate_per_hour, |
| 145 double min_hours, | |
| 146 double max_hours) { | |
| 98 // The computation below is well-defined only for |metric_value| > 1 (log of | 147 // The computation below is well-defined only for |metric_value| > 1 (log of |
| 99 // negative value or division by zero). When |metric_value| -> 1, the estimate | 148 // negative value or division by zero). When |metric_value| -> 1, the estimate |
| 100 // below -> infinity, so kMaxHours is a natural result, here. | 149 // below -> infinity, so max_hours is a natural result, here. |
| 101 if (metric_value <= 1) | 150 if (metric_value <= 1) |
| 102 return kMaxHours; | 151 return max_hours; |
| 103 | 152 |
| 104 // This is the estimate with the assumption that last event happened right | 153 // This is the estimate with the assumption that last event happened right |
| 105 // now and the system is in the steady-state. Solve estimate_hours in the | 154 // now and the system is in the steady-state. Solve estimate_hours in the |
| 106 // steady-state equation: | 155 // steady-state equation: |
| 107 // metric_value = 1 + e^{-discount_rate * estimate_hours} * metric_value, | 156 // metric_value = 1 + e^{-discount_rate * estimate_hours} * metric_value, |
| 108 // i.e. | 157 // i.e. |
| 109 // -discount_rate * estimate_hours = log((metric_value - 1) / metric_value), | 158 // -discount_rate * estimate_hours = log((metric_value - 1) / metric_value), |
| 110 // discount_rate * estimate_hours = log(metric_value / (metric_value - 1)), | 159 // discount_rate * estimate_hours = log(metric_value / (metric_value - 1)), |
| 111 // estimate_hours = log(metric_value / (metric_value - 1)) / discount_rate. | 160 // estimate_hours = log(metric_value / (metric_value - 1)) / discount_rate. |
| 112 double estimate_hours = | 161 double estimate_hours = |
| 113 std::log(metric_value / (metric_value - 1)) / discount_rate_per_hour; | 162 std::log(metric_value / (metric_value - 1)) / discount_rate_per_hour; |
| 114 return std::max(kMinHours, std::min(kMaxHours, estimate_hours)); | 163 return std::max(min_hours, std::min(max_hours, estimate_hours)); |
| 115 } | 164 } |
| 116 | 165 |
| 117 // The inverse of GetEstimateHoursBetweenEvents(). | 166 // The inverse of GetEstimateHoursBetweenEvents(). |
| 118 double GetMetricValueForEstimateHoursBetweenEvents( | 167 double GetMetricValueForEstimateHoursBetweenEvents( |
| 119 double estimate_hours, | 168 double estimate_hours, |
| 120 double discount_rate_per_hour) { | 169 double discount_rate_per_hour, |
| 121 // Keep the input value within [kMinHours, kMaxHours]. | 170 double min_hours, |
| 122 estimate_hours = std::max(kMinHours, std::min(kMaxHours, estimate_hours)); | 171 double max_hours) { |
| 123 | 172 // Keep the input value within [min_hours, max_hours]. |
| 173 estimate_hours = std::max(min_hours, std::min(max_hours, estimate_hours)); | |
| 124 // Return |metric_value| such that GetEstimateHoursBetweenEvents for | 174 // Return |metric_value| such that GetEstimateHoursBetweenEvents for |
| 125 // |metric_value| returns |estimate_hours|. Thus, solve |metric_value| in | 175 // |metric_value| returns |estimate_hours|. Thus, solve |metric_value| in |
| 126 // metric_value = 1 + e^{-discount_rate * estimate_hours} * metric_value, | 176 // metric_value = 1 + e^{-discount_rate * estimate_hours} * metric_value, |
| 127 // i.e. | 177 // i.e. |
| 128 // metric_value * (1 - e^{-discount_rate * estimate_hours}) = 1, | 178 // metric_value * (1 - e^{-discount_rate * estimate_hours}) = 1, |
| 129 // metric_value = 1 / (1 - e^{-discount_rate * estimate_hours}). | 179 // metric_value = 1 / (1 - e^{-discount_rate * estimate_hours}). |
| 130 return 1.0 / (1.0 - std::exp(-discount_rate_per_hour * estimate_hours)); | 180 return 1.0 / (1.0 - std::exp(-discount_rate_per_hour * estimate_hours)); |
| 131 } | 181 } |
| 132 | 182 |
| 133 } // namespace | 183 } // namespace |
| 134 | 184 |
| 135 UserClassifier::UserClassifier(PrefService* pref_service) | 185 UserClassifier::UserClassifier(PrefService* pref_service) |
| 136 : pref_service_(pref_service), | 186 : pref_service_(pref_service), |
| 137 discount_rate_per_hour_(GetDiscountRatePerHour()) { | 187 discount_rate_per_hour_(GetDiscountRatePerHour()), |
| 188 min_hours_(GetMinHours()), | |
| 189 max_hours_(GetMaxHours()), | |
| 190 active_consumer_scrolls_at_least_once_per_hours_( | |
| 191 GetParamValue(kActiveConsumerScrollsAtLeastOncePerHoursParam, | |
| 192 kActiveConsumerScrollsAtLeastOncePerHours)), | |
| 193 active_consumer_opens_ntp_at_least_once_per_hours_( | |
| 194 GetParamValue(kActiveConsumerOpensNTPAtLeastOncePerHoursParam, | |
| 195 kActiveConsumerOpensNTPAtLeastOncePerHours)), | |
| 196 rare_user_opens_ntp_at_most_once_per_hours_( | |
| 197 GetParamValue(kRareUserOpensNTPAtMostOncePerHoursParam, | |
| 198 kRareUserOpensNTPAtMostOncePerHours)) { | |
| 138 // The pref_service_ can be null in tests. | 199 // The pref_service_ can be null in tests. |
| 139 if (!pref_service_) | 200 if (!pref_service_) |
| 140 return; | 201 return; |
| 141 | 202 |
| 203 // TODO(jkrcal): Store the current discount rate per hour into prefs. If it | |
| 204 // differs from the previous value, rescale the metric values so that the | |
| 205 // expectation does not change abruptly! | |
| 206 | |
| 142 // Initialize the prefs storing the last time: the counter has just started! | 207 // Initialize the prefs storing the last time: the counter has just started! |
| 143 for (const Metric metric : kMetrics) { | 208 for (const Metric metric : kMetrics) { |
| 144 if (!HasLastTime(metric)) | 209 if (!HasLastTime(metric)) |
| 145 SetLastTimeToNow(metric); | 210 SetLastTimeToNow(metric); |
| 146 } | 211 } |
| 147 } | 212 } |
| 148 | 213 |
| 149 UserClassifier::~UserClassifier() {} | 214 UserClassifier::~UserClassifier() {} |
| 150 | 215 |
| 151 // static | 216 // static |
| 152 void UserClassifier::RegisterProfilePrefs(PrefRegistrySimple* registry) { | 217 void UserClassifier::RegisterProfilePrefs(PrefRegistrySimple* registry) { |
| 218 double discount_rate = GetDiscountRatePerHour(); | |
| 219 double min_hours = GetMinHours(); | |
| 220 double max_hours = GetMaxHours(); | |
| 221 | |
| 153 for (Metric metric : kMetrics) { | 222 for (Metric metric : kMetrics) { |
| 154 double default_metric_value = GetMetricValueForEstimateHoursBetweenEvents( | 223 double default_metric_value = GetMetricValueForEstimateHoursBetweenEvents( |
| 155 kDefaults[static_cast<int>(metric)], GetDiscountRatePerHour()); | 224 GetDefaultEstimate(metric), discount_rate, min_hours, max_hours); |
| 156 registry->RegisterDoublePref(kMetricKeys[static_cast<int>(metric)], | 225 registry->RegisterDoublePref(kMetricKeys[static_cast<int>(metric)], |
| 157 default_metric_value); | 226 default_metric_value); |
| 158 registry->RegisterInt64Pref(kLastTimeKeys[static_cast<int>(metric)], 0); | 227 registry->RegisterInt64Pref(kLastTimeKeys[static_cast<int>(metric)], 0); |
| 159 } | 228 } |
| 160 } | 229 } |
| 161 | 230 |
| 162 void UserClassifier::OnEvent(Metric metric) { | 231 void UserClassifier::OnEvent(Metric metric) { |
| 163 DCHECK_NE(metric, Metric::COUNT); | 232 DCHECK_NE(metric, Metric::COUNT); |
| 164 double metric_value = UpdateMetricOnEvent(metric); | 233 double metric_value = UpdateMetricOnEvent(metric); |
| 165 | 234 |
| 166 double avg = | 235 double avg = GetEstimateHoursBetweenEvents( |
| 167 GetEstimateHoursBetweenEvents(metric_value, discount_rate_per_hour_); | 236 metric_value, discount_rate_per_hour_, min_hours_, max_hours_); |
| 168 switch (metric) { | 237 switch (metric) { |
| 169 case Metric::NTP_OPENED: | 238 case Metric::NTP_OPENED: |
| 170 UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToOpenNTP, avg, 1, | 239 UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToOpenNTP, avg, 1, |
| 171 kMaxHours, 50); | 240 kMaxHours, 50); |
|
Marc Treib
2016/09/22 12:29:05
Hm, so the histograms still use kMaxHours rather t
jkrcal
2016/09/22 13:26:14
Oh, I missed this, thanks! Comments added.
| |
| 172 break; | 241 break; |
| 173 case Metric::SUGGESTIONS_SHOWN: | 242 case Metric::SUGGESTIONS_SHOWN: |
| 174 UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToShowSuggestions, avg, | 243 UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToShowSuggestions, avg, |
| 175 1, kMaxHours, 50); | 244 1, kMaxHours, 50); |
| 176 break; | 245 break; |
| 177 case Metric::SUGGESTIONS_USED: | 246 case Metric::SUGGESTIONS_USED: |
| 178 UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToUseSuggestions, avg, | 247 UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToUseSuggestions, avg, |
| 179 1, kMaxHours, 50); | 248 1, kMaxHours, 50); |
| 180 break; | 249 break; |
| 181 case Metric::COUNT: | 250 case Metric::COUNT: |
| 182 NOTREACHED(); | 251 NOTREACHED(); |
| 183 break; | 252 break; |
| 184 } | 253 } |
| 185 } | 254 } |
| 186 | 255 |
| 187 double UserClassifier::GetEstimatedAvgTime(Metric metric) const { | 256 double UserClassifier::GetEstimatedAvgTime(Metric metric) const { |
| 188 DCHECK_NE(metric, Metric::COUNT); | 257 DCHECK_NE(metric, Metric::COUNT); |
| 189 double metric_value = GetUpToDateMetricValue(metric); | 258 double metric_value = GetUpToDateMetricValue(metric); |
| 190 return GetEstimateHoursBetweenEvents(metric_value, discount_rate_per_hour_); | 259 return GetEstimateHoursBetweenEvents(metric_value, discount_rate_per_hour_, |
| 260 min_hours_, max_hours_); | |
| 191 } | 261 } |
| 192 | 262 |
| 193 UserClassifier::UserClass UserClassifier::GetUserClass() const { | 263 UserClassifier::UserClass UserClassifier::GetUserClass() const { |
| 194 if (GetEstimatedAvgTime(Metric::NTP_OPENED) >= | 264 double avg_time_to_ntp = GetEstimatedAvgTime(Metric::NTP_OPENED); |
| 195 kOccasionalUserOpensNTPAtMostOncePerHours) { | 265 |
| 266 if (avg_time_to_ntp >= rare_user_opens_ntp_at_most_once_per_hours_) { | |
| 196 return UserClass::RARE_NTP_USER; | 267 return UserClass::RARE_NTP_USER; |
| 197 } | 268 } |
| 198 | 269 |
| 199 if (GetEstimatedAvgTime(Metric::SUGGESTIONS_SHOWN) <= | 270 double avg_time_to_scroll = GetEstimatedAvgTime(Metric::SUGGESTIONS_SHOWN); |
| 200 kFrequentUserScrollsAtLeastOncePerHours) { | 271 |
| 272 if (avg_time_to_ntp <= active_consumer_opens_ntp_at_least_once_per_hours_ && | |
| 273 avg_time_to_scroll <= active_consumer_scrolls_at_least_once_per_hours_) { | |
| 201 return UserClass::ACTIVE_SUGGESTIONS_CONSUMER; | 274 return UserClass::ACTIVE_SUGGESTIONS_CONSUMER; |
| 202 } | 275 } |
| 203 | 276 |
| 204 return UserClass::ACTIVE_NTP_USER; | 277 return UserClass::ACTIVE_NTP_USER; |
| 205 } | 278 } |
| 206 | 279 |
| 207 std::string UserClassifier::GetUserClassDescriptionForDebugging() const { | 280 std::string UserClassifier::GetUserClassDescriptionForDebugging() const { |
| 208 switch (GetUserClass()) { | 281 switch (GetUserClass()) { |
| 209 case UserClass::RARE_NTP_USER: | 282 case UserClass::RARE_NTP_USER: |
| 210 return "Rare user of the NTP"; | 283 return "Rare user of the NTP"; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 227 SetLastTimeToNow(metric); | 300 SetLastTimeToNow(metric); |
| 228 } | 301 } |
| 229 } | 302 } |
| 230 | 303 |
| 231 double UserClassifier::UpdateMetricOnEvent(Metric metric) { | 304 double UserClassifier::UpdateMetricOnEvent(Metric metric) { |
| 232 // The pref_service_ can be null in tests. | 305 // The pref_service_ can be null in tests. |
| 233 if (!pref_service_) | 306 if (!pref_service_) |
| 234 return 0; | 307 return 0; |
| 235 | 308 |
| 236 double hours_since_last_time = | 309 double hours_since_last_time = |
| 237 std::min(kMaxHours, GetHoursSinceLastTime(metric)); | 310 std::min(max_hours_, GetHoursSinceLastTime(metric)); |
| 238 // Ignore events within the same "browsing session". | 311 // Ignore events within the same "browsing session". |
| 239 if (hours_since_last_time < kMinHours) | 312 if (hours_since_last_time < min_hours_) |
| 240 return GetUpToDateMetricValue(metric); | 313 return GetUpToDateMetricValue(metric); |
| 241 | 314 |
| 242 SetLastTimeToNow(metric); | 315 SetLastTimeToNow(metric); |
| 243 | 316 |
| 244 double metric_value = GetMetricValue(metric); | 317 double metric_value = GetMetricValue(metric); |
| 245 // Add 1 to the discounted metric as the event has happened right now. | 318 // Add 1 to the discounted metric as the event has happened right now. |
| 246 double new_metric_value = | 319 double new_metric_value = |
| 247 1 + DiscountMetric(metric_value, hours_since_last_time, | 320 1 + DiscountMetric(metric_value, hours_since_last_time, |
| 248 discount_rate_per_hour_); | 321 discount_rate_per_hour_); |
| 249 SetMetricValue(metric, new_metric_value); | 322 SetMetricValue(metric, new_metric_value); |
| 250 return new_metric_value; | 323 return new_metric_value; |
| 251 } | 324 } |
| 252 | 325 |
| 253 double UserClassifier::GetUpToDateMetricValue(Metric metric) const { | 326 double UserClassifier::GetUpToDateMetricValue(Metric metric) const { |
| 254 // The pref_service_ can be null in tests. | 327 // The pref_service_ can be null in tests. |
| 255 if (!pref_service_) | 328 if (!pref_service_) |
| 256 return 0; | 329 return 0; |
| 257 | 330 |
| 258 double hours_since_last_time = | 331 double hours_since_last_time = |
| 259 std::min(kMaxHours, GetHoursSinceLastTime(metric)); | 332 std::min(max_hours_, GetHoursSinceLastTime(metric)); |
| 260 | 333 |
| 261 double metric_value = GetMetricValue(metric); | 334 double metric_value = GetMetricValue(metric); |
| 262 return DiscountMetric(metric_value, hours_since_last_time, | 335 return DiscountMetric(metric_value, hours_since_last_time, |
| 263 discount_rate_per_hour_); | 336 discount_rate_per_hour_); |
| 264 } | 337 } |
| 265 | 338 |
| 266 double UserClassifier::GetHoursSinceLastTime(Metric metric) const { | 339 double UserClassifier::GetHoursSinceLastTime(Metric metric) const { |
| 267 if (!HasLastTime(metric)) | 340 if (!HasLastTime(metric)) |
| 268 return 0; | 341 return 0; |
| 269 | 342 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 288 | 361 |
| 289 void UserClassifier::SetMetricValue(Metric metric, double metric_value) { | 362 void UserClassifier::SetMetricValue(Metric metric, double metric_value) { |
| 290 pref_service_->SetDouble(kMetricKeys[static_cast<int>(metric)], metric_value); | 363 pref_service_->SetDouble(kMetricKeys[static_cast<int>(metric)], metric_value); |
| 291 } | 364 } |
| 292 | 365 |
| 293 void UserClassifier::ClearMetricValue(Metric metric) { | 366 void UserClassifier::ClearMetricValue(Metric metric) { |
| 294 pref_service_->ClearPref(kMetricKeys[static_cast<int>(metric)]); | 367 pref_service_->ClearPref(kMetricKeys[static_cast<int>(metric)]); |
| 295 } | 368 } |
| 296 | 369 |
| 297 } // namespace ntp_snippets | 370 } // namespace ntp_snippets |
| OLD | NEW |