Sign in

Gilles Colling

@gilles-colling.bsky.social
28 followers 27 following 113 posts

PhD researcher in biology, studying alien plant species and global change. Background in numerical physics and astrophysics.

PostsRepliesMedia
Gilles Colling @gilles-colling.bsky.social · 07/04/2026
Third use-after-free in a month. Only triggers above 4 million points — never shows up in testing. Rewrite the backend in Rust. The borrow checker catches out-of-bounds errors at COMPILE time that would've been segfaults weeks later. 1/3
110
Gilles Colling @gilles-colling.bsky.social · 07/04/2026
Puzzle: how many copies does x$a[1] <- 99L trigger on a data.frame? TWO. One value changed, two full copies made. A data.frame is a list of column vectors. The list and each column are separate objects with separate reference counts. Modify one column and R copies the column AND the container. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 07/04/2026
5 km apart: 73% species overlap. 50 km: 31%. 200 km: 8%. Fitting the decay curve takes five minutes. But the residuals are where it gets interesting — pairs at the same distance that are consistently more or less similar than predicted. 1/3
100
Gilles Colling @gilles-colling.bsky.social · 07/04/2026
Relative abundance went up 30%. Which part moved — focal species increased, or everything else decreased? A ratio collapses two biological processes into one number. Can't tell which drove it. numdenom fits numerator and denominator as a joint model with shared random effects. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 07/04/2026
Square grid cells at the equator are 2x the area of cells at 60°N. Bigger cells capture more observations — and if a spatial process spans more than a few degrees of latitude, that area distortion might mess up ALL the downstream statistics. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 03/04/2026
New alien plant species per decade in Austria: 1950s → 14 2010s → 47 No plateau. The rate itself is accelerating. #biodiversity
010
Gilles Colling @gilles-colling.bsky.social · 03/04/2026
VIF says drop temperature. But there are 23 valid subsets of uncorrelated variables — and temperature survives in 19 of them. VIF picked one subset and hid the other 22. corrselect enumerates ALL of them. You choose. #rstats
021
Gilles Colling @gilles-colling.bsky.social · 03/04/2026
left_join() with relationship = "many-to-many" suppresses the warning. But a warning you can silence isn't a contract. join_strict() makes cardinality explicit: 1:1, 1:many, many:many. State what you expect. Get a hard error when it's violated. #rstats
000
Gilles Colling @gilles-colling.bsky.social · 03/04/2026
80% of eBird checklists in Austria are within 500m of a parking lot. That species gradient you're mapping? It's a gradient of where people stop their cars. #ecology
020
Gilles Colling @gilles-colling.bsky.social · 03/04/2026
Relative abundance went up 30%. Sounds like good news — until you realize the focal species stayed flat and everything else crashed. A ratio can't tell you which side moved. numdenom models numerator and denominator jointly so you actually know. #rstats
000
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
100 species observed. Is that 100 out of 100 or 100 out of 300? Extrapolation curves flatten when sampling is near-complete — each additional sample adds almost nothing. 1/3
110
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Package depends on X. X depends on Y. Y breaks on the new R release. Your package breaks and you didn't change a single line. Every Imports entry is a bet that the maintainer will keep up with R-core's release cycle. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Run richness at 1 km, 10 km, 100 km. Hotspots invert. The pattern you find depends on the grain you chose. If your conclusions flip at a different resolution, the resolution IS the finding. #ecology
000
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Without `force(x)`: "before" prints, then nothing — `x` is never evaluated because nothing used it. Arguments in R aren't evaluated when the function is CALLED. They're evaluated when they're first ACCESSED. This is lazy evaluation. 1/3
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Point falls on the boundary between two polygons. Which one gets it? Depends on the algorithm, the floating-point precision, and sometimes the order of polygons in the file. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
R's own functions: `is.numeric`, `as.data.frame`, `read.csv`, `seq.int`. Base R chose dot.case decades ago. Writing `is_numeric` next to `is.numeric` in the same pipe creates visual noise. Match the ecosystem. #rstats
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
The species list says 120 species COULD live here based on habitat and climate. You observed 74. That gap — 46 species absent from suitable habitat — is dark diversity. High observed richness with low dark diversity: the community is saturated. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
`g()` sees `x` because R uses LEXICAL scoping — functions look up variables in the environment where they were DEFINED, not where they were called. `g` was defined inside `f`, so `g`'s parent environment is `f`'s execution environment. This is why closures work. 1/3
110
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Variables as nodes. Draw edges where correlation exceeds the threshold. Take the complement graph — flip every edge. Now every maximal clique in the complement is a valid subset where NO pair exceeds the threshold. Bron-Kerbosch (1973) finds ALL maximal cliques. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Zero rows. One row. NA in the key column. Duplicate keys. Column name with a space. Factor with unused levels. These aren't exotic inputs. They show up in real pipelines every week. If your function hasn't been tested against each one, it works on demos, not data. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
80% of eBird checklists in Austria are within 500m of a parking lot. The species gradient tracks access, not ecology. Any spatial model trained on this data learns where birders walk, not where birds live. #ecology
000
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
This isn't a string. It's a LANGUAGE OBJECT with class `formula`. R parsed it into an abstract syntax tree — `~` is the root, left branch is `y`, right branch is `+` with children `x1` and `x2`. Every modelling function in R walks this tree. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Mahalanobis distance on a full community matrix. Species that co-occur in weird combinations light up as multivariate outliers — BORG flags the records, you decide what they mean. One function, no training step. #rstats
000
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Profile first. The inner loop runs 10 million times. Vectorized R: 4.2 seconds. Rewrite JUST that loop in C++: 0.08 seconds. Rcpp isn't a style choice. It's a scalpel. Find the bottleneck with `profvis`, confirm it's a tight loop that can't vectorize, rewrite THAT function. 1/2
200
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Overall trend: species A is declining. Split by habitat: increasing in forests, increasing in grasslands, increasing in wetlands. Every habitat shows a gain. The aggregate shows a loss. How? Sampling effort shifted toward habitats where the species was ALREADY rare. 1/3
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Six equidistant neighbors. Every neighbor shares an edge, not a corner. No orientation bias — north-south and east-west distances are equal. Squares can't do any of this. Hexagons are the spatial unit your analysis deserves. #rstats
000
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
42 million rows. You need 3 columns and records from 2024. Loading the whole file to filter afterward wastes RAM on data you're about to throw away. Filter runs inside the parser. Non-matching rows are skipped as raw bytes — never tokenized, never allocated. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
y doesn't copy anything. R just points two names at the same memory. The moment you write `y[1] <- 99L`, R copies the ENTIRE vector — 40 MB — to keep x unchanged. This is copy-on-modify. It's why "R is slow" complaints often come from code that triggers copies inside loops. Modify in place? 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Add sites from south to north. Richness climbs fast — looks like a latitudinal gradient. Randomize the order. Same sites, same species, slower climb. The curve shape reflects the ORDER you added sites, not the diversity of the landscape. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 30/03/2026
Pipe a grouped tibble into a function that doesn't expect groups. No error. Silent wrong results. keyed tags the key columns as metadata — downstream functions can CHECK whether the data is grouped by what they expect before running. #rstats
000
Gilles Colling @gilles-colling.bsky.social · 29/03/2026
You deleted every variable in your workspace. The function you defined five minutes ago still returns 10. f <- local({ x <- 10; function() x }) rm(list = ls()) f() # 10 That x lives inside the function itself. 1/4
100
Gilles Colling @gilles-colling.bsky.social · 28/03/2026
First CRAN submission to acceptance: 11 days, three rounds. The first rejection was one missing tag in one documentation file. #rstats
130
Gilles Colling @gilles-colling.bsky.social · 28/03/2026
ggguides — p + legend_inside("topright") replaces 5 lines of legend.position / legend.justification / element_rect boilerplate, returns a theme object, chains with + #rstats
161
Gilles Colling @gilles-colling.bsky.social · 28/03/2026
left_join in R is silent when keys aren't unique. It just multiplies rows. The output has more rows than the input and nothing tells you. #rstats
320
Gilles Colling @gilles-colling.bsky.social · 26/03/2026
Thinking about building occupancy models with INLA. Detection/occupancy with spatial random effects. Has anyone done this? I haven't found many examples beyond the standard textbook cases and I'm curious what the pain points are before I start. #rstats
001
Gilles Colling @gilles-colling.bsky.social · 25/03/2026
1654, Paris. A gambler rolls a single die four times and bets he'll get at least one six. He wins more often than he loses. He rolls two dice 24 times and bets on at least one double six. He loses more often than he wins. Both bets have the same expected number of successes. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 25/03/2026
Late March and the Alps still have a meter of snow above 1800m. Spent the afternoon up there. Just cold air and the sound your boots make in spring snow, that wet crunch. If you're anywhere near mountains this time of year, go. They're still winter up top and spring at the base. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 25/03/2026
Started learning Affinity Designer last week for graphical abstracts. I'm a second year PhD student and I have no idea what I'm doing in a design tool. But it's fun. One-time purchase, no subscription, no telemetry. 1/2
100
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
In the last year of my PhD I split my time roughly 80/20. Eighty percent on the research, twenty percent on side projects. Some weeks more like 60/40. The side projects taught me C++, package development, spatial algorithms, things that had nothing to do with my thesis on paper. 1/3
120
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
I wrote about this with interactive simulations where you can watch the paradox form and dissolve as you change the data. gillescolling.com/blog/simpsons-par…
000
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
Simpson's Paradox: Hospital A wins every surgery. Hospital B wins overall. Both are true. Once you see it you'll find it everywhere.
000
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
I wrote about this with interactive simulations where you can watch the paradox form and dissolve as you change the data. gillescolling.com/blog/simpsons-par…
000
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
Simpson's Paradox: Hospital A wins every surgery. Hospital B wins overall. Both are true. Once you see it you'll find it everywhere.
000
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
I wrote about this with interactive simulations where you can watch the paradox form and dissolve as you change the data. gillescolling.com/blog/simpsons-par…
000
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
Simpson's Paradox: Hospital A wins every surgery. Hospital B wins overall. Both are true. Once you see it you'll find it everywhere.
000
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
You left_join two tables. One has 10,000 rows. The result has 14,000. Where did 4,000 extra rows come from? Duplicate keys in the right table. Every duplicate multiplies your rows silently. No warning, no error, just a data frame that's 40% larger than it should be. 1/4
200
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
200 treated patients. 800 controls. Five covariates to match on. How do you pair them? Propensity scores collapse those five dimensions into one number and match on that. Clean and well-understood. But you can also solve the pairing directly in the original covariate space. 1/4
111
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
I fell in love with the R ecosystem during my PhD. Thousands of open source packages, all free. I never had to depend on Microsoft or a university license to do science. Now I write ecology packages and put them on CRAN. Independent tools for independent science. #rstats
0221
Gilles Colling @gilles-colling.bsky.social · 24/03/2026
Hello World (of BlueSky)
020
Reposted by Gilles Colling
Journal of Open Source Software @joss-openjournals.bsky.social · 25/02/2026
Just published in JOSS: 'corrselect: Fast and flexible predictor pruning for data analysis and modeling' doi.org/10.21105/joss.09539
011