The trouble with 'ntile()'

原始链接: https://blog.djnavarro.net/posts/2026-09-20_the-trouble-with-ntile/

Hacker News new | past | comments | ask | show | jobs | submit login The trouble with 'ntile()' ( djnavarro.net ) 21 points by luu 8 hours ago | hide | past | favorite | 1 comment help tmoertel 4 hours ago [–] Tl;dr: The trouble with ntile seems to be that, when the author of the post imagined what it did based solely on its name and she imagined wrong, she ran with her imaginary version way too long before checking the documentation, which was very clear about its behavior: > Unlike other ranking functions, ntile() ignores ties: it will create evenly sized buckets even if the same value of x ends up in different buckets. reply Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact Search:
相关文章

原文

You keep using that function. I do not think it does what you think it does

As longtime readers of this blog will no doubt be aware, I am a tidyverse girl. As deeply as I adore the R programming language, there are some wild things that are baked into the behaviour of base R, and a lot of what tidyverse does so very, very well is smooth over those rough edges. Whether it is data visualisation with ggplot2, data wrangling with dplyr, or navigating the hell that is string manipulation with stringr rather than grappling with the stunningly inconsistent base R regex tools, it has been a blessing. I don’t usually bother to write posts pointing out the obvious, though, so I’ve been more likely to write about a few of the less celebrated packages like fs and cli that sit underneath tidyverse and make everyone’s life a little less painful.

In short, I am a fan.

And so it is with a certain level of trepidation and regret that I find myself writing a post about something that a tidyverse package doesn’t do well. After all, who am I to criticise? I have written some truly terrible code over the years and had some very unwise choices end up in packages that people actually use. But of course that’s the point… even the very best tools have problems, even the best programmers make mistakes, etc. It’s foolish to pretend otherwise.

With that in mind, this is a post about dplyr::ntile(). It is a warning that you should not use it for any purpose where statistical accuracy is important. If you try to guess what it does based on the function name – and are one of the fortunate souls never to have worked with SQL – you will get burned when you discover what it actually does. It is emphatically not a tool for binning data into quantile-based groups, and it will absolutely misbehave when you use it for data analysis. Please be careful.

NTILE function in SQL. Just like its SQL counterpart, ntile() forces identical values to be assigned into different groups if that would produce a more “even” split of the data. In SQL though, this behaviour leads to even stranger outcomes: because databases don’t really have any inherent concept of row order the tie-breaking behaviour in NTILE is simply declared to be “nondeterministic”. All you’re really told about its behaviour is this:

If the number of rows in a partition isn’t divisible by integer_expression, this causes groups of two sizes that differ by one member. Larger groups come before smaller groups in the order specified by the OVER clause. For example, if the total number of rows is 53 and the number of groups is five, the first three groups have 11 rows and the two remaining groups have 10 rows each. If on the other hand the total number of rows is divisible by the number of groups, the rows are evenly distributed among the groups. For example, if the total number of rows is 50, and there are five groups, each bucket contains 10 rows.

NTILE prescribes the size of the groups, but not their membership or the rule that maps values to categories. Despite the painfully inappropriate similarity of name, NTILE is not in any meaningful sense a tool for quantile binning. Indeed, if the ORDER BY clause in an NTILE expression produces ties at the breaks… well, who even knows what it will do? It’s “nondeterministic”, which most certainly is not the same thing as “random” in this context. Breaking ties at random would be a lot less unhinged, since the statistical properties of random allocation are well understood. But breaking ties using a rule that is unknown but probably systematically related to variables that matter for your analysis? That is horrifically bad. There are perhaps some contexts in which the “quick and dirty carve up” that NTILE and ntile() provide is useful, but serious data analysis is not one of them.

And without question, neither one is suitable for regulatory work in the pharmaceuticals industry.

Appendix

Reuse

Citation

BibTeX citation:

@online{navarro2026,
  author = {Navarro, Danielle},
  title = {The Trouble with “Ntile()”},
  date = {2026-09-20},
  url = {https://blog.djnavarro.net/posts/2026-09-20_the-trouble-with-ntile/},
  langid = {en}
}

For attribution, please cite this work as:

Navarro, Danielle. 2026. “The Trouble with ‘Ntile()’.” September 20. https://blog.djnavarro.net/posts/2026-09-20_the-trouble-with-ntile/.
联系我们 contact @ memedata.com