packages

pacman::p_load(tidyverse,
               labelled, # set_variable_labels
               snakecase, #to_title_case
               janitor, 
               lubridate, 
               survival, 
               survminer, 
               gtsummary)

preparation

theme_set(theme_minimal())

Data

df <- read_csv("https://docs.google.com/spreadsheets/d/e/2PACX-1vTRhbK2QPcx_WdSa6ImgzVH4PBtWAbe0j79_gxbdNDZaPkvvk58ILVMrQ8yvai-kWnPeXcPzxsZHuFT/pub?gid=1722645119&single=true&output=csv")
Rows: 27 Columns: 17
── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (7): Sex, date of birth, date of surgery, control, donor tooth- recipient reagion, departament, development stage
dbl (10): Patient nr., Teeth nr., ID, age at surgery, hard wire, recipient region, total surgery time (min.), extra- alveolar time (SEC.), time to pl...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
names(df)
 [1] "Patient nr."                    "Teeth nr."                      "ID"                             "Sex"                           
 [5] "date of birth"                  "date of surgery"                "control"                        "age at surgery"                
 [9] "donor tooth- recipient reagion" "departament"                    "hard wire"                      "development stage"             
[13] "recipient region"               "total surgery time (min.)"      "extra- alveolar time (SEC.)"    "time to place"                 
[17] "Sucessfull after 1y"           
glimpse(df)
Rows: 27
Columns: 17
$ `Patient nr.`                    <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
$ `Teeth nr.`                      <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 21, 22, 23
$ ID                               <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 21, 22, 23
$ Sex                              <chr> "Female", "Male", "Female", "Female", "Male", "Female", "Male", "Female", "Female", "Female", "Female", "Femal…
$ `date of birth`                  <chr> "26/11/1998", "1/8/2000", "17/6/1998", "5/10/1998", "10/10/2001", "12/1/2000", "14/5/2000", "4/2/2002", "22/4/…
$ `date of surgery`                <chr> "14/8/2019", "27/8/2019", "9/12/2019", "31/10/2019", "26/9/2019", "27/1/2020", "11/2/2020", "7/5/2020", "13/5/…
$ control                          <chr> "13/8/2020", "26/8/2020", "8/12/2020", "30/10/2020", "25/9/2020", "26/1/2021", "10/2/2021", "7/5/2021", "13/5/…
$ `age at surgery`                 <dbl> 20, 19, 21, 21, 17, 20, 19, 18, 16, 16, 16, 16, 14, 17, 17, 17, 14, 18, 17, 22, 16, 16, 20, 18, 18, 17, 17
$ `donor tooth- recipient reagion` <chr> "28-36", "38-37", "38-36", "38-36", "18-36", "38-16", "28-35", "18-46", "48-25", "28-23", "38-15", "28-26", "2…
$ departament                      <chr> "O", "T", "O", "O", "O", "S", "O", "T", "O", "O", "O", "T", "O", "O", "S", "O", "O", "S", "S", "S", "O", "O", …
$ `hard wire`                      <dbl> 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
$ `development stage`              <chr> "F", "G", "F", "H", "F", "F", "G", "F", "F", "F", "H", "F", "D", "E", "G", "E", "D", "E", "F", "G", "F", "F", …
$ `recipient region`               <dbl> 3, 1, 2, 2, 3, 3, 4, 1, 4, 4, 4, 2, 2, 2, 2, 2, 5, 5, 2, 3, 2, 2, 2, 5, 5, 5, 2
$ `total surgery time (min.)`      <dbl> 50, 30, 60, 75, 70, 110, 70, 50, NA, NA, NA, 60, 50, 70, 70, 60, 90, 120, 60, 70, NA, NA, 90, NA, NA, 50, 45
$ `extra- alveolar time (SEC.)`    <dbl> 180, 30, 30, 60, 90, 180, 30, 30, 60, 300, 30, 120, 60, 30, 90, 60, 90, 30, 30, 30, 60, 30, 60, 180, 60, 30, 60
$ `time to place`                  <dbl> 3, 1, 2, 2, 3, 5, 1, 3, 2, 3, 1, 3, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 4, 1, 1, 2
$ `Sucessfull after 1y`            <dbl> 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1

Remove some columns and normalize names

df <- df %>% 
  janitor::clean_names() %>% 
  select(-c( patient_nr))

Exploratory data analysis

How many patients?

n_distinct(df$id)
[1] 23

Table 1

