Germán Rodríguez
Demographic Methods Princeton University

Life Table Analysis of Contraceptive Use

We will illustrate the application of increment-decrement life tables to the analysis of contraceptive effectiveness using a classic dataset from Tietze (1967), Intra-Uterine Contraception: Recommended Procedures for Data Analysis. Studies in Family Planning Vol 1, No 18, Supplement, pp 1-6.

Women will enter the life table with the insertion of an IUD, which defines a segment of use. The segment ends with an event or “termination” or “continues” as of the analysis date. Some events (pregnancy) close the case and are called “closures”, but others (first expulsion) terminate the segment but not necessarily the case, as the device may be “reinserted”, in which case the woman re-enters the table with a new segment of use.

The data come in two tables, one showing first insertions per calendar month, and another giving details of terminations and reinsertions. I did some preliminary work to put the data in a more usable form. The manipulations are simple but tedious. The end result is a file tabulating insertions, reinsertions, terminations, closures and continuations by ordinal month. The file is called tietze.dta and is available in the datasets section in Stata format.

The variables include the ordinal month, counts of insertions and reinsertions (ins and reins), terminations by accidental pregnancy (ap), first and later expulsion (fe,le), removal for medical or personal reasons or by investigator’s choice (rm, rp, ric), and lost to follow up (lfu), as well as counts of closures by the same reasons (with names that add a c prefix, so cfe are closures due to first expulsions.

We start by reading the file and listing some of the counts.

. use https://grodri.github.io/datasets/tietze, clear

. list month ins reins terms cont in 1/12, clean

       month   ins   reins   terms   cont  
  1.       1   250       7      25     18  
  2.       2     .       8       9     14  
  3.       3     .       1       7     17  
  4.       4     .       1       7     16  
  5.       5     .       2       4     13  
  6.       6     .       9      11     10  
  7.       7     .       5       7     17  
  8.       8     .       2       3      9  
  9.       9     .       0       3     17  
 10.      10     .       1       2     12  
 11.      11     .       0       0     15  
 12.      12     .       7       7     14  

. 
> library(haven)
> library(dplyr)
> tietze <- read_dta("https://grodri.github.io/datasets/tietze.dta")
> select(tietze, month, ins, reins, terms, cont) |> slice(1:12)
# A tibble: 12 × 5
   month   ins reins terms  cont
   <dbl> <dbl> <dbl> <dbl> <dbl>
 1     1   250     7    25    18
 2     2    NA     8     9    14
 3     3    NA     1     7    17
 4     4    NA     1     7    16
 5     5    NA     2     4    13
 6     6    NA     9    11    10
 7     7    NA     5     7    17
 8     8    NA     2     3     9
 9     9    NA     0     3    17
10    10    NA     1     2    12
11    11    NA     0     0    15
12    12    NA     7     7    14

We have a total of 250 first insertions. In the first month there are 7 reinsertions, 25 terminations of various kinds, and 18 continuing segments.

Woman-Months of Use

The first task is to compute woman-months of exposure in each month. We will follow Tietze in assuming that events are uniformly distributed within each month of use. In the first month we have 250 segments at the start and 250 + 7 - 25 - 18 = 214 at the end, and exposure is simply the average, 232 woman-months.

. gen exit = ins[1] + sum(reins - terms - cont)

. gen enter = ins[1]

. replace enter = exit[_n - 1] in 2/L
(14 real changes made)

. gen expo = (enter + exit)/2

. list month enter reins terms cont exit expo in 1/12, clean

       month   enter   reins   terms   cont   exit    expo  
  1.       1     250       7      25     18    214     232  
  2.       2     214       8       9     14    199   206.5  
  3.       3     199       1       7     17    176   187.5  
  4.       4     176       1       7     16    154     165  
  5.       5     154       2       4     13    139   146.5  
  6.       6     139       9      11     10    127     133  
  7.       7     127       5       7     17    108   117.5  
  8.       8     108       2       3      9     98     103  
  9.       9      98       0       3     17     78      88  
 10.      10      78       1       2     12     65    71.5  
 11.      11      65       0       0     15     50    57.5  
 12.      12      50       7       7     14     36      43  
> last <- nrow(tietze)
> tietze <- mutate(tietze, exit = ins[1] + cumsum(reins - terms - cont),
+   enter = c(ins[1], exit[-last]),
+   expo = (enter + exit)/2)
> select(tietze, month, enter, reins, terms, cont, exit, expo) |> slice(1:12)
# A tibble: 12 × 7
   month enter reins terms  cont  exit  expo
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1     1   250     7    25    18   214 232  
 2     2   214     8     9    14   199 206. 
 3     3   199     1     7    17   176 188. 
 4     4   176     1     7    16   154 165  
 5     5   154     2     4    13   139 146. 
 6     6   139     9    11    10   127 133  
 7     7   127     5     7    17   108 118. 
 8     8   108     2     3     9    98 103  
 9     9    98     0     3    17    78  88  
10    10    78     1     2    12    65  71.5
11    11    65     0     0    15    50  57.5
12    12    50     7     7    14    36  43  

Continuation “Rates”

We will compute continuation probabilities using all “relevant” closures, defined as pregnancy, first and later expulsion, and removal for medical or personal reasons. We are used to computing rates and then converting to probabilities (see formula 3.2 in the textbook), but we can also compute the probability directly using as denominator an adjusted number at the start of each month obtained by adding half the relevant closures to the exposure.

It is easy to verify that the two approaches given exactly the same answer. For example in the first month we have 12 relevant closures. Dividing by the 232 woman-months of exposure we obtain a rate of 0.0517 which converts to a probability of 0.0504 (using formula 3.12 in the text: q = 2 m/(2 + m)). Or we can divide 12 by the adjusted denominator of 232 + 12/2 = 238 to obtain 0.0504 directly.

Once we have the probability of discontinuation in each month we obtain the probability of continuation as the complement, and the cumulative continuation probability (unfortunately often called cumulative continuation “rate”) as a cumulative product

. gen relclos = cap + cfe + cle + crm + crp

. gen nadj = expo + relclos/2

. gen q = relclos/nadj

. gen p = 1 - q

. gen cr = exp(sum(log(p)))       

. list month nadj relclos q p cr in 1/12, clean

       month    nadj   relclos           q           p          cr  
  1.       1     238        12   .05042017   .94957983   .94957983  
  2.       2   208.5         4   .01918465   .98081535   .93136247  
  3.       3   190.5         6   .03149606   .96850394   .90202822  
  4.       4   167.5         5   .02985075   .97014925   .87510201  
  5.       5     147         1   .00680272   .99319728   .86914893  
  6.       6   133.5         1   .00749064   .99250936   .86263845  
  7.       7   118.5         2   .01687764   .98312236   .84807915  
  8.       8   104.5         3   .02870813   .97129187   .82373238  
  9.       9    89.5         3   .03351955   .96648045   .79612124  
 10.      10      72         1   .01388889   .98611111     .785064  
 11.      11    57.5         0           0           1     .785064  
 12.      12    43.5         1   .02298851   .97701149   .76701655  
> tietze <- mutate(tietze, relclos = cap + cfe + cle + crm + crp,
+   nadj = expo + relclos/2,
+   q = relclos/nadj,
+   p = 1 - q,
+   cr = cumprod(p))
> select(tietze, month, nadj, relclos, q, p, cr) |> slice(1:12)
# A tibble: 12 × 6
   month  nadj relclos       q     p    cr
   <dbl> <dbl>   <dbl>   <dbl> <dbl> <dbl>
 1     1 238        12 0.0504  0.950 0.950
 2     2 208.        4 0.0192  0.981 0.931
 3     3 190.        6 0.0315  0.969 0.902
 4     4 168.        5 0.0299  0.970 0.875
 5     5 147         1 0.00680 0.993 0.869
 6     6 134.        1 0.00749 0.993 0.863
 7     7 118.        2 0.0169  0.983 0.848
 8     8 104.        3 0.0287  0.971 0.824
 9     9  89.5       3 0.0335  0.966 0.796
10    10  72         1 0.0139  0.986 0.785
11    11  57.5       0 0       1     0.785
12    12  43.5       1 0.0230  0.977 0.767

So the probability of continuing use after 12 months is 76.7%.

Net Rates of Events

We now compute so-called “net” rates of events, which correspond to the multiple decrement life table and reflect the probabilities of experiencing various events in the presence of the competing risks. Here is the calculation for pregnancies (technically closures due to accidental pregnancies or cap).

We obtain a conditional monthly probability of pregnancy dividing pregnancies by the adjusted denominator, and then unconditional probabilities multiplying by the continuation probability at the beginning of the month, which can be accumulated over duration of use.

. gen qap = cap/nadj

. gen lcr = cr[_n-1]    // lagged continuation rate
(1 missing value generated)

. replace lcr = 1 in 1
(1 real change made)

. gen cnap = sum(lcr * qap)

. list month nadj cap qap cnap in 1/12, clean

       month    nadj   cap         qap        cnap  
  1.       1     238     0           0           0  
  2.       2   208.5     0           0           0  
  3.       3   190.5     2   .01049869   .00977808  
  4.       4   167.5     3   .01791045   .02593381  
  5.       5     147     0           0   .02593381  
  6.       6   133.5     0           0   .02593381  
  7.       7   118.5     1   .00843882   .03321346  
  8.       8   104.5     0           0   .03321346  
  9.       9    89.5     0           0   .03321346  
 10.      10      72     1   .01388889    .0442707  
 11.      11    57.5     0           0    .0442707  
 12.      12    43.5     0           0    .0442707  
> tietze <- mutate(tietze, qap = cap/nadj,
+   lcr = c(1, cr[-last]),
+   cnap = cumsum(lcr * qap))
> select(tietze, month, nadj, cap, qap, cnap) |> slice(1:12)
# A tibble: 12 × 5
   month  nadj   cap     qap    cnap
   <dbl> <dbl> <dbl>   <dbl>   <dbl>
 1     1 238       0 0       0      
 2     2 208.      0 0       0      
 3     3 190.      2 0.0105  0.00978
 4     4 168.      3 0.0179  0.0259 
 5     5 147       0 0       0.0259 
 6     6 134.      0 0       0.0259 
 7     7 118.      1 0.00844 0.0332 
 8     8 104.      0 0       0.0332 
 9     9  89.5     0 0       0.0332 
10    10  72       1 0.0139  0.0443 
11    11  57.5     0 0       0.0443 
12    12  43.5     0 0       0.0443 

The probability of accidental pregnancy in the first year of use is 4.4%. Try computing similar probabilities for the other relevant closures. You should get 4.3% for first expulsions, 3.6% for later expulsions, 6.7% for medical reasons and 4.3% for personal reasons. These add up to 23.3%, which is of course the complement of the probability of continuing use after 12 months.

These “rates” can also be computed for events other than closures using exactly the same procedure. Here is the probability of a first expulsion in the presence of the other risks:

. gen qfe = fe/nadj

. gen cnfe = sum(lcr * qfe)

. list month nadj fe qfe cnfe in 1/12, clean

       month    nadj   fe         qfe        cnfe  
  1.       1     238   15   .06302521   .06302521  
  2.       2   208.5    4   .01918465   .08124257  
  3.       3   190.5    2   .01049869   .09102065  
  4.       4   167.5    0           0   .09102065  
  5.       5     147    2   .01360544    .1029268  
  6.       6   133.5    1   .00749064   .10943728  
  7.       7   118.5    3   .02531646   .13127623  
  8.       8   104.5    1   .00956938   .13939182  
  9.       9    89.5    0           0   .13939182  
 10.      10      72    0           0   .13939182  
 11.      11    57.5    0           0   .13939182  
 12.      12    43.5    1   .02298851   .15743927  
> tietze <- mutate(tietze, qfe = fe/nadj,   
+   cnfe = cumsum(lcr * qfe))
> select(tietze, month, nadj, fe, qfe, cnfe) |> slice(1:12)
# A tibble: 12 × 5
   month  nadj    fe     qfe   cnfe
   <dbl> <dbl> <dbl>   <dbl>  <dbl>
 1     1 238      15 0.0630  0.0630
 2     2 208.      4 0.0192  0.0812
 3     3 190.      2 0.0105  0.0910
 4     4 168.      0 0       0.0910
 5     5 147       2 0.0136  0.103 
 6     6 134.      1 0.00749 0.109 
 7     7 118.      3 0.0253  0.131 
 8     8 104.      1 0.00957 0.139 
 9     9  89.5     0 0       0.139 
10    10  72       0 0       0.139 
11    11  57.5     0 0       0.139 
12    12  43.5     1 0.0230  0.157 

We get a 15.7% probability of first expulsion in the first year of use. (Recall that first expulsions are not “fatal”, as the IUD can be reinserted.) Try computing similar rates for later expulsions and removals for medical and personal reasons. You should get 6.1%, 8.3% and 4.3% respectively. For pregnancies the answer is the same as above because every termination is a closure.

Gross Rates of Events

We can also compute the equivalent of an associated single-decrement life table under the assumption of independence of risks. The results are often called “gross” rates. The calculation proceeds as before but we use a new adjusted denominator, which adds to the woman-months of exposure half the events of interest (as opposed to half of all relevant closures). Let us do the calculation for pregnancies

. gen nadjap = expo + 0.5 * cap // pregnancies are only risk

. gen gqap = cap/nadjap

. gen gcrap = exp(sum(log(1 - gqap)))     // continuation

. gen gdrap = 1 - gcrap                   // discontinuation

. list month gqap gcrap gdrap in 1/12, clean

       month        gqap       gcrap       gdrap  
  1.       1           0           1           0  
  2.       2           0           1           0  
  3.       3   .01061008   .98938992   .01061008  
  4.       4   .01801802   .97156308   .02843692  
  5.       5           0   .97156308   .02843692  
  6.       6           0   .97156308   .02843692  
  7.       7   .00847458   .96332949   .03667051  
  8.       8           0   .96332949   .03667051  
  9.       9           0   .96332949   .03667051  
 10.      10   .01388889   .94994991   .05005009  
 11.      11           0   .94994991   .05005009  
 12.      12           0   .94994991   .05005009  
> tietze <- mutate(tietze, nadjap = expo + cap/2,
+   gqap = cap/nadjap,
+   gcrap = cumprod(1 - gqap),
+   gdrap = 1 - gcrap)  
> select(tietze, month, gqap, gcrap, gdrap) |> slice(1:12)
# A tibble: 12 × 4
   month    gqap gcrap  gdrap
   <dbl>   <dbl> <dbl>  <dbl>
 1     1 0       1     0     
 2     2 0       1     0     
 3     3 0.0106  0.989 0.0106
 4     4 0.0180  0.972 0.0284
 5     5 0       0.972 0.0284
 6     6 0       0.972 0.0284
 7     7 0.00847 0.963 0.0367
 8     8 0       0.963 0.0367
 9     9 0       0.963 0.0367
10    10 0.0139  0.950 0.0501
11    11 0       0.950 0.0501
12    12 0       0.950 0.0501

The probability of accidental pregnancy would be a bit higher, 5%, in the absence of the other risks. The calculation is based on the assumption of independence of risks, as the observed probabilities of pregnancy are applied to women who discontinued for other reasons.

Note that the demographic literature uses “net” for rates in the presence of other risks and “gross” for rates in the absence of other risks. The statistical literature reverses the usage.

A useful article in addition to Tietze’s classic is S. R. Karia, J. Toivonen and E. Arjas (1998), Analysis of Contraceptive Failure Data in Intrauterine Device Studies, Contraception, 58:361-374.