Magnesium Self-Experiments

3 magnesium self-experiments on magnesium l-threonate and magnesium citrate.
nootropics, psychology, experiments, statistics, DNB, R, power-analysis, Bayes
2013-05-132020-01-31 in progress certainty: possible importance: 3


The ele­men­tal metal mag­ne­sium (Exam­ine.­com), like or potas­sium (which did­n’t help me & ), plays many and has an RDA for me of 400mg which is higher than I likely get (most peo­ple appar­ently get less, with 68% of Amer­i­can adults <RDA; and while I fre­quently eat oats, milk, peanut but­ter, and whole-wheat bread, I don’t eat many leafy greens and my tap water is very soft). The anec­dotes are the usual pos­i­tive effects: gen­eral ben­e­fits, life improve­ments, higher affect; the inter­est­ing bits are the claims that mag­ne­sium is anx­i­olytic and affects sleep (pos­i­tive­ly, if you don’t mind the increase in dream­ing, which makes me won­der if the ben­e­fits ascribed to might not be due to absorb­ing mag­ne­sium via the which pro­vide the buoy­an­cy).

L-threonate

There are a vari­ety of sub­stances to get mag­ne­sium from. Con­sid­er­able enthu­si­asm for the new com­pound was stirred by 2 small ani­mal rat stud­ies find­ing that mag­ne­sium l-thre­onate was able to increase mag­ne­sium lev­els in the brain and improve learning/memory tasks. (There are no pub­lished human tri­als as of Octo­ber 2015, and evi­dence of pub­li­ca­tion bias, which I take as evi­dence against there being large effects in human­s.) Ani­mal stud­ies mean very lit­tle, of course (see ), but I thought it’d be inter­est­ing to try using l-thre­onate, so I bought the $30 “Life Exten­sion Neu­ro-Mag Mag­ne­sium L-Thre­onate with Cal­cium and Vit­a­min D3 (205g)”, which accord­ing to the LEF prod­uct page works out to ~60g of “Magtein™ mag­ne­sium L-thre­onate” and ~4.31g ele­men­tal mag­ne­sium inas­much as LEF claims 2000mg of thre­onate pow­der pro­vides 144mg ele­men­tal mag­ne­sium or a 14:1 ratio. (I don’t need the cal­cium or vit­a­min D3, but this was the only mag­ne­sium l-thre­onate on Ama­zon.) Exper­i­men­t-wise, I’ll prob­a­bly look at sleep met­rics and Mnemosyne per­for­mance; I put off design­ing a blind self­-ex­per­i­ment until after try­ing some.

The pow­der itself is quite bulky; the rec­om­mended dose to hit 200mg of absorbed mag­ne­sium leads to ~7g of pow­der (so cap­ping will be diffi­cult) and the con­tainer pro­vides only 30 dos­es’ worth (or each dose costs $1!). It’s described as lemon-fla­vored, and it is, but it’s sick­ly-sweet unpleas­ant and since it’s so much pow­der, takes half a glass of water to dis­solve it entirely and wash it down. Sub­jec­tive­ly, I notice noth­ing after tak­ing it for a week. I may try a sim­ple A-B-A analy­sis of sleep or Mnemosyne, but I’m not opti­mistic. And given the large expense of LEF’s “Magtein”, it’s prob­a­bly a non-s­tarter even if there seems to be an effect. For sleep effects, I will have to look at more rea­son­ably priced mag­ne­sium sources.

One thing I did do was pig­gy­back on my Noopept self­-ex­per­i­ment: I blinded & ran­dom­ized the Noopept for a real exper­i­ment, but sim­ply made sure to vary the Magtein with­out wor­ry­ing about blind­ing or ran­dom­iz­ing it. (The pow­der is quite bulky.) The cor­re­la­tion the exper­i­ment turned in was a odd­s-ra­tio of 1.9; inter­est­ing and in the right direc­tion (higher is bet­ter), but since the mag­ne­sium part was­n’t ran­dom or blind, not a causal result.

Citrate

Experiment 1

Encour­aged by TruBrain’s mag­ne­sium & my mag­ne­sium l-thre­onate use, I design and run a blind ran­dom self­-ex­per­i­ment to see whether mag­ne­sium cit­rate sup­ple­men­ta­tion would improve my mood or pro­duc­tiv­i­ty. I col­lected ~200 days of data at two dose lev­els. The analy­sis finds that the net effect was neg­a­tive, but a more detailed look shows time-vary­ing effects with a large ini­tial ben­e­fit negated by an increas­ing­ly-neg­a­tive effect. Com­bined with my expec­ta­tions, the long half-life, and the high­er-than-in­tended dosage, I infer that I over­dosed on the mag­ne­sium. To ver­ify this, I will be run­ning a fol­lowup exper­i­ment with a much smaller dose.

The orig­i­nal mag­ne­sium l-thre­onate caused me no appar­ent prob­lems by the time I fin­ished off the pow­der and usage cor­re­lated with bet­ter days, fur­ther sup­port­ing the hypoth­e­sis that mag­ne­sium helps it. But l-thre­onate would be diffi­cult to cap (and hence blind self­-ex­per­i­ment) and is ruinously expen­sive on a per-dose basis. So I looked around for alter­na­tives for the fol­lowup; one of the most com­mon com­pounds sug­gested was the cit­rate form because it is rea­son­ably well-ab­sorbed and causes fewer diges­tive prob­lems, so I could just take that. Mag­ne­sium oxide is widely avail­able it looks cheap, but the absorption/bioavailability prob­lem makes it unat­trac­tive: at a 3:5 ratio, an esti­mate of 4% absorp­tion, a ZMA for­mu­la­tion of an impres­sive-sound­ing 500mg would be mg or a small frac­tion of RDAs for male adults like 400mg ele­men­tal. (Cal­cium should­n’t be a prob­lem since I get 220mg of cal­cium from my mul­ti­vi­t­a­min and I enjoy dairy prod­ucts dai­ly.)

Find­ing a usable prod­uct on Ama­zon caused me some diffi­cul­ties. I wanted a 500mg mag­ne­sium-c­i­trate-only prod­uct at <$20 for 120 dos­es, but I dis­cov­ered most of the selec­tion for “mag­ne­sium cit­rate” had sub­-500mg dos­es, involved cal­cium cit­rate or other sub­stances like zinc (not nec­es­sar­ily a bad thing, but would con­found an exper­i­men­t), were mostly mag­ne­sium oxide rather than cit­rate, or some still other prob­lem. Ulti­mately I set­tled on Sol­gar’s $13 120x400mg mag­ne­sium cit­rate as accept­able. (To com­pare with the bulk­i­ness of the LEF vit­a­min D+l-thre­onate pow­der, the Office of Dietary Sup­ple­ments says mag­ne­sium cit­rate is 16% mag­ne­sium, so to get 400mg of mag­ne­sium as claimed, would take 2.5g of mate­ri­al, rather than 7g for 200mg; even if l-thre­onate is absorbed 100% and cit­rate 50%, the cit­rate is ahead. The pills turn out to be wider and longer than my 00 pills; if I want to get them into my gel cap­sules, I have to crush them into fine pow­der. The pow­der from one pill turns out to take up 2 00 pill­s.)

My impres­sion after the first two days (2 doses of 400mg each, one with break­fast & then lunch) was pos­i­tive. I did not have the rumored diges­tion prob­lems, and the first day went excel­lent­ly: I was up until 1:30AM work­ing and even then did­n’t feel like going to bed—and I prob­a­bly should have since I then slept abom­inably, which made the sec­ond day merely a good day. The third day I took none and it was an ordi­nary day. This is con­sis­tent with what I expected from the LEF l-thre­onate & TruBrain glycinate/lycinate, and so it is worth inves­ti­gat­ing with a self­-ex­per­i­ment.

Experiment

The basic idea is to rem­edy a defi­ciency (not look for acute stim­u­lant effects) and mag­ne­sium has a slow excre­tion rate1, so week-long blocks seem appro­pri­ate. I can reuse the same method­ol­ogy as the lithium self­-ex­per­i­ment. The response vari­ables will be the usual mood/productivity self­-rat­ing and, since I was orig­i­nally inter­ested in mag­ne­sium for pos­si­ble sleep qual­ity improve­ments, a stan­dard­ized score of sleep latency + # of awak­en­ings + time spent awake (the same vari­able as my ).

Since each 400mg pill takes up 2 00 pills, that’s 4 gel caps a day to reach 800mg mag­ne­sium cit­rate (ie. 136mg ele­men­tal mag­ne­sium), or 224 gel caps (2x120) for the first batch of Sol­gar mag­ne­sium pills. Turn­ing the Sol­gar tablets into gel cap­sules was diffi­cult enough that I switched to NOW Food’s 227g mag­ne­sium cit­rate pow­der for the sec­ond batch.

Power

Reusing the mag­ne­sium cor­re­la­tion from the first Noopept self­-ex­per­i­ment and using the t-test as an approx­i­ma­tion

pwr.t.test(d = (0.27 / sd(npt$MP)), power = 0.8, type="paired", alternative="greater")
# Paired t test power calculation
#
# n = 50.61
# ...

50 pairs of active/placebos or 100 days. With 120 tablets and 4 tablets used up, that leaves me 58 dos­es. That might seem ade­quate except the paired t-test approx­i­ma­tion is over­ly-op­ti­mistic, and I also expect the non-ran­dom­ized non-blinded cor­re­la­tion is too high which means that is over­ly-op­ti­mistic as well. The power would be lower than I’d pre­fer. I decided to sim­ply order another bot­tle of Sol­gar’s & dou­ble the sam­ple size to be safe.

Is 200 enough? There are no canned power func­tions for the ordi­nal logis­tic regres­sion I would be using, so the stan­dard advice is to esti­mate power by sim­u­la­tion: gen­er­at­ing thou­sands of new datasets where we know by con­struc­tion that the binary mag­ne­sium vari­able increases MP by 0.27 (such as by boot­strap­ping the orig­i­nal Noopept exper­i­men­t’s data), and see­ing how often in this col­lec­tion the cut­off of sta­tis­ti­cal-sig­nifi­cance is passed when the usual analy­sis is done (back­ground: Cross­Val­i­dated or “Power Analy­sis and Sam­ple Size Esti­ma­tion using Boot­strap”). In this case, we leave alpha at 0.05, reuse the Noopept exper­i­men­t’s data with its Magtein cor­re­la­tion, and ask for the power when n = 200

library(boot)
library(rms)
npt <- read.csv("https://www.gwern.net/docs/nootropics/2013-gwern-noopept.csv")
n <- 200
magteinPower <- function(dt, indices) {
    d <- dt[sample(nrow(dt), n, replace=TRUE), ] # new dataset, possibly larger than the original
    lmodel <- lrm(MP ~ Noopept + Magtein, data = d)
    return(anova(lmodel)[8])
}
bs <- boot(data=npt, statistic=magteinPower, R=100000, parallel="multicore", ncpus=4)
alpha <- 0.05
print(sum(bs$t<=alpha)/length(bs$t))
# [1] 0.7132

So the power will be ~71%.

Data

  1. 27 August–2 Sep­tem­ber: 0

    3 Sep­tem­ber–9 Sep­tem­ber: 1

  2. 10 Sep­tem­ber–15 Sep­tem­ber: 0

    16 Sep­tem­ber–21 Sep­tem­ber: 1

  3. 22 Sep­tem­ber–28 Sep­tem­ber: 0

    29 Sep­tem­ber–5 Octo­ber: 1

  4. 6 Octo­ber–12 Octo­ber: 0

    13 Octo­ber–19 Octo­ber: 1

  5. 21 Octo­ber–27 Octo­ber: 1

    28 Octo­ber–2 Novem­ber: 0

  6. 5 Novem­ber–11 Novem­ber: 1 (skipped 3/4 Novem­ber)

    Dur­ing 11 Novem­ber, I acci­den­tally unblinded myself while clean­ing my room. Hence, I refilled the active jar and began a fresh pair of blocks.

  7. 12–17 Novem­ber: 0

    18–24 Novem­ber: 1

  8. 25–29 Novem­ber: 0; on 30 Novem­ber, I again unblinded myself and started over lat­er.

  9. 2–8 Decem­ber: 1

    9–15 Decem­ber: 0

  10. 16–17 Decem­ber: 0

    18–19 Decem­ber: 1

    At this point, I dis­cov­ered I had run out of mag­ne­sium pills and had for­got­ten to order the mag­ne­sium cit­rate pow­der I’d intended to. I still had a lot of Noopept pills for the con­cur­rently run­ning sec­ond Noopept self­-ex­per­i­ment, but since I wanted to wrap up some other exper­i­ments with a big analy­sis at the end of the year, I decided to halt and resume in Jan­u­ary 2014.

  11. 25–2014-01-31: 0

    1 Feb­ru­ary–7 Feb­ru­ary: 1

    For this batch, I tried out NOW Foods Mag­ne­sium Cit­rate Pow­der” ($7 for 227g); the pow­der was still a bit sticky but much eas­ier to work with than the Sol­gar pills, and the 227g made 249 gel cap­sule pills. The pack­age esti­mates 119 serv­ing of 315mg ele­men­tal mag­ne­sium, so a ratio of 0.315g mag­ne­sium for 1.9g mag­ne­sium cit­rate, imply­ing that each gel cap pill then con­tains 0.152g mag­ne­sium () and since I want a total dose of 0.8g, I need 5 of the gel cap pills a day or 35 per block.

  12. 9–15 Feb­ru­ary: 1 (skipped 8 Feb­ru­ary)

    16–22 Feb­ru­ary: 0

  13. 23–1 March: 1

    2–8 March: 0

  14. 9–15 March: 1

    16–22 March: 0

  15. 23–29 March: 0

    30 March–5 April: 1

  16. 6–12 April: 0

    13–19 April: 1

  17. 20–26 April: 0

    27 April–3 May: 1

Sub­jec­tive­ly, I have no par­tic­u­lar com­ments, other than that (like the thre­onate), I noticed no diar­rhea.

Analysis

Some prep:

magnesium <- read.csv("magnesium.csv")
mp <- read.csv("~/selfexperiment/mp.csv")
mp$MP <- as.integer(as.character(mp$MP))
rm(magnesium$MP)
magnesium <- merge(mp, magnesium, all=TRUE)
write.csv(magnesium, file="magnesium.csv", row.names=FALSE)

The basic ques­tion: did the mag­ne­sium cit­rate increase MP?

magnesium <- read.csv("https://www.gwern.net/docs/nootropics/2013-2014-magnesium.csv")
summary(lm(MP ~ Magnesium.citrate, data=magnesium))
# Coefficients:
#                    Estimate Std. Error t value Pr(>|t|)
# (Intercept)        3.276515   0.056677   57.81   <2e-16
# Magnesium.citrate -0.000543   0.000144   -3.79    2e-04
#
# Residual standard error: 0.671 on 206 degrees of freedom
#   (678 observations deleted due to missingness)
# Multiple R-squared:  0.065,   Adjusted R-squared:  0.0605
# F-statistic: 14.3 on 1 and 206 DF,  p-value: 0.000201
mean(-0.000543 * c(136, 800))
# [1] -0.2541

The ini­tial results are a shock: the mean effect of the mag­ne­sium cit­rate comes in at almost the exact same mag­ni­tude (-0.25) as had been esti­mated for the Magtein back in the orig­i­nal Noopept analy­sis (0.26), except the esti­mated aver­age effect is neg­a­tive, as in, the mag­ne­sium cit­rate was harm­ful, and sta­tis­ti­cal­ly-sig­nifi­cantly so. Huh?

This was so unex­pected that I won­dered if I had some­how acci­den­tally put the mag­ne­sium pills into the placebo pill bag­gie or had swapped val­ues while typ­ing up the data into a spread­sheet, and checked into that. The spread­sheet accorded with the log above, which rules out data entry mis­takes; and look­ing over the log, I dis­cov­ered that some ear­lier slip-ups were able to rule out the pil­l-swap: I had care­lessly put in some placebo pills made using rice, in order to get rid of them, and that led to me being unblinded twice before I became irri­tated enough to pick them all out of the bag of place­bos—but how could that hap­pen if I had swapped the groups of pills?

So I began look­ing fur­ther into the data to see just what had hap­pened (per­haps bad luck on a few days?), and turned to a plot:

library(ggplot2)
magnesium$Date <- as.Date(magnesium$Date)
with(magnesium[559:nrow(magnesium),],
qplot(Date, MP, color=as.factor(Magnesium.citrate), legend="Magnesium citrate", size=I(7)) +
       scale_colour_manual(values=c("gray49", "red1", "red3"), name = "Magnesium"))
MP cat­e­gor­i­cal data plot­ted by date, col­ored by size of mag­ne­sium dose

One thing I notice look­ing at the data is that the red mag­ne­sium-free days seem to dom­i­nate the upper ranks towards the end, and blues appear mostly at the bot­tom, although this is a lit­tle hard to see because good days in gen­eral start to become sparse towards the end. Now, why would days start to be worse towards the end, and mag­ne­sium-dose days in par­tic­u­lar?

The grim sur­mise is: an accu­mu­lat­ing over­dose—no imme­di­ate acute effect, but the mag­ne­sium builds up, drag­ging down all days, but espe­cially mag­ne­sium-dose days. The gen­er­ally rec­og­nized symp­toms of don’t include effect on mood or cog­ni­tion, aside from “mus­cle weak­ness, con­fu­sion, and decreased reflex­es…poor appetite that does not improve”, but it seems plau­si­ble that below med­ical­ly-rec­og­niz­able lev­els of dis­tress like hyper­mag­ne­semia might still cause men­tal changes, and I would­n’t expect any psy­cho­log­i­cal research to have been done on this top­ic.

A pic­ture is worth a thou­sand words, par­tic­u­larly in this case where there seems to be tem­po­ral effects, differ­ent trends for the con­di­tions, and gen­eral con­fu­sion. So, I drag up 2.5 years of MP data (for con­tex­t), plot all the data, color by magnesium/non-magnesium, and fit differ­ent LOESS lines to each as a sort of smoothed aver­age (since cat­e­gor­i­cal data is hard to inter­pret as a bunch of dot­s), which yields:

magnesium[is.na(magnesium$Magnesium.citrate),]$Magnesium.citrate <- -1
ggplot(data = magnesium, aes(x=Date, y=MP, col=as.factor(magnesium$Magnesium.citrate))) +
 geom_point(size=I(4)) +
 stat_smooth() +
 scale_colour_manual(values=c("gray49", "grey35", "red1", "red3" ),
                     name = "Magnesium")
Full MP dataseries, with smoothed mov­ing aver­ages of no mag­ne­sium, 136mg, & 800mg doses

That really says it all: there’s an ini­tial spike in MP, which reads like the promised stim­u­la­tive effects pos­si­bly due to fix­ing a defi­ciency (a spike which does­n’t seem to have any coun­ter­parts in the pre­vi­ous his­tory of MP), fol­lowed by a dras­tic plunge in the mag­ne­sium days but not so much the con­trol days (indi­cat­ing an acute effect when over­loaded with mag­ne­sium), a par­tial recov­ery dur­ing the non-ex­per­i­men­tal Christ­mas break, another plunge, and finally recov­ery after the exper­i­ment has end­ed.

We can ver­ify the neg­a­tive cor­re­la­tion with the date & an inter­ac­tion between mag­ne­sium and the date; I don’t know whether to treat the mag­ne­sium dose as a lin­ear, cat­e­gor­i­cal, or log­i­cal, so I’ll try all of them:

magnesium <- read.csv("https://www.gwern.net/docs/nootropics/2013-2014-magnesium.csv")
magnesium$Date <- as.integer(magnesium$Date)
slm <- step(lm(MP ~ Magnesium.citrate * as.logical(Magnesium.citrate) *
                    as.factor(Magnesium.citrate) * Date * Noopept, data=magnesium))
# MP ~ as.logical(Magnesium.citrate) + Date + as.logical(Magnesium.citrate):Date
summary(slm)
# Coefficients:
#                                         Estimate Std. Error t value Pr(>|t|)
# (Intercept)                             3.942875   0.571166    6.90  6.3e-11
# as.logical(Magnesium.citrate)TRUE       1.217860   0.806212    1.51    0.132
# Date                                   -0.000992   0.000830   -1.20    0.233
# as.logical(Magnesium.citrate)TRUE:Date -0.002105   0.001173   -1.79    0.074
#
# Residual standard error: 0.664 on 204 degrees of freedom
#   (678 observations deleted due to missingness)
# Multiple R-squared:  0.0933,  Adjusted R-squared:  0.08
# F-statistic:    7 on 3 and 204 DF,  p-value: 0.000167

As feared and con­sis­tent with the accu­mu­lat­ing over­dose hypoth­e­sis, scores decrease over time and they decrease if mag­ne­sium is used that day. (The inter­ac­tion isn’t sta­tis­ti­cal­ly-sig­nifi­cant, but I am not sur­prised: I pow­ered this self­-ex­per­i­ment to detect one main effect, not two main effects and an inter­ac­tion.)

But at least ini­tial­ly, the mag­ne­sium seemed to be remark­ably use­ful. The crossover point, using this lin­ear mod­el, would have been some­where around 20 days of the early small mag­ne­sium dos­es:

## Extract estimated MP for continuous small magnesium dosing, then for no magnesium dosing;
## compare them pair-wise to see which is bigger, and count how many days favor magnesium dosing.
with(magnesium[!is.na(magnesium$Magnesium.citrate),], sum(predict(slm, newdata=data.frame(Date=Date, Magnesium.citrate=136)) >
                                                          predict(slm, newdata=data.frame(Date=Date, Magnesium.citrate=0))))
# [1] 20

The final ques­tion is: since I was tak­ing an over­dose, how did I mess up? I thought I was mak­ing sure I got at least the right RDA of ele­men­tal mag­ne­sium by aim­ing for 800mg of ele­men­tal mag­ne­sium and care­fully con­vert­ing from raw pow­der weight. So I went back to the orig­i­nal ref­er­ences, and scru­ti­niz­ing them close­ly, they really were talk­ing about ele­men­tal mag­ne­sium and indi­cat­ing I should be get­ting 400mg ele­men­tal a day, but I did notice some­thing: I got the dose wrong for the Sol­gar pills, it was­n’t 800mg ele­men­tal, it was 800mg of cit­rate—I mis­read the label. So I went from tak­ing ~130mg of ele­men­tal mag­ne­sium in the first period to ~800mg in the sec­ond; I don’t think it is an acci­dent that the sec­ond period seems to have been much worse (be­tween the plot and the time trend).

I find this very trou­bling. The mag­ne­sium sup­ple­men­ta­tion was harm­ful enough to do a lot of cumu­la­tive dam­age over the months involved (I could have done a lot of writ­ing Sep­tem­ber 2013–June 2014), but not so bla­tantly harm­ful enough as to be notice­able with­out a ran­dom­ized blind self­-ex­per­i­ment or at least sys­tem­atic data col­lec­tion—nei­ther of which are com­mon among peo­ple who would be sup­ple­ment­ing mag­ne­sium I would much pre­fer it if my mag­ne­sium over­dose had come with vis­i­ble harm (such as wak­ing up in the mid­dle of the night after a night­mare soaked in sweat), since then I’d know quickly and sure­ly, as would any­one else tak­ing mag­ne­sium. But the harm I observed in my data? For all I know, that could be affect­ing every user of mag­ne­sium sup­ple­ments! How would we know oth­er­wise?

Sleep

I reused the mag­ne­sium data with my Zeo data and looked at the effects. The result were ambigu­ous: only a few effects sur­vive mul­ti­ple cor­rec­tion, which were a mix of good and bad ones, and I would guess that some of the bad effects are due to too much mag­ne­sium (although there is no time trend as bla­tan­t).

Conclusion

The inter­pre­ta­tion which seems to best resolve every­thing I know about mag­ne­sium with the data from my exper­i­ment is that mag­ne­sium sup­ple­men­ta­tion does indeed help me a large amount, but I was tak­ing way too much.

Experiment 2

This is not 100% clear from the data and just blindly using a plau­si­ble amount car­ries the risk of the neg­a­tive effects, so I intend to run another large exper­i­ment. I will reuse the “NOW Foods Mag­ne­sium Cit­rate Pow­der”, but this time, I will use longer blocks (to make cumu­la­tive over­dos­ing more evi­dent) and try to avoid any doses >150mg of ele­men­tal mag­ne­sium.

I spent 2.5 hours mak­ing gel cap­sules:

  • 10x24 Bisquick placebo
  • 10x24 mag­ne­sium cit­rate
  • 480 total

