## # A tibble: 6 × 7
## `Record id` Lab_a_t0 Lab_a_t1 Lab_a_t2 Lab_b_t0 Lab_b_t1 Lab_b_t2
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 2 5 4 100 400 500
## 2 2 6 5 4 200 400 100
## 3 3 8 29 NA 150 900 NA
## 4 4 1 4 4 NA 500 700
## 5 5 3 7 3 160 550 150
## 6 6 10 48 67 420 1236 2474
dat.format.wide %>%
pivot_longer(
cols = Lab_a_t0:Lab_b_t2,
names_to = c("lab_n","time"), #names of new columns
names_pattern = "Lab_(.*)_(.*)", #using regular expression pattern in () to match the 2 new columns
values_to = "Value", #new column name for value
values_transform = list(Value = as.numeric) #transform the values to numeric
)
## # A tibble: 120 × 4
## `Record id` lab_n time Value
## <dbl> <chr> <chr> <dbl>
## 1 1 a t0 2
## 2 1 a t1 5
## 3 1 a t2 4
## 4 1 b t0 100
## 5 1 b t1 400
## 6 1 b t2 500
## 7 2 a t0 6
## 8 2 a t1 5
## 9 2 a t2 4
## 10 2 b t0 200
## # ℹ 110 more rows
.* from regular expression matches any number of
character (except newline).
Other arguments like values_drop_na = ,
names_prefix() could be added to pivot_longer
to further clean the value and column names.
## # A tibble: 10 × 2
## case_number specialty
## <dbl> <chr>
## 1 102001 Cardiology
## 2 102001 Urology
## 3 102002 Urology
## 4 102002 General Surgery
## 5 102003 Urology
## 6 102003 <NA>
## 7 102003 Cardiology
## 8 102004 Vascular Medicine
## 9 102004 Ob/Gyn
## 10 102004 <NA>
dat.format.long %>%
group_by(case_number) %>%
mutate(spec_index = paste0("specialty_", row_number())) %>% #create a index number
pivot_wider(
names_from = spec_index,
values_from = c(specialty)
)
## # A tibble: 27 × 4
## # Groups: case_number [27]
## case_number specialty_1 specialty_2 specialty_3
## <dbl> <chr> <chr> <chr>
## 1 102001 Cardiology Urology <NA>
## 2 102002 Urology General Surgery <NA>
## 3 102003 Urology <NA> Cardiology
## 4 102004 Vascular Medicine Ob/Gyn <NA>
## 5 102005 Urology Vascular Medicine Colon and Rectal Surg…
## 6 102006 Urology <NA> <NA>
## 7 102007 Vascular Medicine General Surgery <NA>
## 8 102008 Ob/Gyn <NA> <NA>
## 9 102009 General Surgery Internal Medicine Urology
## 10 102010 Colon and Rectal Surgery <NA> <NA>
## # ℹ 17 more rows
## # A tibble: 6 × 11
## `RedCap ID` `preop_dx_regurgitation (1=1, 0=0)` preop_dx_obstruction (1=1, 0…¹
## <dbl> <dbl> <dbl>
## 1 1 0 0
## 2 2 1 0
## 3 3 0 0
## 4 4 1 0
## 5 5 0 1
## 6 6 0 0
## # ℹ abbreviated name: ¹`preop_dx_obstruction (1=1, 0=0)`
## # ℹ 8 more variables: `preop_dx_respiratory_symp (1=1, 0=0)` <dbl>,
## # `preop_dx_chest_pain (1=1, 0=0)` <dbl>,
## # `preop_dx_early_satiety (1=Yes, 0=No)` <dbl>,
## # `preop_dx_anemia (1=1, 0=0)` <dbl>,
## # `preop_dx_asymptomatic (1=Yes, 0=No)` <dbl>,
## # `preop_upper_endoscopy (1=1, 0=0)` <dbl>, …
a. use gsub() from
base
gsub (pattern, replacement, x, ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)
#use string pattern to rename column names
gsub("\\s*\\(.*\\)", "", names(dat.string))
## [1] "RedCap ID" "preop_dx_regurgitation"
## [3] "preop_dx_obstruction" "preop_dx_respiratory_symp"
## [5] "preop_dx_chest_pain" "preop_dx_early_satiety"
## [7] "preop_dx_anemia" "preop_dx_asymptomatic"
## [9] "preop_upper_endoscopy" "preop_endo_hiatal_hernia"
## [11] "preop_endo_barretts"
\\s represents a white space character.
\\s* matches zero or more white space characters.
\\(: Matches an open parenthesis (.
.*: Matches zero or more of any character (except
newlines).
\\): Matches a close parenthesis ).
b. use str_remove() or
str_replace() from
stringr
colnames(dat.string) <- names(dat.string)
#str_replace(string, pattern, replacement)
#str_remove(string, pattern)
str_replace(names(dat.string), "\\s*\\(.*\\)", "")
## [1] "RedCap ID" "preop_dx_regurgitation"
## [3] "preop_dx_obstruction" "preop_dx_respiratory_symp"
## [5] "preop_dx_chest_pain" "preop_dx_early_satiety"
## [7] "preop_dx_anemia" "preop_dx_asymptomatic"
## [9] "preop_upper_endoscopy" "preop_endo_hiatal_hernia"
## [11] "preop_endo_barretts"
c. clean column names directly when reading the data
## # A tibble: 10 × 6
## patient_n date1 date2 date3 date4 date5
## <dbl> <dbl> <chr> <chr> <chr> <chr>
## 1 1 45555 <NA> <NA> <NA> <NA>
## 2 2 45432 <NA> <NA> <NA> <NA>
## 3 88 NA 12/1/2020 <NA> <NA> <NA>
## 4 112 NA 2/1/2011 <NA> <NA> <NA>
## 5 113 NA <NA> 10-Jan-1994 <NA> <NA>
## 6 114 NA <NA> 10-Nov-2024 <NA> <NA>
## 7 115 NA <NA> <NA> 2025-2-30 <NA>
## 8 116 NA <NA> <NA> <NA> 10 Feburary 2007
## 9 117 NA <NA> <NA> <NA> 2025-01-10 15:30:00 UTC
## 10 134 NA <NA> <NA> <NA> 2010-03-20 13:45:00 UTC
as.Date()
ymd()mdy() from base and
lubridate package:dat.date %>%
mutate(date1.tidy = as.Date(date1, origin = "1899-12-30"),
date2.tidy = mdy(date2),
date3.tidy = as.Date(date3, format = "%d-%b-%Y"),
date4.tidy = as.Date(date5, format = "%d %m %Y")) %>% #In "%d-%b-%Y", d=date of month, b=abbr. of month, Y=year
select(patient_n, date1, date1.tidy, date2, date2.tidy, date3, date3.tidy)
## # A tibble: 10 × 7
## patient_n date1 date1.tidy date2 date2.tidy date3 date3.tidy
## <dbl> <dbl> <date> <chr> <date> <chr> <date>
## 1 1 45555 2024-09-20 <NA> NA <NA> NA
## 2 2 45432 2024-05-20 <NA> NA <NA> NA
## 3 88 NA NA 12/1/2020 2020-12-01 <NA> NA
## 4 112 NA NA 2/1/2011 2011-02-01 <NA> NA
## 5 113 NA NA <NA> NA 10-Jan-1994 1994-01-10
## 6 114 NA NA <NA> NA 10-Nov-2024 2024-11-10
## 7 115 NA NA <NA> NA <NA> NA
## 8 116 NA NA <NA> NA <NA> NA
## 9 117 NA NA <NA> NA <NA> NA
## 10 134 NA NA <NA> NA <NA> NA
as.Date() is used to convert between
numeric to date. Starting date should
be specify using origin =. The format = should
match.
%d-%b-%Y matches 10-Jan-1994 and d=date
of month, b=abbr. of month, Y=year
%d %m %Y matches 10 Feb 2007
mdy(), ymd(),
dmy() from lubridate package
transforms dates stored in character and numeric vectors to Date
format.
ymd() needs to be used to correctly convert 2020/01/03
from character to date class.parse_date() from parsedate
package## # A tibble: 7 × 2
## patient_n month_year_of_transplantation
## <dbl> <chr>
## 1 88 12/1/2020
## 2 112 2/1/2011
## 3 113 10-Jan-1994
## 4 114 10-Nov-2024
## 5 116 10 Feb 2007
## 6 117 2025-01-10 15:30:00 UTC
## 7 134 2010-03-20 13:45:00 UTC
parse_date(dates, approx = TRUE, default_tz = "UTC")
dates is a character vector but can have a wide
range of formats
dat.date2 %>%
mutate(date.tidy = as.Date(parse_date(month_year_of_transplantation)))
## # A tibble: 7 × 3
## patient_n month_year_of_transplantation date.tidy
## <dbl> <chr> <date>
## 1 88 12/1/2020 NA
## 2 112 2/1/2011 NA
## 3 113 10-Jan-1994 NA
## 4 114 10-Nov-2024 NA
## 5 116 10 Feb 2007 NA
## 6 117 2025-01-10 15:30:00 UTC NA
## 7 134 2010-03-20 13:45:00 UTC NA
coalesce() finds the first non-missing value at each
position, given a set of vectors.
## # A tibble: 6 × 8
## cl_pat_mrn_id drug1 drug2 drug3 drug4 drug5 drug6 drug7
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 10014905 1 1 1 1 1 0 1
## 2 10030773 0 1 0 1 0 1 1
## 3 10075530 0 0 NA NA NA 0 NA
## 4 10120942 1 0 0 NA 0 0 NA
## 5 10185955 0 0 NA 0 0 0 0
## 6 10189373 NA 0 1 0 NA 1 NA
dat.coalesce %>%
mutate(across(everything(), ~ ifelse(.==0, NA, .))) %>%
mutate(drug123 = coalesce(drug1, drug2, drug3, drug4, drug5, drug6, drug7, 0)) %>%
slice(1:5)
## # A tibble: 5 × 9
## cl_pat_mrn_id drug1 drug2 drug3 drug4 drug5 drug6 drug7 drug123
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 10014905 1 1 1 1 1 NA 1 1
## 2 10030773 NA 1 NA 1 NA 1 1 1
## 3 10075530 NA NA NA NA NA NA NA 0
## 4 10120942 1 NA NA NA NA NA NA 1
## 5 10185955 NA NA NA NA NA NA NA 0
#Default to 0 if all are NA
summarize() to reduce rows within a group.
## person_id drug1 drug2 drug3 drug4
## 1 id_1 NA 1 1 0
## 2 id_1 1 1 1 NA
## 3 id_2 1 0 0 0
## 4 id_2 0 NA NA 0
## 5 id_3 0 1 0 0
## 6 id_3 0 1 NA 1
dat.row %>%
group_by(person_id) %>%
summarize(across(drug1:drug4, max, na.rm=TRUE))
## Warning: There was 1 warning in `summarize()`.
## ℹ In argument: `across(drug1:drug4, max, na.rm = TRUE)`.
## ℹ In group 1: `person_id = "id_1"`.
## Caused by warning:
## ! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
## Supply arguments directly to `.fns` through an anonymous function instead.
##
## # Previously
## across(a:b, mean, na.rm = TRUE)
##
## # Now
## across(a:b, \(x) mean(x, na.rm = TRUE))
## # A tibble: 3 × 5
## person_id drug1 drug2 drug3 drug4
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 id_1 1 1 1 0
## 2 id_2 1 0 0 0
## 3 id_3 0 1 0 1
Also works for character:
## person_id insurance edu
## 1 id_1 Private College
## 2 id_1 Private <NA>
## 3 id_2 Public High School
## 4 id_2 Public High School
## 5 id_3 <NA> <NA>
## 6 id_3 Public College
dat.row.2 %>%
group_by(person_id) %>%
summarize(
insurance = paste(unique(na.omit(insurance)), collapse = ", "),
edu = paste(unique(na.omit(edu)), collapse = ", "),
.groups = "drop"
)
## # A tibble: 3 × 3
## person_id insurance edu
## <chr> <chr> <chr>
## 1 id_1 Private College
## 2 id_2 Public High School
## 3 id_3 Public College
map functions from purrr packageThe map functions transform their input by applying a function to each element of a list or atomic vector and returning an object of the same length as the input.
map() applies a function to each element of a
list/vector and returns a list.
map2() applies a function to two lists/vectors at
the same time (pairwise).
map_dfr() works like map(), but it
automatically binds the results row-wise
(dfr = “data frame row-bind”).
Other map functions includes: map_lgl(),
map_int(), map_dbl()
map_chr()
## [1] "PAT_MRN_ID" "Symptom Group" "LASTNAME"
## [4] "FIRSTNAME" "Pre-Remission Eckardt" "Pre-Remission SDI"
## # A tibble: 6 × 43
## pat_mrn_id symptom_group lastname firstname pre_remission_eckardt
## <int> <chr> <chr> <chr> <chr>
## 1 1 Persistent Symptoms Auito Alex 6
## 2 2 Persistent Symptoms Bates Ronald <NA>
## 3 3 Persistent Symptoms Beery Pamela <NA>
## 4 4 Persistent Symptoms Blevins Amber <NA>
## 5 5 Persistent Symptoms Coburn David 5
## 6 6 Persistent Symptoms Collette Anthony 1
## # ℹ 38 more variables: pre_remission_sdi <chr>,
## # pre_remission_promis_t_score <chr>, pre_remission_promis_se <chr>,
## # pre_remission_gerd_hrql_heartburn_total <chr>,
## # pre_remission_gerd_hrql_regurgitation_total <chr>,
## # pre_remission_gerd_hrql_total <chr>, pre_remission_gerd_total <chr>,
## # pre_remission_promis_global_total_t_score_physical <chr>,
## # pre_remission_promis_global_total_t_score_mental <chr>, …
Apply labels using map2()
#apply labels
map2(names(dat), dat.label,
function(col_name, col_label) {
labels(dat[[col_name]]) <<- col_label
})
map2 iterates over two vectors or lists
(names(dat) and dat.label) in parallel.Given there’s multiple spreadsheets in the project folder, we need to read into R and combine as one.
Try use map function to read all csv. data files and combine them into 1 data frame with year as an identifier.
library(purrr)
library(readr)
ParentDir <- "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF"
filepath <- list.files(path = ParentDir,
pattern = "PUF_ECODEDES.csv",
full.names = TRUE,
recursive = TRUE) #This allows to search both specified dir and all of its subdirectories
filepath
## [1] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2008 4/CSV/PUF_ECODEDES.csv"
## [2] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2009/CSV/PUF_ECODEDES.csv"
## [3] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2010/CSV/PUF_ECODEDES.csv"
## [4] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2011/CSV/PUF_ECODEDES.csv"
## [5] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2012/CSV/PUF_ECODEDES.csv"
## [6] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2013/CSV/PUF_ECODEDES.csv"
## [7] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2014/CSV/PUF_ECODEDES.csv"
## [8] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2015/CSV/PUF_ECODEDES.csv"
## [9] "/home/tuc/projects/GeneralSurgery/Sofya_Asfaw/pTQIP_racial/TQIP_PUF/PUF AY 2016/CSV/PUF_ECODEDES.csv"
data.list <- map(filepath, ~ read_csv(.x, col_types = cols(.default = "c")))
data.list <- map2(data.list, c(2008:2016), ~ mutate(.x, year = .y))
combined.data <- bind_rows(data.list)
combined.data
## # A tibble: 8,019 × 6
## ECODE ECODEDES INJTYPE INTENT MECHANISM year
## <chr> <chr> <chr> <chr> <chr> <int>
## 1 <NA> No Matching E-Code Found <NA> <NA> <NA> 2008
## 2 -1 Not Applicable BIU 1 <NA> <NA> <NA> 2008
## 3 -2 Not Known/Not Recorded BIU 2 <NA> <NA> <NA> 2008
## 4 800.0 Railway Collision w/ Rolling Stock - Ra… Blunt Unint… Transpor… 2008
## 5 800.1 Railway Collision w/ Rolling Stock - Ra… Blunt Unint… Transpor… 2008
## 6 800.2 Railway Collision w/ Rolling Stock - Pe… Blunt Unint… Pedestri… 2008
## 7 800.3 Railway Collision w/ Rolling Stock - Pe… Blunt Unint… Pedal cy… 2008
## 8 800.8 Railway Collision w/ Rolling Stock - Ot… Blunt Unint… Transpor… 2008
## 9 800.9 Railway Collision w/ Rolling Stock - Un… Blunt Unint… Transpor… 2008
## 10 801.0 Railway Collision w/ Oth Object - Railw… Blunt Unint… Transpor… 2008
## # ℹ 8,009 more rows
2b) Use data sheet map_func containing patients treated with surgical and non-surgical procedures. The investigator further divided the patients into A, B and C groups based on their post-surgical outcomes. After a period of follow up, they have either censored or died (status). “When” is the column of follow up years.
The investigator would like to know the median follow up time, with
quartile range (Q1 and Q3), and the total number with percentage, by
Treatment, Outcome, and Status. Please try to use split()
function and map_dfr() function to calculate the
statistics.
Final statistical table looks like:
## # A tibble: 90,954 × 5
## PatientID Treatment Outcome Status When
## <chr> <chr> <chr> <dbl> <dbl>
## 1 140Z2314239 Surgical A 0 2.52
## 2 1406872917 Surgical A 0 6.90
## 3 1407140585 Surgical A 0 4.64
## 4 1403943291 Surgical A 0 2.57
## 5 1403900350 Surgical A 0 9.98
## 6 1405380447 Surgical A 0 1.08
## 7 1403329155 Surgical A 0 1.75
## 8 1403940407 Surgical A 0 13.3
## 9 1403961799 Surgical A 0 8.05
## 10 1405842113 Surgical A 0 1.44
## # ℹ 90,944 more rows
# Split the data into subsets based on unique combinations of 'Treatment', 'Outcome', and 'Status'
dat.map.split <- split(dat.map, list(dat.map$Treatment, dat.map$Outcome, dat.map$Status), drop=TRUE) #This creates a list where each element corresponds to a unique combination of these three columns.
# Define the function to compute summary statistics for each subset
stats <- function(df) {
tibble(
Treatment = unique(df$Treatment),
Outcome = unique(df$Outcome),
Status = unique(df$Status),
Median = median(df$When, na.rm = TRUE),
Q1 = quantile(df$When, 0.25, na.rm = TRUE),
Q3 = quantile(df$When, 0.75, na.rm = TRUE),
N = nrow(df),
Proportion = nrow(df) / nrow(dat.map) * 100
)
}
# Apply the 'stats' function to each subset in the data frame and combine the results into a single tibble
stats.tbl <- map_dfr(dat.map.split, stats)
print(stats.tbl)
## # A tibble: 12 × 8
## Treatment Outcome Status Median Q1 Q3 N Proportion
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <int> <dbl>
## 1 Nonsurgical A 0 6.21 3.92 9.00 24485 26.9
## 2 Surgical A 0 5.90 3.38 8.93 4957 5.45
## 3 Nonsurgical B 0 6.17 3.90 8.97 23934 26.3
## 4 Surgical B 0 5.82 3.35 8.85 4853 5.34
## 5 Nonsurgical C 0 6.27 3.96 9.10 25060 27.6
## 6 Surgical C 0 5.94 3.40 8.97 5032 5.53
## 7 Nonsurgical A 1 4.70 2.66 7.39 780 0.858
## 8 Surgical A 1 4.30 2.16 5.70 96 0.106
## 9 Nonsurgical B 1 4.64 2.64 7.28 1331 1.46
## 10 Surgical B 1 4.77 2.43 6.97 200 0.220
## 11 Nonsurgical C 1 5.66 3.68 8.36 205 0.225
## 12 Surgical C 1 5.77 4.13 7.07 21 0.0231
2c) It’s common to access the univariate relationship between multiple predictors and one outcome. In R, there is a data set “iris”. Try use map function to build univariate linear regression models with outcome “Sepal.Length”. There should be 4 individual linear regression models. Could you also present the results by combing each model? Something like this:
data(iris)
# Identify all column names except 'Sepal.Length', as these will be used as predictors.
predictors <- setdiff(names(iris), "Sepal.Length")
predictors
## [1] "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
# Apply linear regression for each predictor separately and store the results
iris.result <- map_dfr(predictors,
~ { # Fit the model
model <- lm(Sepal.Length ~ ., data = iris[, c("Sepal.Length", .x), drop = FALSE])
#Subsets the iris dataset to include only the Sepal.Length column (outcome) and the current predictor (.x).
# broom (Converts the model summary into a tidy data frame format)
broom::tidy(model) %>%
mutate(predictors = .x)
}
) %>%
select(predictors, term, estimate, std.error, statistic, p.value)
iris.result
## # A tibble: 9 × 6
## predictors term estimate std.error statistic p.value
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Sepal.Width (Intercept) 6.53 0.479 13.6 6.47e- 28
## 2 Sepal.Width Sepal.Width -0.223 0.155 -1.44 1.52e- 1
## 3 Petal.Length (Intercept) 4.31 0.0784 54.9 2.43e-100
## 4 Petal.Length Petal.Length 0.409 0.0189 21.6 1.04e- 47
## 5 Petal.Width (Intercept) 4.78 0.0729 65.5 3.34e-111
## 6 Petal.Width Petal.Width 0.889 0.0514 17.3 2.33e- 37
## 7 Species (Intercept) 5.01 0.0728 68.8 1.13e-113
## 8 Species Speciesversicolor 0.93 0.103 9.03 8.77e- 16
## 9 Species Speciesvirginica 1.58 0.103 15.4 2.21e- 32
2d) In some cases we have multiple outcomes and
only one group variable, could you perform the univariate comparisons on
different outcomes?
In the same “iris” data, use “Sepal.Length” as group variable, and the rest are the outcomes. Be aware that some outcomes are continuous and some are categorical.
# Split the outcomes into continuous and categorical
continuous_vars <- c("Sepal.Width", "Petal.Length", "Petal.Width")
categorical_vars <- c("Species")
# Continuous Outcomes: Linear Regression
continuous_results <- map_dfr(continuous_vars, ~ {
lm(as.formula(paste(.x, "~ Sepal.Length")), data = iris) %>%
broom::tidy() %>%
mutate(predictor = .x)
})
# Categorical Outcomes: Logistic Regression (One-vs-All Approach)
categorical_results <- map_dfr(categorical_vars, ~ {
glm(as.formula(paste(.x, "~ Sepal.Length")), data = iris, family = binomial) %>%
broom::tidy() %>%
mutate(predictor = .x)
})
all_results <- bind_rows(continuous_results, categorical_results) %>%
select(predictor,term, estimate, std.error, statistic, p.value)
all_results
## # A tibble: 8 × 6
## predictor term estimate std.error statistic p.value
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Sepal.Width (Intercept) 3.42 0.254 13.5 1.55e-27
## 2 Sepal.Width Sepal.Length -0.0619 0.0430 -1.44 1.52e- 1
## 3 Petal.Length (Intercept) -7.10 0.507 -14.0 6.13e-29
## 4 Petal.Length Sepal.Length 1.86 0.0859 21.6 1.04e-47
## 5 Petal.Width (Intercept) -3.20 0.257 -12.5 8.14e-25
## 6 Petal.Width Sepal.Length 0.753 0.0435 17.3 2.33e-37
## 7 Species (Intercept) -27.8 4.83 -5.76 8.19e- 9
## 8 Species Sepal.Length 5.18 0.893 5.79 6.90e- 9
##### Reference: