Kapitel 58 Wide oder Long so lang wie breit

Wir lieben weite Landschaften.

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows

Dies ist eine sehr schwierige Übung; das Umformen von Daten macht mich in R wahnsinnig. Tun Sie dies nicht, wenn Sie gestresst sind.

Zuerst simulieren wir ein paar Daten

library(kableExtra)
id<-1:5
    pain_t1<-c(rnorm(5,5,2))
    pain_t2<-c(rnorm(5,5.2,2.2))
    pain_t3<-c(rnorm(5,6,2)) 
    
    df_pain_wide<-cbind.data.frame(id, pain_t1, pain_t2, pain_t3)
  kbl(df_pain_wide) %>% kable_styling()
id pain_t1 pain_t2 pain_t3
1 4.477547 0.6891036 5.502578
2 5.778489 4.1823753 3.960967
3 3.714936 7.5441658 1.806426
4 1.100044 4.0373206 2.632779
5 4.646760 6.1326351 4.034842
library(tidyr)
    df_pain_long<-df_pain_wide %>% 
      pivot_longer(
        cols= 2:4, 
        names_to = "timepoint",
        names_prefix = "pain_t",
        values_to="pain"
      )
    
    kbl(df_pain_long) %>% kable_styling()
id timepoint pain
1 1 4.4775467
1 2 0.6891036
1 3 5.5025783
2 1 5.7784891
2 2 4.1823753
2 3 3.9609670
3 1 3.7149358
3 2 7.5441658
3 3 1.8064256
4 1 1.1000442
4 2 4.0373206
4 3 2.6327794
5 1 4.6467597
5 2 6.1326351
5 3 4.0348420

Um zu verstehen, was der Code macht, schauen Sie sich an, was passiert, wenn wir kein names_prefix setzen:

    df_pain_long<-df_pain_wide %>% 
      pivot_longer(
        cols= 2:4, 
        names_to = "timepoint",
        values_to="pain"
      )
    kbl(df_pain_long) %>% kable_styling()
id timepoint pain
1 pain_t1 4.4775467
1 pain_t2 0.6891036
1 pain_t3 5.5025783
2 pain_t1 5.7784891
2 pain_t2 4.1823753
2 pain_t3 3.9609670
3 pain_t1 3.7149358
3 pain_t2 7.5441658
3 pain_t3 1.8064256
4 pain_t1 1.1000442
4 pain_t2 4.0373206
4 pain_t3 2.6327794
5 pain_t1 4.6467597
5 pain_t2 6.1326351
5 pain_t3 4.0348420
rm(df_pain_wide) # for this exercise, we delete df_pain_wide, just to re-create it
    # https://tidyr.tidyverse.org/reference/pivot_wider.html 
    
    df_pain_wide<-df_pain_long %>% 
      pivot_wider(
      names_from = timepoint, 
      values_from=pain,
      )
    
    kbl(df_pain_wide) %>% kable_styling()
id pain_t1 pain_t2 pain_t3
1 4.477547 0.6891036 5.502578
2 5.778489 4.1823753 3.960967
3 3.714936 7.5441658 1.806426
4 1.100044 4.0373206 2.632779
5 4.646760 6.1326351 4.034842

58.1 Jetzt erstellen wir ein etwas komplexeres Beispiel mit zwei Variablen:

id<-1:20
    pain_t1<-c(rnorm(20,5,0.8))
    pain_t2<-c(rnorm(20,5.2,1))
    pain_t3<-c(rnorm(20,6,1))        
    depression_t1<-rnorm(20,3,1.5)    
    depression_t2<-rnorm(20,2.3,1.2)    
    depression_t3<-rnorm(20,2,1)    

    df_wide<-cbind.data.frame(id, pain_t1, pain_t2, pain_t3, depression_t1,depression_t2, depression_t3)    