The pow­der totals 227g of mag­ne­sium cit­rate, hence there is ~0.945g per mag­ne­sium cit­rate pill. The nutri­tional infor­ma­tion states that it con­tains 119 serv­ings of 0.315g mag­ne­sium ele­men­tal = 37.485g ele­men­tal, as expect­ed, and so like­wise there is 0.156g ele­men­tal mag­ne­sium per pill. This is the same dosage as the sec­ond half of the first mag­ne­sium cit­rate exper­i­ment (249 gel cap­sules there, 240 here), where the over­dose effect seemed to also hap­pen; so to avoid the over­dosage, I will take one pill every other day to halve the dose to an aver­age of ~0.078g/78mg ele­men­tal per day (pig­gy­back­ing on the morn­ing-caffeine exper­i­ment to make com­pli­ance eas­ier).

At 1 pill every other day, 14 dos­es, so pairs of 28-day blocks. The total time to use up all pills will then be ~960 days; this is a long time and exces­sive­ly-pow­ered, so I may stop early or pos­si­bly do a .

The ben­e­fit of sequen­tial analy­sis here is being able to stop ear­ly, con­serv­ing pills, and let­ting me test another dosage: if I see another pat­tern of ini­tial ben­e­fits fol­lowed by decline, I can then try cut­ting the dose by tak­ing one pill every 3 days; or, if there is a ben­e­fit and no decline, then I can try tweak­ing the dose up a bit (maybe 3 days out of 5?). Since I don’t have a good idea what dose I want and the opti­mal dose seems like it could be valu­able (and the wrong dose harm­ful!), I can’t afford to spend a lot of time on a sin­gle defin­i­tive exper­i­ment.

Power

Since I did­n’t take any 78mg ele­men­tal doses and the effects were time-vary­ing, it’s more diffi­cult to esti­mate the expected effec­t-size and hence pow­er.

If I assume that the coeffi­cient of +1.22 for as.logical(Magnesium.citrate)TRUE’s effect on MP in the pre­vi­ous analy­sis rep­re­sents the true causal effect of 0.156g ele­men­tal mag­ne­sium with­out any over­dose involved and that mag­ne­sium would have a lin­ear increase (up until over­dose), then one might argue that opti­misti­cally 0.078 would cause an increase of ~0.61. Or one could eye­ball the graph and note that the LOESS lines look like at the mag­ne­sium peak improved by <+0.5 over the long-run base­line of ~3 Then one could do a power esti­mate with those 2 esti­mates.

## _d_:
0.61 / sd(magnesium$MP, na.rm=TRUE)
# [1] 0.83795623
power.t.test(n = 480, delta = 0.83)
#  Two-sample t test power calculation
#
#            n = 480
#        delta = 0.83
#           sd = 1
#    sig.level = 011.05
#        power = 1
power.t.test(delta = 0.83, power = 0.9)
# Two-sample t test power calculation
#
#          n = 31.4970227
#      delta = 0.83
#         sd = 1
#  sig.level = 0.05
#      power = 0.9
0.5 / sd(magnesium$MP, na.rm=TRUE)
# [1] 0.686849369
power.t.test(delta = 0.68, power = 0.8)
# Two-sample t test power calculation
#
#          n = 34.9352817
power.t.test(delta = 0.5, power = 0.8)
# Two-sample t test power calculation
#
#          n = 63.7657637

Power con­sid­er­a­tions sug­gest I could prob­a­bly ter­mi­nate after 4 months

Data

  1. 29 August–2014-09-27: 0

    28 Sep­tem­ber–2 Novem­ber: 1

  2. 3 Novem­ber–4 Decem­ber: 0

    5 Decem­ber–2015-01-11: 1

  3. 12 Jan­u­ary–18 Feb­ru­ary: 0

    19 Feb­ru­ary–5 March: 1 (ended block early so I could have com­plete data for the LLLT exper­i­men­t’s analy­sis)

  4. 6 March–4 April: 1

    5 April–10 May: 0

  5. 11 May–12 June: 0

    13 June–15 July: 1

  6. 16 July–6 Sep­tem­ber : 1

    Thought I was done with both blocks so I unblinded myself, only to dis­cover I was­n’t. Oops.

  7. 7 Sep­tem­ber–7 Novem­ber: 1 (skipped over half a month due to long trip)

    8 Novem­ber–2016-01-08: 0

  8. 4 March–28 April: 0

    29 April:–25 May: 1

  9. 1 June–28 June: 1

    29 June–26 July: 0

  10. 27 July–24 August: 1

    25 August–21 Sep­tem­ber: 0

  11. 22 Sep­tem­ber–16 Octo­ber: 1

    17 Octo­ber–10 Novem­ber: 0

Analysis

Conclusion

78mg, every other day

Prep

mp <- na.omit(read.csv("~/selfexperiment/mp.csv", colClasses=c("Date", "integer")))
magnesium2 <- read.csv("~/2016-10-10-magnesium-second.csv", header=TRUE, colClasses=c("Date", "integer", "integer"))

magnesium <- merge(magnesium2, mp)

write.csv(magnesium, file="~/wiki/docs/nootropics/2016-10-10-magnesium-second.csv", row.names=FALSE)

Descriptive


magnesium <- read.csv("~/wiki/docs/nootropics/2016-10-10-magnesium-second.csv",
               colClasses=c("Date", "integer", "integer", "integer", "numeric", "numeric", "numeric"))
library(skimr)
skim(magnesium)
# Skim summary statistics
#  n obs: 767
#  n variables: 7
#
# Variable type: Date
#  variable missing complete   n        min        max     median n_unique
#      Date       0      767 767 2014-08-29 2016-11-10 2015-09-16      767
#
# Variable type: integer
#      variable missing complete   n  mean    sd p0 p25 p50 p75 p100     hist
#          Dose       0      767 767 18.41 33.14  0   0   0   0   78 ▇▁▁▁▁▁▁▂
#  Experimental      56      711 767  0.5   0.5   0   0   1   1    1 ▇▁▁▁▁▁▁▇
#            MP       0      767 767  3.2   0.64  1   3   3   4    5 ▁▂▁▇▁▅▁▁
#
# Variable type: numeric
#              variable missing complete   n  mean    sd p0     p25   p50  p75 p100     hist
#       Dose.cumulative       0      767 767 1.21  0.56   0 0.85    1.21  1.56 2.42 ▂▃▅▇▇▆▂▃
#  Dose.cumulative.fast       0      767 767 0.059 0.061  0 5.8e-07 0.033 0.1  0.15 ▇▁▁▁▁▃▁▃
#  Dose.cumulative.slow       0      767 767 1.15  0.54   0 0.81    1.16  1.47 2.27 ▂▃▅▇▇▆▂▃

library(ggplot2)

magnesiumTmp[is.na(magnesiumTmp$Experimental),]$Experimental <- 0

with(magnesiumTmp, qplot(Date, MP, color=as.logical(Experimental), legend="Magnesium citrate") +
    scale_colour_manual(values=c("gray49", "red1"), name = "Magnesium") + stat_smooth())
2016 mag­ne­sium self­-ex­per­i­ment, MP vs mag­ne­sium sta­tus (LOESS smooth­ing)

Testing

wilcox.test(MP ~ Experimental, data=magnesium)
#
#   Wilcoxon rank sum test with continuity correction
#
# data:  MP by Experimental
# W = 66897, p-value = 0.125959
# alternative hypothesis: true location shift is not equal to 0
summary(lm(MP ~ Date + Experimental, data=magnesium))
# ...Residuals:
#       Min        1Q    Median        3Q       Max
# -2.172324 -0.269037 -0.164076  0.714138  1.855738
#
# Coefficients:
#                  Estimate   Std. Error  t value   Pr(>|t|)
# (Intercept)   8.33930e+00  1.61701e+00  5.15722 3.2567e-07
# Date         -3.05501e-04  9.67501e-05 -3.15763  0.0016581
# Experimental -7.48915e-02  4.71081e-02 -1.58978  0.1123307
#
# Residual standard error: 0.627593 on 708 degrees of freedom
#   (56 observations deleted due to missingness)
# Multiple R-squared:  0.0168461,   Adjusted R-squared:  0.0140689
# F-statistic: 6.06572 on 2 and 708 DF,  p-value: 0.00244347

magnesium$Date.int <- as.integer(magnesium$Date)
library(brms)
## reasonably informative prior:
magnesium$Magnesium.citrate <- 0
b <- brm(MP ~ Date.int + I(Dose + Magnesium.citrate), prior=c(prior(normal(0,0.1/78), "b")),
          autocor=cor_arma(~1, p=0, q=1),
          iter=10000, chains=30, cores=30, data=magnesium); summary(b); fixef(b)
# Correlation Structures:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# ma[1]     0.15      0.04     0.07     0.22      84215 1.00
#
# Population-Level Effects:
#                         Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept                   8.19      1.83     4.58    11.76     150000 1.00
# Date.int                   -0.00      0.00    -0.00    -0.00     150000 1.00
# IDosePMagnesium.citrate    -0.00      0.00    -0.00     0.00     150000 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.63      0.02     0.60     0.66      83059 1.00
#                                Estimate      Est.Error            Q2.5           Q97.5
# Intercept                8.187500103687 1.825404749366  4.581534432199  1.17586125e+01
# Date.int                -0.000297324482 0.000109197301 -0.000511038825 -8.14888755e-05
# IDosePMagnesium.citrate -0.000928834462 0.000571607891 -0.002050468458  1.87187142e-04
mean(fixef(b, summary=FALSE)[,3] < 0)
# [1] 0.94834

The stan­dard binary test with a lin­ear date trend indi­cates high prob­a­bil­ity of harm as before, and the esti­mated per-mg effect size of the halved (78mg) dose is sim­i­lar to the orig­i­nal mag­ne­sium cit­rate per-mg effect size: the orig­i­nal esti­mate was -0.0005/mg; and the new is -0.0009/mg; so, sim­i­lar, and actu­ally higher (but well within the two esti­mates’ com­bined sam­pling error).

Unsur­pris­ing­ly, com­bin­ing the two exper­i­ments into a sin­gle analy­sis yields an inter­me­di­ate effect size of -0.0006/mg (95% cred­i­ble inter­val, -0.0008 to -0.0003) with P = 1 that it’s neg­a­tive:

magnesium1 <- read.csv("https://www.gwern.net/docs/nootropics/2013-2014-magnesium.csv", colClasses=c("Date", rep("numeric", 4)))
magnesiumAll <- merge(magnesium, magnesium1, all=TRUE)
magnesiumAll$Date.int <- as.integer(magnesiumAll$Date)

magnesiumAllClean <- subset(magnesiumAll, select=c(Date, Date.int, MP, Experimental, Magnesium.citrate, Dose))
magnesiumAllClean <- magnesiumAllClean[!is.na(magnesiumAllClean$Dose) | !is.na(magnesiumAllClean$Magnesium.citrate),]
magnesiumAllClean[is.na(magnesiumAllClean)] <- 0

ba <- brm(MP ~ Date.int + I(Dose + Magnesium.citrate), prior=c(prior(normal(0,0.1/78), "b")),
          autocor=cor_arma(~1, p=0, q=1),
          iter=10000, chains=30, cores=30, data=magnesiumAllClean); summary(ba)
# Correlation Structures:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# ma[1]     0.14      0.03     0.08     0.20      84642 1.00
#
# Population-Level Effects:
#                         Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept                   6.53      1.21     4.16     8.89     150000 1.00
# Date.int                   -0.00      0.00    -0.00    -0.00     150000 1.00
# IDosePMagnesium.citrate    -0.00      0.00    -0.00    -0.00     150000 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.64      0.01     0.61     0.67      88110 1.00
#
# Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample
# is a crude measure of effective sample size, and Rhat is the potential
# scale reduction factor on split chains (at convergence, Rhat = 1).
#                                Estimate      Est.Error           Q2.5           Q97.5
# Intercept                6.528906256390 1.20706045e+00  4.15836502039  8.89383946e+00
# Date.int                -0.000199023324 7.26410825e-05 -0.00034141518 -5.62550961e-05
# IDosePMagnesium.citrate -0.000616714063 1.36473721e-04 -0.00088489562 -3.49705762e-04
mean(fixef(ba, summary=FALSE)[,3] < 0)
# [1] 0.999986667
## so -0.0006 (-0.0008 - -0.0003) / mg, P=1

So the orig­i­nal result is not anom­alous and is con­firmed by the fol­lowup.

This is a dis­ap­point­ing find­ing on sev­eral lev­els: from a bio­log­i­cal per­spec­tive, mag­ne­sium is a vital micronu­tri­ent and defi­ciency expected and get­ting a result of harm makes me ques­tion my meth­ods & results; from a prac­ti­cal per­spec­tive, it means that in addi­tion to the con­sid­er­able work required to set up & run the self­-ex­per­i­ments, I inflicted a non­triv­ial level of harm on myself (-0.06 on >1 year’s worth of days); and from a deci­sion per­spec­tive, this result is, ex post, worth­less, as my default deci­sion is to not sup­ple­ment mag­ne­sium and the addi­tional infor­ma­tion does­n’t change my deci­sion and so has a VoI of zero (only some­what ame­lio­rated by the pos­si­bil­ity that the results will be of inter­est or use to read­er­s).

What might explain this harm? After think­ing about the results some more, I have two sug­ges­tions:

  1. Elec­trolyte Imbal­ance: I recall that there is another related sup­ple­ment where my ran­dom­ized blinded self­-ex­per­i­ment found harm despite gen­eral reports of ben­e­fits and defi­cien­cies: .

    Potas­sium is much like magnesium/sodium/calcium in being a metal and heav­ily used by the ner­vous sys­tem and often sup­ple­mented for activ­i­ties like sports. Could sup­ple­ment­ing potas­sium and then mag­ne­sium, sep­a­rate­ly, have been caus­ing ? This would ele­gantly resolve both find­ings of harm and explain why oth­ers find ben­e­fits (per­haps they had higher base­line lev­els of the nec­es­sary co-elec­trolytes, or were sup­ple­ment­ing them simul­ta­ne­ous­ly). has also been sug­gested as a pos­si­ble used up by mag­ne­sium sup­ple­men­ta­tion.

    In that case, the solu­tion is sim­ple: do some read­ing to find out if any opti­mal ratios have been mea­sured yet, or sim­ply take a com­mon-sized dose of both potas­sium & mag­ne­sium (and per­haps sodium too—I am pretty sure I get more than enough cal­cium because I con­sume so much dairy, but I am not sure about sodium since I cook almost all my food & use lit­tle salt by default as I grew up in a low-sodium home & find even a lit­tle salt to be more than enough fla­vor­ing). There might be some­thing use­ful in blood test pan­els too. Fig­ur­ing out the right dose might be tricky, as over­doses can pro­duce issues like .

    Given the estab­lished harm, I would have to run yet a third self­-ex­per­i­ment, one long enough to be able to rule out even a small harm and cer­tify long-term use (which has poten­tially high regret).

  2. Over­dose: as men­tioned in the first exper­i­ment, the fact that the harm seems like it increases over time is sus­pi­cious. This shows up less in the sec­ond one, but that uses a smaller dose and has longer & more breaks, so that might be why.

    If it’s a cumu­la­tive over­dose, since mag­ne­sium has a long half-life, mod­el­ing the hypo­thet­i­cal cumu­la­tive doses each day should offer some insight. If there turns out to be

    No addi­tional exper­i­men­ta­tion is need­ed, since the doses & dose sched­ule is known and there ought to be enough vari­a­tion in sums to analyse. So I can do some exploratory analy­ses of this pos­si­bil­i­ty.

Modeling Cumulative Dose

To model the pos­si­bil­ity of over­dose, I can take the exist­ing data’s sched­ule of doses and use a mag­ne­sium half-life for­mula to cal­cu­late the increase in mag­ne­sium load each day over an assumed base­line of 0mg. Then regress as before, but on the total mag­ne­sium load, both lin­ear and qua­dratic (for the dose-re­sponse curve).

So what’s the actual half-life of a mag­ne­sium sup­ple­ment, besides “long”?

“Mag­ne­sium Basics” cites on the topic just the paper Avi­oli & Berman 1966, “Mg28 kinet­ics in man”. They trace mag­ne­sium in humans and fit to the data a rather com­plex mul­ti­-com­part­ment model with sev­eral small (15% of total mag­ne­sium) fast-ex­chang­ing reser­voirs of mag­ne­sium and a few large slow-ex­chang­ing reser­voirs (the other 85%), all of which turnover and con­nect with each other at differ­ent rates. This would be unman­age­able but they do sug­gest a sim­pli­fied two-com­part­ment mod­el:

Most often the data have been treated with the assump­tion that each expo­nen­tial func­tion rep­re­sented a dis­crete mag­ne­sium com­part­ment with inde­pen­dent rates of turnover. On the basis of such analy­ses applied to uri­nary Mg28 spe­cific activ­ity curves, Sil­ver et al. (21) defined three exchang­ing mag­ne­sium com­part­ments in man with half-times of 35 hr, 3 hr, and 1 hr, respec­tive­ly…Zu­moff (23) ana­lyz­ing curves in nor­mal sub­jects again described three com­po­nents with half-lives of 15, 40, and 340 min.

In the present model over 85% of the exchange­able mag­ne­sium pool was accounted for by com­part­ment 3. Of total body mag­ne­sium of man, 60% can be accounted for by bone and 20 % by mus­cle (1). The mag­ne­sium con­tent of soft tis­sues in man approx­i­mate 400-420 mEq or 20% of total body mag­ne­sium (1). The rapid exchange­abil­ity of this soft tis­sue mag­ne­sium with injected Mg28 as com­pared to the much slower skele­tal mus­cle and bone mag­ne­sium exchange­abil­ity has been doc­u­mented repeat­edly in ani­mals and man by many inves­ti­ga­tors (4, 10, 11, 15, 17). One could argue, there­fore, that the cal­cu­lated whole-body exchange­able mag­ne­sium con­tent in the present study rep­re­sent­ing 15% of the whole-body mag­ne­sium pri­mar­ily reflects intra-cel­lu­lar mag­ne­sium.

…The present study indi­cates that in man there are at least three exchange­able mag­ne­sium pools with var­ied rates of turnover reflected in a 6-day study. Com­part­ments I and 2, exem­pli­fy­ing pools with a rel­a­tively fast turnover, together approx­i­mate extra­cel­lu­lar fluid in dis­tri­b­u­tion; com­part­ment 3, an intra­cel­lu­lar pool con­tain­ing over 80% of the exchang­ing mag­ne­sium, with a turnover one-half that of the most rapid pool; and com­part­ment 5, which prob­a­bly accounts for most of whole-body mag­ne­sium. Since only 15% of whole-body mag­ne­sium is accounted for by rel­a­tively rapid exchange process­es, approx­i­mately 25.5 mEq/kg of body mag­ne­sium (0.85 X 30 mEq/kg) is either nonex­change­able or exchanges very slow­ly.

Assum­ing 1. a steady state wherein Rho35 = Rho53 (Rho35 = 0.0156 mEq/kg hr, Table I) and 2. that the slowly exchang­ing body mag­ne­sium could be accounted for by a sin­gle com­part­ment (com­part­ment 5, Fig. 3), then (Equa­tion 9):

This rep­re­sents a bio­log­i­cal half-life of about 1,000 hr and would require an iso­topic kinetic study of about 50 days for exper­i­men­tal ver­i­fi­ca­tion. The short phys­i­cal half-life of Mg28 and radi­a­tion haz­ards imposed by mil­li­curie doses of Mg28 presently pro­hibit in vivo exper­i­ments of this nature in man…The sub­jects may not have been in a mag­ne­sium steady state dur­ing the Mg28 study since com­part­ment 5 is so large (85%; whole-body mag­ne­sium) and its esti­mated turnover of 0.0006/hr so small that it had not yet adjusted to the con­stant dietary intake selected arbi­trar­ily for each patient.

If I’m under­stand­ing it right, the sug­gested sim­ple model is a two-com­part­ment one, with a ‘fast’ and a ‘slow’ com­part­ment. The fast one holds 15% of the mag­ne­sium and decays at a frac­tion of 0.0156 per hour, giv­ing a half-life of ~44 hours () or ~1.8 days, while the slow one holds 85% and has a half life of >1000 hours () or ~42 days (!). So to approx­i­mate the net dis­tur­bance each day and any accu­mu­la­tion, we can add the daily dose, and decay the pre­vi­ous daily total by the weighted decay rates. (Av­er­ag­ing like this, assum­ing that of each day’s dose, 15% goes into the fast com­part­ment & 85% into the slow com­part­ment, may not be right. The slow com­part­ment is slow, after all. Should the slow com­part­ment be mod­eled as instead suck­ing in a small per­cent­age each day from the fast com­part­men­t?)

library(purrr)
magnesium$Dose.cumulative.slow <- 0.85*magnesium$Dose %>% accumulate(function(cm, prv) { prv + (1-0.00062)^24*cm} )
magnesium$Dose.cumulative.fast <- 0.15*magnesium$Dose %>% accumulate(function(cm, prv) { prv + (1-0.01560)^24*cm} )
magnesium$Dose.cumulative      <- magnesium$Dose.cumulative.fast + magnesium$Dose.cumulative.slow

round(digits=2, cor(magnesium[,-1], use="pairwise"))
#                      Experimental  Dose    MP Dose.cumulative.slow Dose.cumulative.fast Dose.cumulative
# Experimental                 1.00
# Dose                         0.58  1.00
# MP                          -0.05 -0.06  1.00
# Dose.cumulative.slow         0.33  0.22 -0.01                 1.00
# Dose.cumulative.fast         0.93  0.76 -0.07                 0.42                 1.00
# Dose.cumulative              0.42  0.29 -0.02                 1.00                 0.50            1.00

ggplot(magnesium, aes(Date, y = value, color = variable)) +
    geom_line(aes(y = Dose.cumulative, col="Cumulative")) +
    geom_line(aes(y = Dose.cumulative.slow, col="Slow")) +
    geom_line(aes(y = Dose.cumulative.fast, col="Fast"))  +
    geom_line(aes(y = Experimental, col="Experiment"))
2016 mag­ne­sium self­-ex­per­i­ment, imputed cumu­la­tive mag­ne­sium body load in grams based on two-com­part­ment model & half-lives over the blocks of the exper­i­ment.

The slow totals turns out to reach far larger lev­els than the fast totals, and the cumu­la­tive is dom­i­nated by the slow total, so it makes more sense to avoid lump­ing them togeth­er: they are differ­ent bio­log­i­cally in size and half-life, are differ­ent parts of the body (the fast seems to be cir­cu­lat­ing mag­ne­sium while the slow cor­re­sponds to mus­cle & skele­ton, I think Avi­oli & Berman 1966 sug­gest­s), and if they act differ­ent­ly, using the total would hide that, and if they don’t, they’ll add up to the same thing any­way.

bo <- brm(MP ~ Date.int + Dose.cumulative.slow + I(Dose.cumulative.slow^2) + Dose.cumulative.fast +  I(Dose.cumulative.fast^2), prior=c(prior(normal(0,0.005), "b")), autocor=cor_arma(~1, p=0, q=1), control = list(adapt_delta = 0.95, max_treedepth=15), iter=30000, chains=29, cores=29, data=magnesium); bo;
# Samples: 29 chains, each with iter = 30000; warmup = 15000; thin = 1;
#          total post-warmup samples = 435000
#
# Correlation Structures:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# ma[1]     0.14      0.04     0.07     0.22      39314 1.00
#
# Population-Level Effects:
#                         Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept                   9.01      1.88     5.33    12.70     435000 1.00
# Date.int                   -0.00      0.00    -0.00    -0.00     435000 1.00
# Dose.cumulative.slow        0.00      0.00    -0.00     0.00     435000 1.00
# IDose.cumulative.slowE2    -0.00      0.00    -0.00     0.00     435000 1.00
# Dose.cumulative.fast        0.00      0.00    -0.01     0.01      34194 1.00
# IDose.cumulative.fastE2    -0.00      0.00    -0.00     0.00      47501 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.63      0.02     0.60     0.66      45975 1.00
fixef(bo); waic(b,bo)
#                                Estimate      Est.Error            Q2.5           Q97.5
# Intercept                9.01339178e+00 1.88242899e+00  5.32696382e+00  1.27043508e+01
# Date.int                -3.52343153e-04 1.13874214e-04 -5.75665506e-04 -1.29252046e-04
# Dose.cumulative.slow     2.37189034e-04 1.99625166e-04 -1.53223784e-04  6.29052489e-04
# IDose.cumulative.slowE2 -8.77790825e-08 9.71539135e-08 -2.78303424e-07  1.02399191e-07
# Dose.cumulative.fast     7.26503721e-04 4.54413745e-03 -8.18732787e-03  9.62905267e-03
# IDose.cumulative.fastE2 -3.74918432e-04 2.37853248e-04 -8.40790729e-04  9.08634153e-05
#           WAIC    SE
# b      1467.51 35.35
# bo     1468.41 35.45
# b - bo   -0.90  3.40
marginal_effects(bo, effects=c("Dose.cumulative.slow", "Dose.cumulative.fast"))
Mar­ginal effects (av­er­aged over other vari­ables) of cumu­la­tive doses on MP

No espe­cially strong qua­dratic dose-re­sponse curves emerge, and the model fit is just slightly worse than the sim­ple lin­ear total-dose mod­el. It is inter­est­ing that the two qua­drat­ics hint at a short­-term overload/harm but long-term ben­e­fit.

If we try fit­ting the qua­dratic with the Experimental indi­ca­tor to see whether the effect of mag­ne­sium is cap­tured by the two-dose mod­el, the model is diffi­cult to fit, requir­ing many more sam­ples for con­ver­gence, but ulti­mately does­n’t

boe <- brm(MP ~ Date.int + Experimental + Dose.cumulative.slow + I(Dose.cumulative.slow^2) + Dose.cumulative.fast +
          I(Dose.cumulative.fast^2), prior=c(prior(normal(0,0.1/78)), prior(coef="Experimental", normal(0,0.1))),
          autocor=cor_arma(~1, p=0, q=1), iter=30000, chains=30, cores=30, control = list(adapt_delta = 0.99),
          data=magnesium)
summary(boe); fixef(boe); waic(b, bo, boe)
# Correlation Structures:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# ma[1]     0.12      0.04     0.05     0.20      83841 1.00
#
# Population-Level Effects:
#                         Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept                   8.71      1.83     5.11    12.30    1350000 1.00
# Date.int                   -0.00      0.00    -0.00    -0.00    1350000 1.00
# Experimental                0.02      0.07    -0.11     0.15      76746 1.00
# Dose.cumulative.slow        0.00      0.00    -0.00     0.00     491004 1.00
# IDose.cumulative.slowE2    -0.00      0.00    -0.00     0.00     542324 1.00
# Dose.cumulative.fast       -0.00      0.00    -0.00     0.00     115784 1.00
# IDose.cumulative.fastE2    -0.00      0.00    -0.00     0.00     138896 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.62      0.02     0.59     0.66      84156 1.00
#                                Estimate      Est.Error            Q2.5           Q97.5
# Intercept                8.71472231e+00 1.83496362e+00  5.11197732e+00  1.23036692e+01
# Date.int                -3.34069444e-04 1.11019111e-04 -5.51282372e-04 -1.15937711e-04
# Experimental             2.18818486e-02 6.51106318e-02 -1.05797456e-01  1.49466686e-01
# Dose.cumulative.slow     2.30301248e-04 1.88349858e-04 -1.39512183e-04  5.99674818e-04
# IDose.cumulative.slowE2 -9.66555633e-08 9.28998977e-08 -2.78618364e-07  8.55000738e-08
# Dose.cumulative.fast    -6.75864519e-06 6.65868030e-04 -1.31344906e-03  1.29675370e-03
# IDose.cumulative.fastE2 -3.49600899e-04 1.82533042e-04 -7.07912048e-04  7.38942643e-06
Mar­ginal effects, with Experimental binary inter­ven­tion indi­ca­tor added to the 2-dose model (min­i­mal differ­ence in esti­mated dose-re­sponse curves)

So it appears that the two-com­part­ment model (at least, as I’ve imple­mented it, which may not be right) is not clearly supe­ri­or; it may or may not be right, but the data is weak.

Additional specifications

In des­per­a­tion, I will pro­ceed to tor­ture the data with var­i­ous ways to try to win­kle out a temporal/accumulating effect.

One idea I had was to try differ­ent decay rates (of a sin­gle com­part­ment, which would be per­haps the fast one), rang­ing from 1 day to 64 days, and use the horse­shoe prior for vari­able selec­tion to pick out the decay rate giv­ing the most pre­dic­tive mov­ing-av­er­age. None of them popped out:

estimateDosing <- function(d) { magnesium$Dose %>% accumulate(function(cm, prv) { prv + (1-(0.5/d))*cm} ) }
magnesium$Dose.1d <- estimateDosing(1)
magnesium$Dose.2d <- estimateDosing(2)
magnesium$Dose.4d <- estimateDosing(4)
magnesium$Dose.8d <- estimateDosing(8)
magnesium$Dose.16d <- estimateDosing(16)
magnesium$Dose.32d <- estimateDosing(32)
magnesium$Dose.64d <- estimateDosing(64)

bod <- brm(MP ~ Date.int + Dose + Dose.1d + Dose.2d + Dose.4d + Dose.8d + Dose.16d + Dose.32d + Dose.64d,
    prior=c(set_prior("horseshoe(1, par_ratio=(1/7))")), iter=15000, chains=30, cores=30, data=magnesium)
summary(bod); fixef(bod)
# Population-Level Effects:
#           Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept     6.38      2.24     2.65    10.73      11367 1.00
# Date.int     -0.00      0.00    -0.00     0.00      11203 1.00
# Dose         -0.00      0.00    -0.00     0.00      22772 1.00
# Dose.1d      -0.00      0.00    -0.00     0.00      16871 1.00
# Dose.2d      -0.00      0.00    -0.00     0.00       9947 1.00
# Dose.4d      -0.00      0.00    -0.00     0.00      13362 1.00
# Dose.8d      -0.00      0.00    -0.00     0.00       4789 1.01
# Dose.16d      0.00      0.00    -0.00     0.00       3778 1.01
# Dose.32d      0.00      0.00    -0.00     0.00       3681 1.01
# Dose.64d     -0.00      0.00    -0.00     0.00       4858 1.01
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.63      0.02     0.60     0.67      23631 1.00
# ...
#                  Estimate      Est.Error            Q2.5          Q97.5
# Intercept  6.37662456e+00 2.235888108006  2.649424916291 1.07293860e+01
# Date.int  -1.87427217e-04 0.000135929535 -0.000451826065 4.02780509e-05
# Dose      -9.83247484e-05 0.000398884863 -0.001201592100 5.62706619e-04
# Dose.1d   -1.14355053e-04 0.000490526386 -0.001424678384 6.96386862e-04
# Dose.2d   -1.23935090e-04 0.000432495370 -0.001206503256 5.95745260e-04
# Dose.4d   -1.84854122e-04 0.000372559311 -0.001123141480 3.49011680e-04
# Dose.8d   -1.63414873e-04 0.000337226934 -0.001082742030 2.72433040e-04
# Dose.16d   5.59172067e-05 0.000248260879 -0.000414186231 6.79183708e-04
# Dose.32d   1.55059360e-04 0.000227871520 -0.000104605208 7.47809143e-04
# Dose.64d  -7.71631435e-05 0.000106139588 -0.000342571572 5.31762310e-05

A sim­i­lar method is lag­ging, just shift­ing the dose and esti­mat­ing an atten­u­a­tion, which did­n’t work either:

magnesium$Lag.1 <- c(rep(0,1), magnesium$Dose)[1:nrow(magnesium)]
magnesium$Lag.2 <- c(rep(0,2), magnesium$Dose)[1:nrow(magnesium)]
magnesium$Lag.3 <- c(rep(0,3), magnesium$Dose)[1:nrow(magnesium)]
magnesium$Lag.4 <- c(rep(0,4), magnesium$Dose)[1:nrow(magnesium)]
magnesium$Lag.5 <- c(rep(0,5), magnesium$Dose)[1:nrow(magnesium)]
magnesium$Lag.6 <- c(rep(0,6), magnesium$Dose)[1:nrow(magnesium)]
magnesium$Lag.7 <- c(rep(0,7), magnesium$Dose)[1:nrow(magnesium)]
bol <- brm(MP ~ Date.int + Dose + Lag.1 + Lag.2 + Lag.3 + Lag.4 + Lag.5 + Lag.6 + Lag.7,
    prior=c(prior(normal(0,0.01))), iter=5000, chains=30, cores=30, data=magnesium)
summary(bol); fixef(bol)
# Population-Level Effects:
#           Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept     8.34      1.62     5.16    11.52      75000 1.00
# Date.int     -0.00      0.00    -0.00    -0.00      75000 1.00
# Dose          0.00      0.00    -0.00     0.00      75000 1.00
# Lag.1         0.00      0.00    -0.00     0.00      75000 1.00
# Lag.2        -0.00      0.00    -0.01     0.00      60789 1.00
# Lag.3        -0.00      0.00    -0.01     0.00      62034 1.00
# Lag.4        -0.00      0.00    -0.01     0.00      62263 1.00
# Lag.5         0.00      0.00    -0.00     0.01      60792 1.00
# Lag.6         0.00      0.00    -0.00     0.00      75000 1.00
# Lag.7        -0.00      0.00    -0.00     0.00      75000 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.64      0.02     0.60     0.67      68165 1.00
#
# Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample
# is a crude measure of effective sample size, and Rhat is the potential
# scale reduction factor on split chains (at convergence, Rhat = 1).
#                  Estimate      Est.Error            Q2.5          Q97.5
# Intercept  8.343749825167 1.62108462e+00  5.164844564711 11.52433155127
# Date.int  -0.000305389794 9.69037305e-05 -0.000495385229 -0.00011560533
# Dose       0.001125326534 1.89417227e-03 -0.002587631351  0.00483233217
# Lag.1      0.000259731777 1.88856710e-03 -0.003464743028  0.00398431704
# Lag.2     -0.002630603643 2.58733392e-03 -0.007694762066  0.00246824541
# Lag.3     -0.003248745460 2.58131724e-03 -0.008338464544  0.00179576211
# Lag.4     -0.000669146992 2.56489651e-03 -0.005715930399  0.00435186920
# Lag.5      0.002623359249 2.59021313e-03 -0.002451459184  0.00773690535
# Lag.6      0.000608268232 1.89271318e-03 -0.003081445775  0.00433930503
# Lag.7     -0.000160728821 1.89947146e-03 -0.003881042703  0.00358413020

brms does sup­port for­mal ARIMA time-series mod­els, so I con­sid­ered sim­i­lar ones which add ARIMA (to the response vari­able, MP) with lags up to 7 days and a mov­ing-av­er­age, a 1-day lag+­mov­ing-av­er­age, and just a mov­ing-av­er­age. (brms does not, as far as I can tell, sup­port infer­ence on the ARIMA para­me­ters them­selves other than in the generic sense of allow­ing you to fit mul­ti­ple dis­crete mod­els and then com­par­ing with waic/loo etc.)

barma71 <- brm(MP ~ Dose, autocor=cor_arma(~1, p=7, q=1), iter=5000, chains=30, cores=30, data=magnesium); summary(barma71); fixef(barma71)
# Correlation Structures:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# ar[1]     0.13      0.52    -0.79     0.94      13907 1.00
# ar[2]    -0.04      0.09    -0.20     0.12      15956 1.00
# ar[3]     0.02      0.05    -0.08     0.11      30385 1.00
# ar[4]    -0.03      0.04    -0.11     0.05      44092 1.00
# ar[5]     0.03      0.04    -0.05     0.12      35208 1.00
# ar[6]     0.00      0.05    -0.09     0.09      32015 1.00
# ar[7]     0.02      0.04    -0.05     0.10      50915 1.00
# ma[1]     0.01      0.52    -0.79     0.93      13888 1.00
#
# Population-Level Effects:
#           Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept     8.22      1.93     4.42    12.01      74914 1.00
# Date.int     -0.00      0.00    -0.00    -0.00      74892 1.00
# Dose         -0.00      0.00    -0.00     0.00      75000 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.63      0.02     0.60     0.66      60937 1.00
#
# Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample
# is a crude measure of effective sample size, and Rhat is the potential
# scale reduction factor on split chains (at convergence, Rhat = 1).
# Warning message:
# There were 17 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help.
# See http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
#                  Estimate      Est.Error            Q2.5           Q97.5
# Intercept  8.222000498575 1.932432753905  4.416327738099  1.20085926e+01
# Date.int  -0.000299167802 0.000115613136 -0.000525771625 -7.13583711e-05
# Dose      -0.001149187774 0.000597896272 -0.002324613368  2.89226774e-05

barma11 <- brm(MP ~ Dose, autocor=cor_arma(~1, p=1, q=1), iter=5000, chains=30, cores=30, data=magnesium); summary(bama11); fixef(bama11)
# Correlation Structures:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# ar[1]    -0.10      0.27    -0.62     0.44      28289 1.00
# ma[1]     0.25      0.27    -0.31     0.72      28510 1.00
#
# Population-Level Effects:
#           Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept     3.22      0.03     3.17     3.28      47473 1.00
# Dose         -0.00      0.00    -0.00     0.00      75000 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.63      0.02     0.60     0.66      43505 1.00

bma <- brm(MP ~ Date.int + Dose, autocor=cor_arma(~1, p=0, q=1), iter=10000, chains=30, cores=30, data=magnesium); summary(bma); fixef(bma)
# Correlation Structures:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# ma[1]     0.15      0.04     0.07     0.22      85325 1.00
#
# Population-Level Effects:
#           Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# Intercept     8.25      1.84     4.65    11.83     150000 1.00
# Date.int     -0.00      0.00    -0.00    -0.00     150000 1.00
# Dose         -0.00      0.00    -0.00     0.00     150000 1.00
#
# Family Specific Parameters:
#       Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
# sigma     0.63      0.02     0.60     0.66      85214 1.00
#
# Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample
# is a crude measure of effective sample size, and Rhat is the potential
# scale reduction factor on split chains (at convergence, Rhat = 1).
#                  Estimate      Est.Error            Q2.5           Q97.5
# Intercept  8.246820322945 1.836822995887  4.649351298371  1.18301614e+01
# Date.int  -0.000300629617 0.000109882242 -0.000515036715 -8.53722332e-05
# Dose      -0.001156989930 0.000636009833 -0.002405544347  8.80188844e-05

While I was at it, I threw some deci­sion-tree meth­ods, ran­dom forests & XGBoost, at it. Nei­ther one per­forms much above chance, and both over­fit:

library(randomForest)
r <- randomForest(MP ~ Date.int + Dose + Dose.1d + Dose.2d + Dose.4d + Dose.8d + Dose.16d + Dose.32d +
    Dose.64d + Lag.1 + Lag.2 + Lag.3 + Lag.4 + Lag.5 + Lag.6 + Lag.7, data=magnesium, importance=TRUE); r
#                Type of random forest: regression
#                      Number of trees: 500
# No. of variables tried at each split: 5
#
#           Mean of squared residuals: 0.45309365
#                     % Var explained: -11.5

library(xgboost)
xdf <- as.matrix(subset(magnesium, select=c("Date.int", "Dose", "Dose.1d", "Dose.2d",
    "Dose.4d", "Dose.8d", "Dose.16d", "Dose.32d", "Dose.64d", "Lag.1", "Lag.2", "Lag.3",
    "Lag.4", "Lag.5", "Lag.6", "Lag.7")))
xdt <- xgb.DMatrix(data=xdf, label=magnesium$MP)
xc <- xgb.cv(data=xdt, nrounds=20, nfold=5); xc
# ##### xgb.cv 5-folds
#  iter train_rmse_mean train_rmse_std test_rmse_mean test_rmse_std
#     1       1.9971932  0.00887113498      1.9965942 0.05663487645
#     2       1.4694444  0.00571063963      1.4738914 0.05622243389
#     3       1.1169894  0.00287774687      1.1322150 0.05330744639
#     4       0.8827894  0.00270631089      0.9221848 0.04989199156
#     5       0.7319208  0.00266308260      0.7998346 0.03957045891
#     6       0.6377054  0.00365968636      0.7273444 0.03119305256
#     7       0.5729780  0.00505585174      0.6925404 0.02332950090
#     8       0.5344652  0.00388501024      0.6750268 0.01660751560
#     9       0.5110230  0.00628505720      0.6688250 0.01083822294
#    10       0.4895788  0.00609432403      0.6633326 0.00994656782
#    11       0.4764658  0.00665422484      0.6616298 0.00788831770
#    12       0.4673910  0.00639055653      0.6622510 0.00830873304
#    13       0.4553722  0.00896999151      0.6623134 0.00798312374
#    14       0.4453348  0.01095618562      0.6634832 0.00916942418
#    15       0.4346564  0.01193689604      0.6643090 0.01121566110
#    16       0.4234282  0.01007038727      0.6668124 0.01150062806
#    17       0.4130764  0.01161052529      0.6686780 0.01166914274
#    18       0.4054248  0.01099076020      0.6720958 0.01327700370
#    19       0.3971520  0.01330724769      0.6726724 0.01219097106
#    20       0.3901480  0.01375990240      0.6741852 0.01182116611

  1. “The kid­neys are cru­cial in mag­ne­sium home­osta­sis [18, 49–51] as serum mag­ne­sium con­cen­tra­tion is pri­mar­ily con­trolled by its excre­tion in urine [7]. Mag­ne­sium excre­tion fol­lows a cir­ca­dian rhythm, with max­i­mal excre­tion occur­ring at night [15].” –↩︎