Kapitel 43 Meta-Analyse in der Physiotherapie

Meta-Analysen muss man einfach lieben.

An dieser Seite - wie leider am ganzen Skript - wird noch gearbeitet. Die Seite ist noch nicht korrigiert.


to do:

  • Mehr Studien hinzufügen, so dass ein Funnel Plot Sinn macht
  • Funnel Plot (2 Varianten)
  • Check Formeln
library(kableExtra)
library(meta)
library(netmeta)


Eine Meta-Analyse ist eine statistische Zusammenfassung mehrer Studien im Rahmen einer systematischen Literaturübersicht.

Wir werden hier nicht gross über die Voraussetzungen für eine Meta-Analyse reden - dazu gibt es gute Bücher, wie zum Beispiel :

Wichtig ist, dass alle eingeschlossenen Studien zur Forschungsfrage passen - d.h. zum PICO(TS) .

Hier ein Link zu Erklärungen zu PICOTSS

Eine Meta-Analyse reduziert vor allem das Problem der statistischen Präzision, sie kann jedoch nicht direkt den Bias reduzieren. Eine Meta-Analyse kann jedoch helfen, Bias aufzudecken - auch wenn eine gutgemachte Meta-Analyse den Bias nicht beweisen kann, gibt sie gute Hinweise über das Risiko eines möglichen Bias.

43.1 Vorteile einer Meta-Analyse

Die nächste Abbildung zeigt einen Forest Plot mit sieben eingeschlossenen Studien. In jeder Studie wurde die Differenz zwischen den beiden Gruppen für die Lebensqualität und das zugehörige Konfidenzintervall berechnet und graphisch und mit Zahlen dargestellt. Bei keiner der Studien kann die Nullhypothese (dass es keinen Unterschied gibt) verworfen werden (man sagt oft: das ist ein statistisch nicht signifikantes Resultat). Die Meta-Analyse besteht nun aus einem poolen der Resultate, etwas vereinfacht gesagt, aus einem gewichteten Mittelwert der Resultate. Studien mit einem schmäleren Konfidenzintervall erhalten mehr Gewicht. Der Rhombus oder Diamant unten zeigt den gepoolten Effekt mit dem 95% Konfidenzintervall. Das Konfidenzintervall berührt die Nullhypothese (hier wäre die Nullhypothese, dass die Differenz in der Population 0 ist) nicht, deswegen verwerfen wir hier die Nullhypothese. Der Gewinn durch die Meta-Analyse ist also, dass wir mehr statistische Power haben.

Forest Plot für die Lebensqualität gemessen mit dem PDQ-39. Die rote gestrichelte Linie stellt die gewichtete mittlere Differenz der eingeschlossenen Studien dar. PDQ-39, Parkinson’s Disease Rating Scale-39; QoL, Lebensqualität.Aus: Elena, P., Demetris, S., Christina, M., & Marios, P. (2021). Differences Between Exergaming Rehabilitation and Conventional Physiotherapy on Quality of Life in Parkinson’s Disease: A Systematic Review and Meta-Analysis. Frontiers in Neurology, 1147.https://doi.org/10.3389/fneur.2021.683385

Im nächsten Beispiel sehen wir einen Forest Plot für den Effekt auf die Gehgeschwindigkeit. Die horizontale Mitte des roten Diamantes zeigt den geschätzten Effekt an, die Schenkel des Rhombuses entsprechen dem 95% Konfidenzintervall. In diesem Forest Plot sehen wir auch eine deutliche Heterogenität, das heisst, es gibt mehr Unterschiede zwischen den Studien in den Effekten als durch den Zufall zu erwarten wäre. Wir sehen dass einerseits mit dem \(\tau ^{2}\) und dem \(I^{2}\).Dazu später mehr.

Forest Plot aus: Booth, A. T., Buizer, A. I., Meyns, P., Oude Lansink, I. L., Steenbrink, F., & van der Krogt, M. M. (2018). The efficacy of functional gait training in children and young adults with cerebral palsy: a systematic review and meta‐analysis. Developmental Medicine & Child Neurology, 60(9), 866-883. Die Wirkung von Gehtraining im Vergleich zu Standard-Physiotherapie und Krafttraining auf die Gehgeschwindigkeit. Die Grösse der Rechtecke in der Mitte der Konfidenzintervalle entsprechen der Gewichtung der Studien; die Farbe zeigt den Evidenzgrad der Studie an (grün, II; blau, III)

Wir können auch Untergruppen bilden. Im nächsten Beispiel, übrigens von unseren Kolleg:innen Katia, Rahel und Martin, sehen wir Untergruppen für verschieden Variaten der Peyton Unterrichtsmethode.

Forst Plot aus: Giacomino, K., Caliesch, R., & Sattelmayer, K. M. (2020). The effectiveness of the Peyton’s 4-step teaching approach on skill acquisition of procedures in health professions education: A systematic review and meta-analysis with integrated meta-regression. PeerJ, 8, e10129. Forest Plot Leistung - Peytons 4-Schritt-Unterricht im Vergleich zum Standardunterricht bei den Tests nach dem Unterricht.Pey, Peytons Unterricht; St, Standardunterricht; PeerPey, Peer Peytons Unterricht; PeerSt, Peer Standardunterricht; PeerBpsl, Peer Best Practice Skills Lab; MPey, Media supported Peyton. NB. Gradl-Dietsch et al. (2018) und Gradl-Dietsch et al. (2016) werden als zwei Stichproben dargestellt, da die Daten für Frauen und Männer getrennt analysiert wurden (a: Frauen, b: Männer). Die Daten von Herrmann-Werner et al. (2013) werden als zwei Stichproben dargestellt (a: Teilnehmer mit einem Follow-up von 3 Monaten, b: Teilnehmer mit einem Follow-up von 6 Monaten).

Das nächste Beispiel zeigt Untergruppen nach Tests geordnet.

Forest Plot aus: Sattelmayer, M., Elsig, S., Hilfiker, R. et al. A systematic review and meta-analysis of selected motor learning principles in physiotherapy and medical education. BMC Med Educ 16, 15 (2016). https://doi.org/10.1186/s12909-016-0538-z Der Forest Plot bezieht sich auf das Ergebnis des Leistungstests. Lizenz: (http://creativecommons.org/licenses/by/4.0/)

43.2 Datenextraktion

Excel ist nicht das beste Werkzeug für die Datenextraktion. Fehler geschehen bei der Eingabe in Excel schnell und bleiben oft unentdeckt. Für kleinere Reviews ist Excel jedoch sicher eine pragmatische Wahl: Jeder kennt Excel, jeder hat Excel auf seinem Computer (und sonst eine Gratisversion wie Google Forms). Für grössere Projekte - d.h. Projekte wo mehrere Personen zusammenarbeiten und sehr viele Studien erwartet werden, lohnt es sich jedoch, ein anderes Tool zu benutzen. Wir benutzen zum Beispiel REDCap für grössere Reviews. Nachteil: Sehr viel Vorbereitungszeit. Vorteil: Sehr gute Kontrolle über die Daten, Fehler werden vermieden oder eher entdeckt.

Doch für die Bachelorarbeit ist Excel meistens das Werkzeug der Wahl.

Vereinfacht gesagt gibt es zwei Varianten, wie man Daten einer Meta-Analyse eintragen kann: im Long und im Wide Format.

43.2.1 Long und Wide Format

Wir schauen uns zuerst das Long Format an. In vielen Fällen ist es das einfachere Format um Daten einzugeben.

Im Long Format hat jedes Outcome, jeder Zeitpunkt und jeder Interventionsarm eine Zeile.

study_id=rep(c("Zgraggen 2010", "Albright 2012", "Chevalier 2009"), each=2)
intervention=rep(c("Exercise", "Usual Care"), times=3)
outcome=rep("Pain", times=6)
timepoint_week=rep(12, times=6)
mean=c(5.3,4.7,3.4,2.7,5.6,7.3)
sd=c(2.1,2.3,1.6,1.8,3.2,3.1)
n=c(12,12,29,28,42,41)
data_long=data.frame(study_id, intervention, outcome, timepoint_week, mean, sd, n)

study_id=rep(c("Zgraggen 2010", "Albright 2012", "Chevalier 2009"), each=2)
intervention=rep(c("Exercise", "Usual Care"), times=3)
outcome=rep("Disability", times=6)
timepoint_week=rep(12, times=6)
mean=c(4.2,4.1,4.2,3.9,4.3,5.3)
sd=c(2.9,2.2,1.0,1.3,3.4,3.1)
n=c(12,12,29,28,42,41)


data_long2=data.frame(study_id, intervention, outcome, timepoint_week, mean, sd, n)

data_long<-bind_rows(data_long, data_long2)

data_long<-data_long %>% arrange(study_id)

kableExtra::kable(data_long, caption="Eine vereinfachte Extraktionstabelle im Long Format") %>% kable_styling("striped", full_width = F)%>%
    scroll_box(width = "100%")
Table 22.1: Eine vereinfachte Extraktionstabelle im Long Format
study_id intervention outcome timepoint_week mean sd n
Albright 2012 Exercise Pain 12 3.4 1.6 29
Albright 2012 Usual Care Pain 12 2.7 1.8 28
Albright 2012 Exercise Disability 12 4.2 1.0 29
Albright 2012 Usual Care Disability 12 3.9 1.3 28
Chevalier 2009 Exercise Pain 12 5.6 3.2 42
Chevalier 2009 Usual Care Pain 12 7.3 3.1 41
Chevalier 2009 Exercise Disability 12 4.3 3.4 42
Chevalier 2009 Usual Care Disability 12 5.3 3.1 41
Zgraggen 2010 Exercise Pain 12 5.3 2.1 12
Zgraggen 2010 Usual Care Pain 12 4.7 2.3 12
Zgraggen 2010 Exercise Disability 12 4.2 2.9 12
Zgraggen 2010 Usual Care Disability 12 4.1 2.2 12

Im Wide Format würde dies so aussehen: (Wobei diese Version hier eigentlich eine Mischung aus Wide und Long ist, da immer noch für jedes Outcome eine neue Zeile benutzt wird - also hat hier jede Studie zwei Zeilen. In einem reinen Wide Format wären ale Outcomes auf einer Zeile, d.h. pro Studie gäbe es nur eine Zeile.)

data_wide<-data_long %>% 
  pivot_wider(id_cols=c(study_id, outcome, timepoint_week),
                        names_from=intervention, 
              values_from=c(mean, sd, n))
data_wide<-janitor::clean_names(data_wide, case='none')
kableExtra::kable(data_wide, caption="Vereinfachte Datenextraktionstabelle im Wide Format.") %>% kable_styling("striped", full_width = F)%>%
    scroll_box(width = "100%")
Table 43.1: Vereinfachte Datenextraktionstabelle im Wide Format.
study_id outcome timepoint_week mean_Exercise mean_Usual_Care sd_Exercise sd_Usual_Care n_Exercise n_Usual_Care
Albright 2012 Pain 12 3.4 2.7 1.6 1.8 29 28
Albright 2012 Disability 12 4.2 3.9 1.0 1.3 29 28
Chevalier 2009 Pain 12 5.6 7.3 3.2 3.1 42 41
Chevalier 2009 Disability 12 4.3 5.3 3.4 3.1 42 41
Zgraggen 2010 Pain 12 5.3 4.7 2.1 2.3 12 12
Zgraggen 2010 Disability 12 4.2 4.1 2.9 2.2 12 12

Hier noch das komplett Wide Format mit nur einer Zeile pro Studie:

data_wide_wide<-data_wide %>% 
  pivot_wider(id_cols=c(study_id, timepoint_week), 
              names_from=c(outcome), 
              values_from=c(mean_Exercise,  mean_Usual_Care, sd_Exercise,sd_Usual_Care,  n_Exercise,  n_Usual_Care))

kableExtra::kable(data_wide_wide, caption="Vereinfachte Datenextraktionstabelle im wirklich breiten Format.") %>% kable_styling("striped", full_width = F)%>%
    scroll_box(width = "100%")
Table 43.2: Vereinfachte Datenextraktionstabelle im wirklich breiten Format.
study_id timepoint_week mean_Exercise_Pain mean_Exercise_Disability mean_Usual_Care_Pain mean_Usual_Care_Disability sd_Exercise_Pain sd_Exercise_Disability sd_Usual_Care_Pain sd_Usual_Care_Disability n_Exercise_Pain n_Exercise_Disability n_Usual_Care_Pain n_Usual_Care_Disability
Albright 2012 12 3.4 4.2 2.7 3.9 1.6 1.0 1.8 1.3 29 29 28 28
Chevalier 2009 12 5.6 4.3 7.3 5.3 3.2 3.4 3.1 3.1 42 42 41 41
Zgraggen 2010 12 5.3 4.2 4.7 4.1 2.1 2.9 2.3 2.2 12 12 12 12

Doch nun zurück zum Long Format. Wir lesen hier ein paar fiktive Daten zu fiktiven Studien ein:

data_long<-rio::import("http://www.pt-wissen.ch/Statistik_BSc_Physiotherapie_Leukerbad/beispiel_example_data_entry_meta_analysis_long.xlsx")

data_long<-data_long %>% 
  mutate(outcome=stringr::str_to_sentence(outcome)) %>% 
  group_by(study_id, outcome, timepoint_weeks) %>% 
  mutate(intervention_arm_index=row_number()) %>% 
  ungroup() %>% 
  group_by(study_id) %>% 
  mutate(study_nr=cur_group_id()) %>% 
  dplyr::select(study_nr,intervention_arm_index, everything()) %>% 
  arrange(study_nr)

nr<-max(data_long$study_nr)

DT::datatable(data_long, filter='top', options=list(pageLength=10, scrollY = "800"), fillContainer = TRUE) %>%
    formatStyle(
      'study_nr',
  target = 'row',
  backgroundColor = styleEqual(data_long$study_nr, rainbow(length(data_long$study_nr),0.2)))

Wir benötigen mindestens folgende Variablen: eine ID für jede Studie, die Bezeichnung der Intervention und der Kontrollgruppe, sowie für jede Gruppe den Mittelwert, die Standardabweichung, die Anzahl Personen in der Analyse, sowie den Zeitpunkt, wann dieses Outcom erhoben wurde. Wir können entweder die Follow-up Daten eingeben, oder die Change Wert (Follow-up minus Baseline). Die Baseline-Werte benötigen wird nicht, ausser wir möchten eine zusätzliche Darstellung der Within-Group Veränderung darstellen (siehe Graphik weiter unten).