df %>%
  select(
    -c(
      teeth_nr,
      date_of_birth,
      date_of_surgery,
      control,
      donor_tooth_recipient_reagion
    )
  ) %>%
  # group_by(id) %>%
  # select(-id) %>%
  labelled::set_variable_labels(
    .labels = snakecase::to_title_case(names(.))
  ) %>% 
  gtsummary::tbl_summary(by = sex, 
                         missing_text = "(Missing)")
Characteristic Female, N = 171 Male, N = 101
Id 10.0 (8.0, 15.0) 17.5 (8.0, 20.5)
Age at Surgery
14 1 (5.9%) 1 (10%)
16 4 (24%) 2 (20%)
17 5 (29%) 2 (20%)
18 1 (5.9%) 3 (30%)
19 0 (0%) 2 (20%)
20 3 (18%) 0 (0%)
21 2 (12%) 0 (0%)
22 1 (5.9%) 0 (0%)
Departament
O 10 (59%) 8 (80%)
S 4 (24%) 1 (10%)
T 3 (18%) 1 (10%)
Hard Wire 9 (53%) 1 (10%)
Development Stage
D 1 (5.9%) 1 (10%)
E 2 (12%) 4 (40%)
F 10 (59%) 3 (30%)
G 2 (12%) 2 (20%)
H 2 (12%) 0 (0%)
Recipient Region
1 1 (5.9%) 1 (10%)
2 9 (53%) 3 (30%)
3 3 (18%) 1 (10%)
4 3 (18%) 1 (10%)
5 1 (5.9%) 4 (40%)
Total Surgery Time Min
30 0 (0%) 1 (17%)
45 1 (7.1%) 0 (0%)
50 2 (14%) 2 (33%)
60 4 (29%) 0 (0%)
70 3 (21%) 2 (33%)
75 1 (7.1%) 0 (0%)
90 2 (14%) 0 (0%)
110 1 (7.1%) 0 (0%)
120 0 (0%) 1 (17%)
(Missing) 3 4
Extra Alveolar Time Sec
30 6 (35%) 5 (50%)
60 5 (29%) 3 (30%)
90 2 (12%) 1 (10%)
120 1 (5.9%) 0 (0%)
180 2 (12%) 1 (10%)
300 1 (5.9%) 0 (0%)
Time to Place
1 4 (24%) 7 (70%)
2 8 (47%) 1 (10%)
3 4 (24%) 1 (10%)
4 0 (0%) 1 (10%)
5 1 (5.9%) 0 (0%)
Sucessfull after 1 y 16 (94%) 7 (70%)

1 Median (IQR); n (%)

check if the successful is affected by something

df %>% 
  mutate(sucessfull_after_1y = case_when(
    sucessfull_after_1y == "0" ~ 0, 
    TRUE ~ 1
  )) %>% 
  glm(sucessfull_after_1y ~ 
            sex + 
            time_to_place + 
            extra_alveolar_time_sec + 
            development_stage + 
            departament + 
            recipient_region, 
          data = ., 
          family = binomial) %>% 
  gtsummary::tbl_regression(exponentiate = TRUE)
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Characteristic OR1 95% CI1 p-value
sex
Female
Male 0.00 0.00, Inf >0.9
time_to_place 755 0.00, NA >0.9
extra_alveolar_time_sec 1.00 0.87, 1.15 >0.9
development_stage
D
E 0.00 0.00, Inf >0.9
F 0.00 0.00, Inf >0.9
G 0.00 0.00, Inf >0.9
H 0.00 0.00, Inf >0.9
departament
O
S 0.00 0.00, Inf >0.9
T 87,268,130,365,153,488 0.00, Inf >0.9
recipient_region 7,893,072,639 0.00, Inf >0.9

1 OR = Odds Ratio, CI = Confidence Interval

m1 %>% 
  
Error: Incomplete expression: m1 %>% 
  

Survival analysis

Convert date of surgery and control to date format

Create the time_event variable

Create the surv object

Check

surv_object
 [1] 365  365  365  365+ 365  365  365  365  365  365  365  365  365  365  365  365  365  365+ 365  365  365+ 365 
[23] 365  365  365  365+ 365 

no negative time?

which(df$time_event < 0) 
integer(0)
fit1 <- survival::survfit(surv_object ~ department, data = df)
Error in eval(predvars, data, env) : object 'department' not found
summary(fit1)
Call: survfit(formula = surv_object ~ departament, data = df)

                departament=O 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
    365.0000      18.0000      15.0000       0.1667       0.0878       0.0593       0.4682 

                departament=S 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
    365.0000       5.0000       4.0000       0.2000       0.1789       0.0346       1.0000 

                departament=T 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
         365            4            4            0          NaN           NA           NA 
survival::survfit(surv_object ~ departament, data = df)
Call: survfit(formula = surv_object ~ departament, data = df)

               n events median 0.95LCL 0.95UCL
departament=O 18     15    365     365     365
departament=S  5      4    365     365      NA
departament=T  4      4    365      NA      NA

LS0tCnRpdGxlOiAiTWlrcyBBdXRvdHJhbnNwbGFudGF0aW9uIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIHBhY2thZ2VzCgpgYGB7cn0KcGFjbWFuOjpwX2xvYWQodGlkeXZlcnNlLAogICAgICAgICAgICAgICBsYWJlbGxlZCwgIyBzZXRfdmFyaWFibGVfbGFiZWxzCiAgICAgICAgICAgICAgIHNuYWtlY2FzZSwgI3RvX3RpdGxlX2Nhc2UKICAgICAgICAgICAgICAgamFuaXRvciwgCiAgICAgICAgICAgICAgIGx1YnJpZGF0ZSwgCiAgICAgICAgICAgICAgIHN1cnZpdmFsLCAKICAgICAgICAgICAgICAgc3Vydm1pbmVyLCAKICAgICAgICAgICAgICAgZ3RzdW1tYXJ5KQpgYGAKCiMjIHByZXBhcmF0aW9uCgpgYGB7cn0KdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkKYGBgCgojIERhdGEKCmBgYHtyfQpkZiA8LSByZWFkX2NzdigiaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvZS8yUEFDWC0xdlRSaGJLMlFQY3hfV2RTYTZJbWd6Vkg0UEJ0V0FiZTBqNzlfZ3hiZE5EWmFQa3Z2azU4SUxWTXJROHl2YWkta1duUGVYY1B6eHNaSHVGVC9wdWI/Z2lkPTE3MjI2NDUxMTkmc2luZ2xlPXRydWUmb3V0cHV0PWNzdiIpCmBgYAoKYGBge3J9Cm5hbWVzKGRmKQpgYGAKCmBgYHtyfQpnbGltcHNlKGRmKQpgYGAKClJlbW92ZSBzb21lIGNvbHVtbnMgYW5kIG5vcm1hbGl6ZSBuYW1lcwoKYGBge3J9CmRmIDwtIGRmICU+JSAKICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSAKICBzZWxlY3QoLWMoIHBhdGllbnRfbnIpKQpgYGAKCiMjIEV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMKCiMjIEhvdyBtYW55IHBhdGllbnRzPyAKCmBgYHtyfQpuX2Rpc3RpbmN0KGRmJGlkKQpgYGAKCiMjIFRhYmxlIDEKCmBgYHtyfQpkZiAlPiUKICBzZWxlY3QoCiAgICAtYygKICAgICAgdGVldGhfbnIsCiAgICAgIGRhdGVfb2ZfYmlydGgsCiAgICAgIGRhdGVfb2Zfc3VyZ2VyeSwKICAgICAgY29udHJvbCwKICAgICAgZG9ub3JfdG9vdGhfcmVjaXBpZW50X3JlYWdpb24KICAgICkKICApICU+JQogICMgZ3JvdXBfYnkoaWQpICU+JQogICMgc2VsZWN0KC1pZCkgJT4lCiAgbGFiZWxsZWQ6OnNldF92YXJpYWJsZV9sYWJlbHMoCiAgICAubGFiZWxzID0gc25ha2VjYXNlOjp0b190aXRsZV9jYXNlKG5hbWVzKC4pKQogICkgJT4lIAogIGd0c3VtbWFyeTo6dGJsX3N1bW1hcnkoYnkgPSBzZXgsIAogICAgICAgICAgICAgICAgICAgICAgICAgbWlzc2luZ190ZXh0ID0gIihNaXNzaW5nKSIpCmBgYAoKIyMgY2hlY2sgaWYgdGhlIHN1Y2Nlc3NmdWwgaXMgYWZmZWN0ZWQgYnkgc29tZXRoaW5nCgpgYGB7cn0KZGYgJT4lIAogIG11dGF0ZShzdWNlc3NmdWxsX2FmdGVyXzF5ID0gY2FzZV93aGVuKAogICAgc3VjZXNzZnVsbF9hZnRlcl8xeSA9PSAiMCIgfiAwLCAKICAgIFRSVUUgfiAxCiAgKSkgJT4lIAogIGdsbShzdWNlc3NmdWxsX2FmdGVyXzF5IH4gCiAgICAgICAgICAgIHNleCArIAogICAgICAgICAgICB0aW1lX3RvX3BsYWNlICsgCiAgICAgICAgICAgIGV4dHJhX2FsdmVvbGFyX3RpbWVfc2VjICsgCiAgICAgICAgICAgIGRldmVsb3BtZW50X3N0YWdlICsgCiAgICAgICAgICAgIGRlcGFydGFtZW50ICsgCiAgICAgICAgICAgIHJlY2lwaWVudF9yZWdpb24sIAogICAgICAgICAgZGF0YSA9IC4sIAogICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwpICU+JSAKICBndHN1bW1hcnk6OnRibF9yZWdyZXNzaW9uKGV4cG9uZW50aWF0ZSA9IFRSVUUpCmBgYAoKYGBge3J9Cm0xICU+JSAKICAKYGBgCgojIFN1cnZpdmFsIGFuYWx5c2lzCgpDb252ZXJ0IGRhdGUgb2Ygc3VyZ2VyeSBhbmQgY29udHJvbCB0byBkYXRlIGZvcm1hdAoKYGBge3J9CmRmIDwtIGRmICU+JSAKICAgIG11dGF0ZShkYXRlX29mX3N1cmdlcnkgPSBsdWJyaWRhdGU6OmRteShkYXRlX29mX3N1cmdlcnkpLCAKICAgICAgICAgY29udHJvbCA9IGx1YnJpZGF0ZTo6ZG15KGNvbnRyb2wpKSAKYGBgCgpDcmVhdGUgdGhlIHRpbWVfZXZlbnQgdmFyaWFibGUKCmBgYHtyfQpkZiA8LSBkZiAlPiUgCiAgbXV0YXRlKHRpbWVfZXZlbnQgPSBhcy5kb3VibGUoZGlmZnRpbWUoY29udHJvbCwgZGF0ZV9vZl9zdXJnZXJ5LCB1bml0PSJkYXlzIikpKQogIG11dGF0ZSh0aW1lX2V2ZW50ID0gZGlmZnRpbWUobHVicmlkYXRlOjp5bWQoY29udHJvbCksCiAgICAgICAgICAgICAgICAgICBsdWJyaWRhdGU6OnltZChkYXRlX29mX3N1cmdlcnkpLAogICAgICAgICAgICAgICAgICAgdW5pdHMgPSAiZGF5cyIpKQpgYGAKCiMjIENyZWF0ZSB0aGUgc3VydiBvYmplY3QKCmBgYHtyfQpzdXJ2X29iamVjdCA8LSBzdXJ2aXZhbDo6U3Vydih0aW1lID0gZGYkdGltZV9ldmVudCwgZXZlbnQgPSBkZiRzdWNlc3NmdWxsX2FmdGVyXzF5KQpgYGAKCkNoZWNrCgpgYGB7cn0Kc3Vydl9vYmplY3QKYGBgCgpubyBuZWdhdGl2ZSB0aW1lPwoKYGBge3J9CndoaWNoKGRmJHRpbWVfZXZlbnQgPCAwKSAKYGBgCgpgYGB7cn0KZml0MSA8LSBzdXJ2aXZhbDo6c3VydmZpdChzdXJ2X29iamVjdCB+IGRlcGFydGFtZW50LCBkYXRhID0gZGYpCmBgYAoKYGBge3J9CnN1bW1hcnkoZml0MSkKYGBgCgpgYGB7cn0Kc3Vydml2YWw6OnN1cnZmaXQoc3Vydl9vYmplY3QgfiBkZXBhcnRhbWVudCwgZGF0YSA9IGRmKQpgYGAKCmBgYHtyfQpzdXJ2bWluZXI6Omdnc3VydnBsb3QoCiAgZml0MSwKICBkYXRhID0gZGYsCiAgY29uZi5pbnQgPSBUUlVFLAogIGxlZ2VuZC5sYWJzID0gYygiTyIsICJUIiwgIlMiKSwKICBmdW4gPSAiZXZlbnQiKSArCiAgbGFicyh0aXRsZSA9ICJTdXJ2aXZhbCB0aW1lIChkYXlzKSIsCiAgICAgICB4ID0gIlRpbWUgaW4gZGF5cyIsCiAgICAgICB5ID0gIlN1Y2VzcyBQcm9iYWJpbGl0eSIpCmBgYAo=