kbl(df_wide) %>% kable_styling()
id pain_t1 pain_t2 pain_t3 depression_t1 depression_t2 depression_t3
1 5.656984 2.819316 5.815402 3.885715 2.0421460 1.5214934
2 6.165082 5.529996 7.583380 2.539429 2.0003762 2.5848875
3 5.531116 6.203559 4.263717 1.720150 3.7065487 2.5164596
4 5.871913 4.494053 5.098977 3.677762 3.0315677 0.4705033
5 4.130856 5.084113 5.002438 1.802936 1.1359716 0.5163920
6 5.698688 6.774785 5.631553 1.800300 3.5014509 4.0980196
7 4.103681 6.371349 7.105606 2.421270 2.2331449 3.9944306
8 5.061298 6.351247 4.317741 2.310692 2.0161379 3.3254441
9 5.497747 4.824040 6.524044 5.370380 2.5366711 1.4734719
10 4.564592 5.644271 5.227413 2.218900 1.4162920 2.1811705
11 3.352520 6.479761 6.433863 3.699441 0.7152843 1.8664987
12 5.539580 5.564063 5.544053 2.555122 3.9129574 2.3375691
13 6.307981 6.872753 6.468923 3.298944 2.0905369 1.9945405
14 4.775065 4.440590 6.859823 2.085893 1.8472488 2.6521203
15 4.927217 4.793689 6.320824 1.342637 2.3073442 0.7300040
16 7.297372 4.465633 7.419043 5.449281 3.4720211 2.8194853
17 4.240963 4.795546 6.239813 1.039829 1.6175661 1.0833755
18 4.599539 5.395504 6.049200 3.290007 0.0489657 2.0439870
19 5.612096 6.391864 5.371284 4.045980 3.7580677 2.1667151
20 5.599089 5.616377 7.023909 2.606809 5.4713226 2.8584734

58.2 Diese Daten sind im wide Format - Jetzt wollen wir sie in das long Format umwandeln.

  • Bemerkung: bei der Zeile cols = 2:7, hätten wir auch folgendes schreiben können: cols = -id,
library(tidyr) 
    # https://tidyr.tidyverse.org/reference/pivot_longer.html 
    
df_long<-df_wide %>%
    pivot_longer(
        cols = 2:7,
        names_to = c(".value", "time"),
        names_sep = '_')

kbl(df_long) %>% kable_styling()
id time pain depression
1 t1 5.656984 3.8857152
1 t2 2.819316 2.0421460
1 t3 5.815402 1.5214934
2 t1 6.165082 2.5394288
2 t2 5.529996 2.0003762
2 t3 7.583380 2.5848875
3 t1 5.531116 1.7201501
3 t2 6.203559 3.7065487
3 t3 4.263717 2.5164596
4 t1 5.871913 3.6777623
4 t2 4.494053 3.0315677
4 t3 5.098977 0.4705033
5 t1 4.130856 1.8029359
5 t2 5.084113 1.1359716
5 t3 5.002438 0.5163920
6 t1 5.698688 1.8003003
6 t2 6.774785 3.5014509
6 t3 5.631553 4.0980196
7 t1 4.103681 2.4212700
7 t2 6.371349 2.2331449
7 t3 7.105606 3.9944306
8 t1 5.061298 2.3106923
8 t2 6.351247 2.0161379
8 t3 4.317741 3.3254441
9 t1 5.497747 5.3703800
9 t2 4.824040 2.5366711
9 t3 6.524044 1.4734719
10 t1 4.564592 2.2189000
10 t2 5.644271 1.4162920
10 t3 5.227413 2.1811705
11 t1 3.352520 3.6994405
11 t2 6.479761 0.7152843
11 t3 6.433863 1.8664987
12 t1 5.539580 2.5551217
12 t2 5.564063 3.9129574
12 t3 5.544053 2.3375691
13 t1 6.307981 3.2989440
13 t2 6.872753 2.0905369
13 t3 6.468923 1.9945405
14 t1 4.775065 2.0858934
14 t2 4.440590 1.8472488
14 t3 6.859823 2.6521203
15 t1 4.927217 1.3426371
15 t2 4.793689 2.3073442
15 t3 6.320824 0.7300040
16 t1 7.297372 5.4492815
16 t2 4.465633 3.4720211
16 t3 7.419043 2.8194853
17 t1 4.240963 1.0398285
17 t2 4.795546 1.6175661
17 t3 6.239813 1.0833755
18 t1 4.599539 3.2900068
18 t2 5.395504 0.0489657
18 t3 6.049200 2.0439870
19 t1 5.612096 4.0459801
19 t2 6.391864 3.7580677
19 t3 5.371284 2.1667151
20 t1 5.599089 2.6068093
20 t2 5.616377 5.4713226
20 t3 7.023909 2.8584734

58.3 Für diese Übung löschen wir df_wide, nur um es neu zu erstellen (von long wieder zu wide umzustellen).

rm(df_wide) 
    # https://tidyr.tidyverse.org/reference/pivot_wider.html 
    
    df_wide<-df_long %>% 
      pivot_wider(
        names_from = "time", 
        values_from=c("pain","depression"))
    
kbl(df_wide) %>% kable_styling()
id pain_t1 pain_t2 pain_t3 depression_t1 depression_t2 depression_t3
1 5.656984 2.819316 5.815402 3.885715 2.0421460 1.5214934
2 6.165082 5.529996 7.583380 2.539429 2.0003762 2.5848875
3 5.531116 6.203559 4.263717 1.720150 3.7065487 2.5164596
4 5.871913 4.494053 5.098977 3.677762 3.0315677 0.4705033
5 4.130856 5.084113 5.002438 1.802936 1.1359716 0.5163920
6 5.698688 6.774785 5.631553 1.800300 3.5014509 4.0980196
7 4.103681 6.371349 7.105606 2.421270 2.2331449 3.9944306
8 5.061298 6.351247 4.317741 2.310692 2.0161379 3.3254441
9 5.497747 4.824040 6.524044 5.370380 2.5366711 1.4734719
10 4.564592 5.644271 5.227413 2.218900 1.4162920 2.1811705
11 3.352520 6.479761 6.433863 3.699441 0.7152843 1.8664987
12 5.539580 5.564063 5.544053 2.555122 3.9129574 2.3375691
13 6.307981 6.872753 6.468923 3.298944 2.0905369 1.9945405
14 4.775065 4.440590 6.859823 2.085893 1.8472488 2.6521203
15 4.927217 4.793689 6.320824 1.342637 2.3073442 0.7300040
16 7.297372 4.465633 7.419043 5.449281 3.4720211 2.8194853
17 4.240963 4.795546 6.239813 1.039829 1.6175661 1.0833755
18 4.599539 5.395504 6.049200 3.290007 0.0489657 2.0439870
19 5.612096 6.391864 5.371284 4.045980 3.7580677 2.1667151
20 5.599089 5.616377 7.023909 2.606809 5.4713226 2.8584734

58.4 Manchmal führen Umwege zum Ziel: Von Wide to Long to Long-Wide

Wir schauen uns ein Beispiel an, bei dem wir zwei Variablen haben, die wir als long darstellen können: Einerseits der Ort der Probleme, hier Knie und Hüfte, anderseits die drei Messgrössen (“Outcomes”) Gehtest, Sit to Stand Test, und der Hop Test. So sehen die Daten aus: Die Daten sind schon zusammengefasst, das heisst, wir haben hier nicht die Werte einzelner Patient:innen, sondern schon zusammengefasste Werte (d.h. die prozentualen Veränderungen der Mittelwerte).Aber das Prinzip bleibt gleich bei Daten einzelner Patient:innen.
Wir könnten sagen, dass die Daten long-wide sind, da die Variable Gelenk als long formatiert ist (d.h. für jede Kategorie der Variable Gelenk eine Zeile), und die Variable Outcome ist hier als wide formatiert (d.h. es gibt keine Variable Outcome die für jede Kategorie eine Zeile hat, sondern bei der Variable perc_change ist jeweils das Outcome angehängt, also im wide Format).

data_long_wide<-rio::import("http://www.pt-wissen.ch/Statistik_BSc_Physiotherapie_Leukerbad/summary_walk_sit_hop.csv", encoding="UTF-8")
kbl(data_long_wide, caption='Daten im long-wide Format') %>% kable_styling()
Table 58.1: Daten im long-wide Format
Gelenk perc_change_Geh_Test perc_change_Sit_to_Stand_Test perc_change_Hop_Test
Hüfte 8% 17% 6%
Knie 9% 18% 27%

Nun werden wir zuerst die Daten komplett ins long Format transformieren. In diesem Fall könnte man sagen, dass danach die Daten im long-long Format sind, da beide Variablen Gelenk und Outcome als long formatiert sind.

data_long_long<-data_long_wide %>% 
  pivot_longer(
        cols= starts_with("perc"), 
        names_to = "Outcome",
        names_prefix = "perc_change_",
        values_to="value"
      ) 
kbl(data_long_long, caption='Daten im long-long Format') %>% kable_styling()
Table 58.2: Daten im long-long Format
Gelenk Outcome value
Hüfte Geh_Test 8%
Hüfte Sit_to_Stand_Test 17%
Hüfte Hop_Test 6%
Knie Geh_Test 9%
Knie Sit_to_Stand_Test 18%
Knie Hop_Test 27%

Doch wir möchten nun eine Tabelle, in der die beiden Gelenke Knie und Hüfte je eine Spalte besetzen. Deshalb transformieren wir die long-long Daten in ein wide-long format.

data_wide_long<-data_long_long %>% 
   pivot_wider(
      names_from = Outcome, 
      values_from=value,
      )
kbl(data_wide_long, caption='Daten im wide-long Format') %>% kable_styling()
Table 58.3: Daten im wide-long Format
Gelenk Geh_Test Sit_to_Stand_Test Hop_Test
Hüfte 8% 17% 6%
Knie 9% 18% 27%

Natürlich könnten wir es auch gerade umgekehrt darstellen.

data_wide_long2<-data_long_long %>% 
   pivot_wider(
      names_from = Gelenk, 
      values_from=value,
      )
kbl(data_wide_long2, caption='Daten im wide-long Format') %>% kable_styling()
Table 58.4: Daten im wide-long Format
Outcome Hüfte Knie
Geh_Test 8% 9%
Sit_to_Stand_Test 17% 18%
Hop_Test 6% 27%

58.5 Oh, ein Beispiel haben wir noch.

Wir haben drei Variablen mit den Antwortsoptionen für die STarTBack Risiko-Kategorien Low, Medium, High-Risk. Siehe hier.

set.seed(666)
id=1:200
Kategorie.t0=sample(c("Low-Risk", "Medium-Risk", "High-Risk"), size=200, replace=TRUE, prob=c(0.34, 0.42, 0.24))
Kategorie.t1=sample(c("Low-Risk", "Medium-Risk", "High-Risk", NA), size=200, replace=TRUE, prob=c(0.38, 0.39, 0.20,0.03))
Kategorie.t2=sample(c("Low-Risk", "Medium-Risk", "High-Risk", NA), size=200, replace=TRUE, prob=c(0.38, 0.37, 0.19,0.06))

data<-data.frame(id, Kategorie.t0, Kategorie.t1, Kategorie.t2)


head(data)
##   id Kategorie.t0 Kategorie.t1 Kategorie.t2
## 1  1    High-Risk  Medium-Risk         <NA>
## 2  2  Medium-Risk  Medium-Risk    High-Risk
## 3  3    High-Risk  Medium-Risk    High-Risk
## 4  4  Medium-Risk  Medium-Risk     Low-Risk
## 5  5  Medium-Risk         <NA>  Medium-Risk
## 6  6     Low-Risk     Low-Risk     Low-Risk

Wir möchten nun eine Tabelle erstellen, um die relative Häufigkeit der Kategorien zu berechnen. Das können wir zum Beispiel tun, indem wir die Tabelle zuerst in ein long Format umwandeln.

By the way, natürlich könnten wir dies mit summarytools::freq(data$Kategorie.t0) etc sehr einfach tun. Doch manchman möchten wir die Tabelle mit den Zusammenfassungen noch für weitere Analysen benutzen, wie zum Beispiel die Berechnungen der Veränderungen oder für ggplot Graphiken.

Hier das Beispiel mit summarytools::freq.

summarytools::freq(data$Kategorie.t0)
## Frequencies  
## data$Kategorie.t0  
## Type: Character  
## 
##                     Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------------- ------ --------- -------------- --------- --------------
##         High-Risk     49     24.50          24.50     24.50          24.50
##          Low-Risk     65     32.50          57.00     32.50          57.00
##       Medium-Risk     86     43.00         100.00     43.00         100.00
##              <NA>      0                               0.00         100.00
##             Total    200    100.00         100.00    100.00         100.00

Nun machen wir es aber auf die harte Tour:

data_long<-data %>% 
  pivot_longer(cols=-id, 
               names_pattern="(.+)\\.(.+)", 
                names_to=c(".value", "Zeitpunkt"))
head(data_long)
## # A tibble: 6 × 3
##      id Zeitpunkt Kategorie  
##   <int> <chr>     <chr>      
## 1     1 t0        High-Risk  
## 2     1 t1        Medium-Risk
## 3     1 t2        <NA>       
## 4     2 t0        Medium-Risk
## 5     2 t1        Medium-Risk
## 6     2 t2        High-Risk

Nun können mit der dplyr::summarise Funktion sehr einfach die Prozente berechnen.

In der Variante 1 berechnen wir die Prozente unter Berücksichtigung der fehlenden Werte (d.h. 100 bezieht sich auf den kompletten Datensatz von 200, und wir berechnen die Prozente der Missing Values auch).

summary_table_variante_1<-data_long %>% 
  group_by(Zeitpunkt, Kategorie) %>% 
  summarise(n=n()) %>% 
  mutate(Prozente=round(n/sum(n)*100,1))
## `summarise()` has grouped output by 'Zeitpunkt'. You can override using the
## `.groups` argument.
kbl(summary_table_variante_1, caption="Absolute und relative Häufigkeit berechnet auf 200 Personen.") %>% kable_styling()
Table 7.1: Absolute und relative Häufigkeit berechnet auf 200 Personen.
Zeitpunkt Kategorie n Prozente
t0 High-Risk 49 24.5
t0 Low-Risk 65 32.5
t0 Medium-Risk 86 43.0
t1 High-Risk 45 22.5
t1 Low-Risk 77 38.5
t1 Medium-Risk 72 36.0
t1 NA 6 3.0
t2 High-Risk 40 20.0
t2 Low-Risk 75 37.5
t2 Medium-Risk 77 38.5
t2 NA 8 4.0

In der nächsten Variante berechnen wir die Prozente nur in Bezug auf die Personen, die keine Missing Values haben. Wir brauchen dazu wieder die length2 Funktion. Dank geht auch hier wieder an http://www.cookbook-r.com/Manipulating_data/Summarizing_data/. Damit wir in der Tabelle die Missing Values auch als Prozente sehen, müssen wir etwas tricksen. Die Prozente der Missing Values beziehen sich auf die 200 Personen. Die Prozente der nicht fehlenden Kategorien beziehen sich hier auf die Personen ohne Missing Values in der Variable Kategorie.

    # New version of length which can handle NA's: if na.rm==T, don't count them
    length2 <- function (x, na.rm=FALSE) {
        if (na.rm) sum(!is.na(x))
        else       length(x)
    }


summary_table_variante_2<-data_long %>% 
  group_by(Zeitpunkt, Kategorie) %>% 
  summarise(n=length2(Kategorie, na.rm=TRUE),
            total_incl_missing=n(),
            missing=sum(is.na(Kategorie))) %>% 
  mutate(Prozente=round(ifelse(is.na(Kategorie),missing/sum(total_incl_missing)*100, n/sum(n)*100),1)) %>% 
  mutate(n=ifelse(is.na(Kategorie), missing, n)) %>% 
  select(-missing,-total_incl_missing)

kbl(summary_table_variante_2, caption="Absolute und relative Häufigkeit berechnet auf Personen ohne Missing Values in der Variable Kategorie.") %>% kable_styling()
Table 54.2: Absolute und relative Häufigkeit berechnet auf Personen ohne Missing Values in der Variable Kategorie.
Zeitpunkt Kategorie n Prozente
t0 High-Risk 49 24.5
t0 Low-Risk 65 32.5
t0 Medium-Risk 86 43.0
t1 High-Risk 45 23.2
t1 Low-Risk 77 39.7
t1 Medium-Risk 72 37.1
t1 NA 6 3.0
t2 High-Risk 40 20.8
t2 Low-Risk 75 39.1
t2 Medium-Risk 77 40.1
t2 NA 8 4.0

Das gleiche Ergebnis bekommen wir mit folgendem Code, ausser dass wir die Missing Values nicht ausgeben können.

summary_table_variante_3<-data_long %>% 
  filter(!is.na(Kategorie)) %>% 
  group_by(Zeitpunkt, Kategorie) %>% 
  summarise(n=n()) %>% 
  mutate(Prozente=round(n/sum(n)*100,1))
kbl(summary_table_variante_3, caption="Absolute und relative Häufigkeit berechnet auf 200 Personen.") %>% kable_styling()
Table 58.5: Absolute und relative Häufigkeit berechnet auf 200 Personen.
Zeitpunkt Kategorie n Prozente
t0 High-Risk 49 24.5
t0 Low-Risk 65 32.5
t0 Medium-Risk 86 43.0
t1 High-Risk 45 23.2
t1 Low-Risk 77 39.7
t1 Medium-Risk 72 37.1
t2 High-Risk 40 20.8
t2 Low-Risk 75 39.1
t2 Medium-Risk 77 40.1

58.6 Häufigkeitstabellen mit mehr als einer Variable

Wenn wir mehr als eine Variable haben, müssen wir nach der ersten long umwandlung noch ein zweites Mal pivot_longer ausführen.

data<-rio::import("http://www.pt-wissen.ch/Statistik_BSc_Physiotherapie_Leukerbad/zufriedenheit.csv", encoding="UTF-8") 

data_long<-data%>% 
  pivot_longer(cols=everything(), 
               names_pattern = "(.+)\\.(.+)", 
               names_to=c(".value", "Zeitpunkt")) 
DT::datatable(data_long)

So wie die Daten jetzt sind, können wir noch nicht einfach eine Häufigkeitstabelle erstellen. Einfacher geht es, wenn wir noch einmal pivot_longer anwenden.

data_long_long<-data_long %>% 
    pivot_longer(cols=-Zeitpunkt, 
               names_to="Variable", 
               values_to="Zufriedenheit")
DT::datatable(data_long_long)

Jetzt können wir ganz einfach mit dplyr::sumarise eine Häufigkeitstabelle erstellen. Damit wir die Missing Values korrekt berücksichtigen, müssen wir die lehren Zellen mit NA ersetzen und wieder die length2 Funktion benutzen.

data_long_long[data_long_long==""]<-NA

length2 <- function (x, na.rm=FALSE) {
        if (na.rm) sum(!is.na(x))
        else       length(x)
    }
summary_table_Zufriedenheit<-data_long_long %>% 
  group_by(Zeitpunkt, Variable, Zufriedenheit) %>% 
  summarise(n=length2(Zufriedenheit, na.rm=TRUE),
            total_incl_missing=n(),
            missing=sum(is.na(Zufriedenheit))) %>% 
  mutate(Prozente=round(ifelse(is.na(Zufriedenheit),missing/sum(total_incl_missing)*100, n/sum(n)*100),1)) %>% 
  mutate(n=ifelse(is.na(Zufriedenheit), missing, n)) %>% 
  select(-missing,-total_incl_missing)
## `summarise()` has grouped output by 'Zeitpunkt', 'Variable'. You can override
## using the `.groups` argument.
kableExtra::kbl(summary_table_Zufriedenheit) %>% kableExtra::kable_styling()
Zeitpunkt Variable Zufriedenheit n Prozente
t1 Zufrieden_mit.Therapie In hohem Masse 3 13.0
t1 Zufrieden_mit.Therapie Mässi 2 8.7
t1 Zufrieden_mit.Therapie Sehr 18 78.3
t1 Zufrieden_mit.Zustand Ja 10 43.5
t1 Zufrieden_mit.Zustand Nein 7 30.4
t1 Zufrieden_mit.Zustand Sehr 6 26.1
t2 Zufrieden_mit.Therapie Mässi 4 30.8
t2 Zufrieden_mit.Therapie Sehr 9 69.2
t2 Zufrieden_mit.Therapie NA 10 43.5
t2 Zufrieden_mit.Zustand In hohem Masse 1 4.8
t2 Zufrieden_mit.Zustand Ja 1 4.8
t2 Zufrieden_mit.Zustand Mässi 6 28.6
t2 Zufrieden_mit.Zustand Nein 4 19.0
t2 Zufrieden_mit.Zustand Sehr 9 42.9
t2 Zufrieden_mit.Zustand NA 2 8.7
t3 Zufrieden_mit.Therapie Mässi 3 27.3
t3 Zufrieden_mit.Therapie Nein 3 27.3
t3 Zufrieden_mit.Therapie Sehr 5 45.5
t3 Zufrieden_mit.Therapie NA 12 52.2
t3 Zufrieden_mit.Zustand Mässi 2 18.2
t3 Zufrieden_mit.Zustand Nein 2 18.2
t3 Zufrieden_mit.Zustand Sehr 7 63.6
t3 Zufrieden_mit.Zustand NA 12 52.2

Ob breit, ob lang, wir lieben alle Daten, sorry, Dackel.