43.2.2 Fehlende Mittelwerte oder fehlende Standardabweichungen.

In unserem (fiktiven) Beispiel fanden wir nicht für alle Studien den Mittelwert und SD, deswegen gibt es Studien, wo der Median, die 25. und die 75. Perzentile angegeben wurde. Wir können dem Befehl metacont dann sagen, mit welcher Methode er sd aus median und iqr etc. schätzen soll (method.sd..

Manchmal fehlt die Standardabweichung. Wir können diese oft von anderen Statistiken berechnen oder schätzen. Eine Übersicht der Methoden finden Sie hier (Tabelle mit Methoden zur Ersetzung von SD aus Median , IQR, oder Range) und hier: Formeln für SD aus Standard Fehler, Konfidenzintervallen, t-Werten und P-Werten.

Mit dem Paket meta haben wir die Möglichkeiten, aus den vorhandenen Informationen automatisch die fehlenden Werte zu ersetzen. Wir geben einfach das in die Excel-Tabelle ein, was wir aus dem Artikel extrahieren können. Die entsprechenden meta-Befehle werden diese Informationen benutzen.



* In der Zgraggen 2011 Studie fehlt der Mean und die SD. Median und 2. und 3. Quartil konten extrahiert werden und werden benutzt.

  • In der Schmid 2006 Studie fehlt die SD, im Artikel wurde nur der Standardfehler (se) angegeben. Dies kann nicht automatisch ersetzt werden mit dem metacont Befehl. Wir können dies jedoch ganz einfach selber rechnen: \[SD = SE * \sqrt{N}\]
data_long<-data_long %>% 
  mutate(sd=case_when(
    is.na(sd)&!is.na(se)~se*n^0.5,
    TRUE~sd))
  • In der Zeneggen 2019 Studie haben wir keine SD, wir konnten jedoch die Konfidenzintervall extrahieren und nun können wir daraus die Standardabweichung berechnen.
data_long<-data_long %>% 
  mutate(sd=case_when(
    is.na(sd)&is.na(se)&!is.na(lower)~(upper-lower)/2*abs(qt(0.025,n-1)),
    TRUE~sd))
  • In der Inderbitzin 2014 Studie fehlt die Standardabweichung, der SE und das 95% Konfidentintervall auch, aber wir fanden einen p-Wert für die Werte jeder Gruppe.
data_long<-data_long %>% 
  mutate(sd=case_when(
    is.na(sd)&is.na(se)&is.na(lower)&!is.na(pvalue_within)~mean*abs(qt(0.5*pvalue_within, n-1)),
    TRUE~sd))
  • In der Burn 1996 Studie fehlt die Standardabweichung auch. SE und 95% Konfidenzintervalle fanden wir auch nicht, dafür einen p-Wert für den Zwischengruppenvergleich. Daraus können wir die SD für beide Gruppen berechnen (die aber damit für beide Gruppen gleich geschätzt werden). Diese Berechnung machen wir jedoch erst, nachdem wir die Daten umgeordnet haben, da es sonst schwieriger ist, die Berechnungen für Studien mit mehr als zwei Behandlungsgruppen zu machen.
df<-data_long %>% 
  arrange(intervention_arm_index) %>% 
  dplyr::select(study_id, intervention_arm_index, treat, outcome, timepoint_weeks, mean,n,  contains("pvalue_between")) %>% 
  group_by(study_id, outcome, timepoint_weeks) 


df2<-df %>% 
  dplyr::select(-contains("pvalue_between"))
  
df_temp<-full_join(df, df2, by=c("study_id", "outcome", "timepoint_weeks"))

df_temp<-df_temp %>% 
    filter(treat.x!=treat.y) 

df_temp<-df_temp %>% 
  select(-(contains("pvalue_between")&ends_with(".y"))) # not needed if this is rund before: df2<-df %>% dplyr::select(-contains("pvalue_between"))



names(df_temp)<-stringr::str_replace(names(df_temp), "\\.x", "_gr1")
names(df_temp)<-stringr::str_replace(names(df_temp), "\\.y", "_gr2")

df_temp<-df_temp %>% 
  mutate(comparison=paste(treat_gr1, treat_gr2, sep="-")) %>% 
  dplyr::select(study_id, contains("intervention_arm_index"), comparison,contains("treat"), everything()) %>%
  group_by(study_id) %>% 
  fill(contains("pvalue"), .direction="updown")


df_temp<-df_temp %>% 
  group_by(study_id, outcome, timepoint_weeks) %>% 
  mutate(pvalue_between = case_when(
    intervention_arm_index_gr1==1 & intervention_arm_index_gr2==2~pvalue_between_gr1_gr2, 
    intervention_arm_index_gr1==1 & intervention_arm_index_gr2==3~pvalue_between_gr1_gr3, 
    intervention_arm_index_gr1==1 & intervention_arm_index_gr2==4~pvalue_between_gr1_gr4, 
    intervention_arm_index_gr1==2 & intervention_arm_index_gr2==3~pvalue_between_gr2_gr3, 
    intervention_arm_index_gr1==2 & intervention_arm_index_gr2==4~pvalue_between_gr2_gr4, 
    intervention_arm_index_gr1==3 & intervention_arm_index_gr2==4~pvalue_between_gr3_gr4)) %>% 
  dplyr::select(study_id, outcome, timepoint_weeks, contains("treat"), pvalue_between, everything()) %>% 
  fill(pvalue_between, .direction = "updown")

df_temp<-df_temp %>% 
  mutate(n=n_gr1+n_gr2) %>% 
  mutate(mean_difference=(mean_gr1-mean_gr2)) %>% 
  mutate(sd_estimated=abs(mean_difference*qt(0.5*pvalue_between, n-2)))


df_to_merge<-df_temp %>% 
  select(study_id, outcome, timepoint_weeks, treat_gr1, sd_estimated) %>% 
  rename(treat=treat_gr1) %>% 
  filter(!is.na(sd_estimated))

Bei Studien mit mehreren Interventionsgruppen haben wir mit dieser Methode der Schätzung der SD nun für jede Intervention mehrere SDs. Im Beispiel der Studie Jossen 2014 haben wir vier Behandlungsgruppen und somit drei Vergleiche für jede Behandlungsgruppe. Da nun jeder Vergleich einen anderen p-Wert hat, haben wir somit auch drei Standardabweichungen, obschon es eigentlich ja nur eine Standardabweichung gibt. Wir nehmen deshalb die gepoolte Standardabweichung der drei Standardabweichungen.

df_to_merge<-df_to_merge %>% 
  group_by(study_id, outcome, timepoint_weeks) %>% 
  mutate(variance_estimated=sd_estimated^2) %>% 
    mutate(sd_estimated_pooled=mean(variance_estimated, na.rm=TRUE)^0.5) %>% 
  dplyr::select(-sd_estimated, -variance_estimated) %>% 
  group_by(study_id, outcome, timepoint_weeks, treat) %>% 
  mutate(index_sd=row_number()) %>% 
  filter(index_sd==1) %>% 
  dplyr::select(-index_sd)

Nun können wir diese geschätzte SD pro Interventionsgruppe wieder mit den Originaldaten zusammenfügen.

data_long<-left_join(data_long, df_to_merge, by=c("study_id", "treat", "outcome", "timepoint_weeks")) 

data_long<-data_long%>% 
  mutate(sd=case_when(
    is.na(sd)&!is.na(sd_estimated_pooled)~sd_estimated_pooled, 
    TRUE~sd))

Im nächsten Schritt wählen wir das Outcome und den Zeitpunkt aus, die wir analysieren wollen und formatieren die Daten in das Pairwise-Format um. Das Pairwise-Format ist im Prinzip eine Art Wide Format. Noch etwas: Eventuell müssen wir auch noch ein paar Daten umdrehen, so damit alle Werte desselben Outcomes in die gleiche Richtung gehen (zum Beispiel, dass hohe Werte schlechte Outcomes bedeuten).

Wir können den Befehl pairwise des Pakets netmeta nutzen.

  1. Auswählen des Outcomes und des Zeitpunktes
# https://rdrr.io/cran/netmeta/man/pairwise.html

pain_t1 <-data_long %>% 
  filter(outcome=="Pain" & timepoint_weeks==3)
  1. Setzen eines Minuszeichens vor die Means, die wir umpolen müssen. Was müssen wir umpolen: Bei Schmerzskalen sind normalerweise die Skalen so gepolt, dass hohe Werte hoher Schmerz bedeuten. Es gibt jedoch Skalen, bei denen hohe Werte wenig Schmerz bedeutet. Zum Beispiel die Schmerzskala des Hos oder Kos. Dort müssen wir ein Minuszeichen vor die Mittelwerte (means) setzen, damit auch da hohe Werte Schmerz bedeuten.
# Wir müssen noch die Richtung der means ändern, falls hohe Werte nicht schlechte Werte sind. 

pain_t1<-pain_t1 %>%
  mutate(mean_unchanged=mean) %>% 
  mutate(Need_Change_Direction_To_Be_Higher_Values_Bad_Values=case_when(
    is.na(Need_Change_Direction_To_Be_Higher_Values_Bad_Values)~1, 
    TRUE~Need_Change_Direction_To_Be_Higher_Values_Bad_Values)) %>% 
  mutate(mean=ifelse(Need_Change_Direction_To_Be_Higher_Values_Bad_Values==1, mean*-1,mean)) %>% 
  select(1:6, mean_unchanged, everything())

Jetzt nutzen wir den pairwise Befehl aus dem netmeta Paket um die Daten in das wide Format zu drehen.

dataPairwise<-pairwise(
  n=n, 
  sd=sd, 
  mean=mean,
  treat=treat,
  data = pain_t1,
  studlab=study_id,
  sm="SMD")

dataPairwise<-dataPairwise %>% 
  mutate(comparison=paste(treat1, treat2, sep="-"))

So sehen die Daten im wide Format aus.

DT::datatable(dataPairwise)

43.3 Meta-Analyse mit den Wide Daten

meta_pair_pain_very.short<-metacont(
  n.e=n1,
  mean.e=mean1,
  sd.e=sd1,
  n.c=n2,
  mean.c=mean2,
  median.e=median1, 
  median.c=median2,
  sd.c=sd2,
  q1.e=q11, 
  q1.c=q12,
  q3.e=q31, 
  q3.c=q32,  
  method.sd='Shi',
  studlab=studlab,
  subgroup=comparison,
  data = dataPairwise,
  subset = NULL,
  exclude = NULL,
  sm = "SMD",
  fixed = FALSE,
  hakn = gs("hakn"),
  method.tau = "SJ",
  title = gs("title"),
  complab = gs("complab"),
  outclab = "",
  overall=FALSE)

Die Resultate werden im Objekt meta_pair_pain_very.short gespeichert. Wir können diese einfach mit meta_pair_pain_very.short + Enter anschauen, oder wir können auch auf gespeicherte Unterobjekte zurückgreifen, zum Beispiel mit meta_pair_pain_very.short$TE. Im nächsten Abschnitt benutzen wir das Objekt meta_pair_pain_very.short um damit den Forest Plot zu erstellen.

43.4 Forest Plot mit den extrahierten und ersetzten (berechneten und geschätzten) Daten.

Schauen Sie sich auch diese Variante für das Speichern an. Bei dieser Variante müssen Sie nur einmal pro Rmarkdown angeben, wie Sie speichern wollen.

Um den Forest-Plot zu speichern, gibt es verschiedene Möglichkeiten. in der folgenden Variante erstellen wir zuerst den Plot und speichern in dann als PDF und als png.

# Step 1: Create the figure
plot_pairwise_forest<-meta::forest(meta_pair_pain_very.short, 
  prediction=TRUE,
  prediction.subgroup=TRUE,
  label.e = "Intervention",
  label.c = "Control",
  label.left = "Favours Intervention",
  label.right ="Favours Control", 
  col.diamond.random="#6BEB46", 
  col.square="#E40FEB", 
  test.overall=TRUE, 
   xlim=c(-4,4), 
  at=seq(-4,4,by=1),
  leftcols=c("studlab", "treat1", "treat2", "mean1", "sd1", "n1","mean2", "sd2", "n2" )) # https://bookdown.org/MathiasHarrer/Doing_Meta_Analysis_in_R/generating-a-forest-plot.html
Forest Plots der verschiedenen Vergleiche und den Effekten auf den Schmerz. Die roten horizontalen Balken geben das Prediction Interval (Vorhersage Intervall) an. Das 95%-Vorhersageintervall ist das Intervall, das die wahre Effektgröße für 95% aller Populationen in dieser Grundgesamtheit enthält. Das Prediction Intervall berücksichtig die Heterogenität stärker als das Konfidenzintervall. Das 95% Konfidenzinterval würde bei unendlichen vielen oder unendlich grossen Studien auf 0 schrumpfen. Das Prediction Intervall würde nicht so stark schrumpfen - so lange die Effekte zwischen den Studien variieren.

Abbildung 11.1: Forest Plots der verschiedenen Vergleiche und den Effekten auf den Schmerz. Die roten horizontalen Balken geben das Prediction Interval (Vorhersage Intervall) an. Das 95%-Vorhersageintervall ist das Intervall, das die wahre Effektgröße für 95% aller Populationen in dieser Grundgesamtheit enthält. Das Prediction Intervall berücksichtig die Heterogenität stärker als das Konfidenzintervall. Das 95% Konfidenzinterval würde bei unendlichen vielen oder unendlich grossen Studien auf 0 schrumpfen. Das Prediction Intervall würde nicht so stark schrumpfen - so lange die Effekte zwischen den Studien variieren.

plot_pairwise_forest <- recordPlot()

print(plot_pairwise_forest) # Step2 Plot the figure 
devEMF::emf('example_forest_plot_pain.emf', width=33, height=23) # speichert es als enhanced windows metafile
invisible(dev.off()) # Step 3: Run dev.off() to create the file!


print(plot_pairwise_forest)
png('example_forest_plot_pain.png', width=33, height=23, res=300, units="cm") # speichert es als png
invisible(dev.off())


# Wenn Sie es als PDF speichern möchten, können Sie folgende Zeile nehmen:
pdf('example_forest_plot_pain.pdf', width=12, height=10)
print(plot_pairwise_forest)
dev.off()
## png 
##   2
# Let's make the forest plot a little bit nicer: 
# have a look for the meta::forest command on the web to find the options.

Je nach Computer können Sie jetzt das PDF (bei Mac) oder das .png File in Word einfügen. Wichtig: Nicht mit Copy-Paste einfügen, sondern über “Einfügen”–>“Bild”.

43.5 Tabelle mit Formeln zu den Methoden um SD zu schätzen / berechnen.

Tabelle Formeln SD Formeln für SD aus Standard Fehler, Konfidenzintervallen, t-Werten und P-Werten.

Übrigens: Hier ein Artikel, der den Unterschied einer Systematic Review / Meta-Analyse zu einer Leitlinie (Guideline) aufzeigt hier klicken für das PDF.

43.6 Hilfe zum Leistungsnachweis

Wir Laden ein Excel-File, in dem wir auch noch weitere Studienergebnisse einführen könnten. Es ist schon im Wide Format.

Sie können diese Datei auch herunterladen (hier klicken), und dann weitere Studien einfügen. Danach speichern Sie die Datei in ihrem Projektordner.

data<-rio::import("Daten_Meta-Analyse_Pc_vs_Mac_2022.xlsx")
DT::datatable(data,filter='top', options=list(pageLength=10, scrollY = "800"), fillContainer = TRUE) %>%
    formatStyle(
      'Study',
  target = 'row',
  backgroundColor = styleEqual(data_long$study_nr, rainbow(length(data_long$study_nr),0.2)))

Hier ein Lösungsvorschlag für den Forest-Plot - den könnte man natürlich noch viel schöner machen .

forForestPlot<-metacont(
    n.e = N_Mac,
    mean.e = Mean_Mac,
    sd.e = SD_Mac,
    n.c = N_PC,
    mean.c= Mean_PC,
    sd.c= SD_PC,
    studlab=Study,
    data = data,
    subset = NULL,
    exclude = NULL,
    sm = "SMD", # da wir unterschiedliche Skalen haben in den Studien, d.h. alle messen das gleiche Konstrukt, jedoch nicht mit der gleichen Skala und demselben Range, müssen wir Standardized Mean Difference wählen ("SMD")
    method.smd = "Hedges", # Das müssten wir gar nicht angeben, da dies die Standardeinstellung ist. 
    sd.glass = gs("sd.glass"), # 
    exact.smd = gs("exact.smd"),
    level = gs("level"),
    fixed = FALSE,
    random = TRUE,
    hakn = TRUE,
    adhoc.hakn = gs("adhoc.hakn"),
    method.tau = "SJ",
    prediction = TRUE,
    level.predict = gs("level.predict"),
    method.bias = gs("method.bias"),
    backtransf = gs("backtransf"),
    title = gs("title"),
    complab = gs("complab"),
    outclab = "",
    label.e = "Mac",
    label.c = "PC",
    label.left = "Favours PC",
    label.right = "Favours Mac")

43.6.1 Hier die Ausgabe als Graphik in unterschiedlichen Formaten:

Graphik:

Ausgabe als PDF

  forest(forForestPlot, 
         at=c( -0.8, -0.5, 0, 0.2, 0.5, 0.8, 1, 1.5, 2),
         col.study="antiquewhite4" , 
         col.square="chartreuse",
         col.diamond="darkmagenta",
         digits=2, 
         digits.mean=2, 
         digits.sd=2)  
Forest Plot. SMD = Standardised Mean Difference.

Abbildung 11.3: Forest Plot. SMD = Standardised Mean Difference.

plot_pairwise_forest <- recordPlot()

pdf(file="Forest_Plot_PC_vs_Mac.pdf", height=6, width=12)
print(plot_pairwise_forest)
dev.off()
## png 
##   2

Ausgabe als windows metafile.

  forest(forForestPlot, 
         at=c( -0.8, -0.5, 0, 0.2, 0.5, 0.8, 1, 1.5, 2),
         col.study="antiquewhite4" , 
         col.square="chartreuse",
         col.diamond="darkmagenta",
         digits=2, 
         digits.mean=2, 
         digits.sd=2) 
Forest Plot. SMD = Standardised Mean Difference.

Abbildung 11.4: Forest Plot. SMD = Standardised Mean Difference.

plot_pairwise_forest <- recordPlot()
win.metafile(file="Forest_Plot_PC_vs_Mac.wmf", height=10, width=12 )
print(plot_pairwise_forest)

dev.off()
## png 
##   2

Als PDF, in einem anderen Design.

pdf(file="Forest_Plot_PC_vs_Mac_look_revman.pdf", height=6, width=12)
  forest(forForestPlot, layout = "RevMan5")
  dev.off()
## png 
##   2

Als PDF, aber nur mit den random effects (d.h. ohne fixed effect Resultate).

  forest(forForestPlot, 
         at=c( -0.8, -0.5, 0, 0.2, 0.5, 0.8, 1, 1.5, 2),
         col.study="antiquewhite4" , 
         col.square="chartreuse", 
         comb.fixed=FALSE,
         col.diamond="darkmagenta", 
         digits=2, 
         digits.mean=2, 
         digits.sd=2) 
Forest Plot. SMD = Standardised Mean Difference.

Abbildung 11.5: Forest Plot. SMD = Standardised Mean Difference.

plot_pairwise_forest <- recordPlot()

pdf(file="Forest_Plot_PC_vs_Mac_nur_random.pdf", height=6, width=12)
print(plot_pairwise_forest)
dev.off()
## png 
##   2

43.6.2 Falls Sie lieber im Long-Format Daten eingeben möchten.

data<-rio::import("Daten_Meta-Analyse_Pc_vs_Mac_2022_long.xlsx")
head(data)
##            Study Jahr Mean   SD  N Computer
## 1      Bern 2013 2013 8.00 2.06  9      Mac
## 2      Bern 2014 2014 7.35 2.07  8      Mac
## 3 Leukerbad 2012 2021 8.36 1.96 11      Mac
## 4     Basel 2014 2014 9.00 0.82  4      Mac
## 5      Sion 2012 2012 9.67 0.65 12      Mac
## 6      Sion 2014 2014 9.22 0.82  9      Mac

Sie können diese Datei auch herunterladen (hier klicken), und dann weitere Studien einfügen. Danach speichern Sie die Datei in ihrem Projektordner.

Da wir die Daten jetzt im Long-Format haben, müssen wir zuerst wieder die sogenannten pairwise Daten erstellen.

library(dplyr)
dataPairwise<-netmeta::pairwise(
  n=N, 
  sd=SD, 
  mean=Mean,
  treat=Computer,
  data = data,
  studlab=Study,
  sm="SMD")

dataPairwise<-dataPairwise %>% 
  mutate(comparison=paste(treat1, treat2, sep="-"))

Die für die Meta-Analyse benötigten Daten sind nun im Data Frame dataPairwise gespeichert.

DT::datatable(dataPairwise, filter='top', options=list(pageLength=10, scrollY = "800"), fillContainer = TRUE) %>%
    formatStyle(
      'studlab',
  target = 'row',
  backgroundColor = styleEqual(dataPairwise$studlab, rainbow(length(dataPairwise$studlab),0.2)))

Mit den dataPairwise können wir nun wieder die Meta-Analyse durchführen und im Objekt forForestPlot speichern. Wir müssen einfach die n.e, mean.e,sd.d, sowohl n.c, mean.c und sd.c anpassen.

forForestPlot<-metacont(
    n.e = n1,
    mean.e = mean1,
    sd.e = sd1,
    n.c = n2,
    mean.c= mean2,
    sd.c= sd2,
    studlab=Study,
    data = dataPairwise,
    subset = NULL,
    exclude = NULL,
    sm = "SMD", # da wir unterschiedliche Skalen haben in den Studien, d.h. alle messen das gleiche Konstrukt, jedoch nicht mit der gleichen Skala und demselben Range, müssen wir Standardized Mean Difference wählen ("SMD")
    method.smd = "Hedges", # Das müssten wir gar nicht angeben, da dies die Standardeinstellung ist. 
    sd.glass = gs("sd.glass"), # 
    exact.smd = gs("exact.smd"),
    level = gs("level"),
    fixed = FALSE,
    random = TRUE,
    hakn = TRUE,
    adhoc.hakn = gs("adhoc.hakn"),
    method.tau = "SJ",
    prediction = TRUE,
    level.predict = gs("level.predict"),
    method.bias = gs("method.bias"),
    backtransf = gs("backtransf"),
    title = gs("title"),
    complab = gs("complab"),
    outclab = "",
    label.e = "Mac",
    label.c = "PC",
    label.left = "Favours PC",
    label.right = "Favours Mac")

Jetzt können wir den Forest Plot erstellen und speichern.

  forest(forForestPlot, 
         at=c( -0.8, -0.5, 0, 0.2, 0.5, 0.8, 1, 1.5, 2),
         col.study="antiquewhite4" , 
         col.square="chartreuse", 
         comb.fixed=FALSE,
         col.diamond="darkmagenta", 
         digits=2, 
         digits.mean=2, 
         digits.sd=2) 
Forest Plot. SMD = Standardised Mean Difference.

Abbildung 38.6: Forest Plot. SMD = Standardised Mean Difference.

plot_pairwise_forest <- recordPlot()

pdf(file="Forest_Plot_PC_vs_Mac_nur_random.pdf", height=6, width=12)
print(plot_pairwise_forest)
dev.off()
## png 
##   2

Wir lieben Meta-Analysen, aber wir lieben es noch mehr, wenn das Kapitel endlich zu Ende ist…Here we are…