Таблицы сопряженности весьма удобный способ отображения материала. В R есть разные способы для его реализации, проще всего следующий. Используем функцию ctab из пакета catspec. У нее есть следующие параметры:

  • dec.places — количество знаков после запятой
  • type — тип таблицы, «n» — частоты, «row» — проценты по строкам, «column» — проценты по столбцам, «total» — общие проценты
  • style — стиль таблицы, «long» или «wide»
  • row.vars — переменные — строки таблицы
  • col.vars — переменные — столбцы таблицы
  • percentages — выводить проценты или частоты, по умолчанию «T», т.е. TRUE, т.е. вывод процентов
  • addmargins — выводить ли итоги таблицы.

Посмотрим ее работу на примере статистики о погибших на Титанике.

В массиве Titanic есть данные об Age, Class, Sex, Survived.

1
2
3
4
5
No 	Name 	Levels
1 	Class 	1st, 2nd, 3rd, Crew
2 	Sex 	Male, Female
3 	Age 	Child, Adult
4 	Survived 	No, Yes

Сначала посмотрим все, что можно.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
> ctab(Titanic,type=c("n","c","r","t"),style="w")
                             Count        Column %         Row %        Total %       
                   Survived     No    Yes       No    Yes     No    Yes      No    Yes
Class Sex    Age                                                                      
1st   Male   Child            0.00   5.00     0.00   8.06   0.00 100.00    0.00   2.78
             Adult          118.00  57.00   100.00  91.94  67.43  32.57   65.56  31.67
      Female Child            0.00   1.00     0.00   0.71   0.00 100.00    0.00   0.69
             Adult            4.00 140.00   100.00  99.29   2.78  97.22    2.76  96.55
2nd   Male   Child            0.00  11.00     0.00  44.00   0.00 100.00    0.00   6.15
             Adult          154.00  14.00   100.00  56.00  91.67   8.33   86.03   7.82
      Female Child            0.00  13.00     0.00  13.98   0.00 100.00    0.00  12.26
             Adult           13.00  80.00   100.00  86.02  13.98  86.02   12.26  75.47
3rd   Male   Child           35.00  13.00     8.29  14.77  72.92  27.08    6.86   2.55
             Adult          387.00  75.00    91.71  85.23  83.77  16.23   75.88  14.71
      Female Child           17.00  14.00    16.04  15.56  54.84  45.16    8.67   7.14
             Adult           89.00  76.00    83.96  84.44  53.94  46.06   45.41  38.78
Crew  Male   Child            0.00   0.00     0.00   0.00   0.00   0.00    0.00   0.00
             Adult          670.00 192.00   100.00 100.00  77.73  22.27   77.73  22.27
      Female Child            0.00   0.00     0.00   0.00   0.00   0.00    0.00   0.00
             Adult            3.00  20.00   100.00 100.00  13.04  86.96   13.04  86.96

Column % в данном случае отражает распределение по возрасту, Row % — по выживанию, Total % — и то и то. Данные сгруппированы по классу пассажиров. Хуже всего, судя по всему, пришлось мужикам во втором классе, а женщинам — в третьем.
row.vars и col.vars позволяют уточнить, по каким параметрам нам нужна инормация:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> ctab(Titanic,type=c("n","t"),style="w",row.vars=c("Age","Survived"))
                      Count                                                  Total %                                                 
               Class    1st           2nd           3rd          Crew            1st           2nd           3rd          Crew       
               Sex     Male Female   Male Female   Male Female   Male Female    Male Female   Male Female   Male Female   Male Female
Age   Survived                                                                                                                       
Child No               0.00   0.00   0.00   0.00  35.00  17.00   0.00   0.00    0.00   0.00   0.00   0.00  44.30  21.52   0.00   0.00
      Yes              5.00   1.00  11.00  13.00  13.00  14.00   0.00   0.00   83.33  16.67  45.83  54.17  16.46  17.72   0.00   0.00
Adult No             118.00   4.00 154.00  13.00 387.00  89.00 670.00   3.00   36.99   1.25  59.00   4.98  61.72  14.19  75.71   0.34
      Yes             57.00 140.00  14.00  80.00  75.00  76.00 192.00  20.00   17.87  43.89   5.36  30.65  11.96  12.12  21.69   2.26
> ctab(Titanic,type=c("n","t"),style="w",row.vars=c("Age","Survived"),col.vars="Class")
                      Count                      Total %                     
               Class    1st    2nd    3rd   Crew     1st    2nd    3rd   Crew
Age   Survived                                                               
Child No               0.00   0.00  52.00   0.00    0.00   0.00  47.71   0.00
      Yes              6.00  24.00  27.00   0.00    5.50  22.02  24.77   0.00
Adult No             122.00 167.00 476.00 673.00    5.83   7.98  22.75  32.17
      Yes            197.00  94.00 151.00 212.00    9.42   4.49   7.22  10.13

Вместо таблиц можно использовать фреймы. Например, в logan собраны данные о позициях, занимаемых неграми и не-неграми в 1972-78.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
> summary(logan)
           occ                focc          educ             black    
 farm        : 19   farm        : 92   Min.   : 2.00   non-black:764  
 operatives  :217   operatives  :235   1st Qu.:12.00   black    : 74  
 craftsmen   :202   craftsmen   :232   Median :13.00                  
 sales       :105   sales       : 82   Mean   :13.58                  
 professional:295   professional:197   3rd Qu.:16.00                  
                                       Max.   :20.00                  
> with(logan,ctab(black,occ,focc,type=c("t"),style="l",row.vars=c("black","occ"),col.vars="focc",addmargins=T))
                       focc   farm operatives craftsmen  sales professional    Sum
black     occ                                                                     
non-black farm                1.96       0.13      0.13   0.00         0.13   2.36
          operatives          2.49      10.08      6.41   1.83         2.75  23.56
          craftsmen           2.75       5.50     10.21   2.09         3.40  23.95
          sales               0.92       2.75      3.40   1.05         4.71  12.83
          professional        1.83       7.07      9.03   5.63        13.74  37.30
          Sum                 9.95      25.52     29.19  10.60        24.74 100.00
black     farm                0.00       1.35      0.00   0.00         0.00   1.35
          operatives         13.51      22.97      8.11   1.35         4.05  50.00
          craftsmen           6.76      16.22      1.35   0.00         1.35  25.68
          sales               0.00       8.11      1.35   0.00         0.00   9.46
          professional        1.35       5.41      1.35   0.00         5.41  13.51
          Sum                21.62      54.05     12.16   1.35        10.81 100.00

Негры в основном работают (occ, суммы по строкам в последнем столбце) в качестве operatives (я так понимаю, что это типа низкооплачиваемых должностей, но не уверен) и craftsmen (ремесленников?), а «не-негры» — на профессиональных позициях. Причем, по сравнению с прошлыми данными (focc, суммы по столбцам) произошло общее повышение уровня работы, но у негров мало изменений в плане профессиональных позиций, больше прирост доли craftsmen и sales. Для вывода таблиц такого рода проще всего, наверное, использовать вставку в Excel с рзделением по ширине.

Альтернативный вариант — функция CrossTable в пакете gmodels. Но она работает лишь с двумерными таблицами, да и вывод данных мне не очень нравится.

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
28
29
30
31
> CrossTable(logan$black,logan$occ,format="SPSS",digits=2)
 
   Cell Contents
|-------------------------|
|                   Count |
| Chi-square contribution |
|             Row Percent |
|          Column Percent |
|           Total Percent |
|-------------------------|
 
Total Observations in Table:  838 
 
             | logan$occ 
 logan$black |         farm  |   operatives  |    craftsmen  |        sales  | professional  |    Row Total | 
-------------|--------------|--------------|--------------|--------------|--------------|--------------|
   non-black |          18  |         180  |         183  |          98  |         285  |         764  | 
             |        0.03  |        1.61  |        0.01  |        0.05  |        0.96  |              | 
             |        2.36% |       23.56% |       23.95% |       12.83% |       37.30% |       91.17% | 
             |       94.74% |       82.95% |       90.59% |       93.33% |       96.61% |              | 
             |        2.15% |       21.48% |       21.84% |       11.69% |       34.01% |              | 
-------------|--------------|--------------|--------------|--------------|--------------|--------------|
       black |           1  |          37  |          19  |           7  |          10  |          74  | 
             |        0.27  |       16.60  |        0.08  |        0.56  |        9.89  |              | 
             |        1.35% |       50.00% |       25.68% |        9.46% |       13.51% |        8.83% | 
             |        5.26% |       17.05% |        9.41% |        6.67% |        3.39% |              | 
             |        0.12% |        4.42% |        2.27% |        0.84% |        1.19% |              | 
-------------|--------------|--------------|--------------|--------------|--------------|--------------|
Column Total |          19  |         217  |         202  |         105  |         295  |         838  | 
             |        2.27% |       25.89% |       24.11% |       12.53% |       35.20% |              | 
-------------|--------------|--------------|--------------|--------------|--------------|--------------|

Наконец, можно не пользоваться catspec, а сделать все самому, может даже удобней будет иногда.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
> t<-ftable(Titanic, row.vars = c("Class","Sex"), col.vars = "Survived")
 
> t
             Survived  No Yes
Class Sex                    
1st   Male            118  62
      Female            4 141
2nd   Male            154  25
      Female           13  93
3rd   Male            422  88
      Female          106  90
Crew  Male            670 192
      Female            3  20
 
> perc_t<-round(prop.table(t, margin=1)*100)
 
> perc_t
             Survived No Yes
Class Sex                   
1st   Male            66  34
      Female           3  97
2nd   Male            86  14
      Female          12  88
3rd   Male            83  17
      Female          54  46
Crew  Male            78  22
      Female          13  87
 
> for (i in c(1:8)) t[i,]<-(paste (t[i,],' (',perc_t[i,],'%)', sep=''))
 
> t
             Survived        No       Yes
Class Sex                                
1st   Male            118 (66%) 62 (34%) 
      Female          4 (3%)    141 (97%)
2nd   Male            154 (86%) 25 (14%) 
      Female          13 (12%)  93 (88%) 
3rd   Male            422 (83%) 88 (17%) 
      Female          106 (54%) 90 (46%) 
Crew  Male            670 (78%) 192 (22%)
      Female          3 (13%)   20 (87%)

В данном примере идет подсчет процентов по строкам, prop_table может делать и по столбцам, и общие. Такой способ, в частности, позволяет использовать полученные таблицы для вывода в html.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> HTMLStart(outdir = "d://4win/R/", filename = "index")
 
 *** Output redirected to directory:  d://4win/R/
 *** Use HTMLStop() to end redirection.[1] TRUE
HTML> t
             Survived        No       Yes
Class Sex                                
1st   Male            118 (66%) 62 (34%) 
      Female          4 (3%)    141 (97%)
2nd   Male            154 (86%) 25 (14%) 
      Female          13 (12%)  93 (88%) 
3rd   Male            422 (83%) 88 (17%) 
      Female          106 (54%) 90 (46%) 
Crew  Male            670 (78%) 192 (22%)
      Female          3 (13%)   20 (87%) 
HTML> HTMLStop()
 
[1] "d://4win/R//index_main.html"

Получаем такую табличку:

Survived No Yes
Class Sex
1st Male 118 (66%) 62 (34%)
Female 4 (3%) 141 (97%)
2nd Male 154 (86%) 25 (14%)
Female 13 (12%) 93 (88%)
3rd Male 422 (83%) 88 (17%)
Female 106 (54%) 90 (46%)
Crew Male 670 (78%) 192 (22%)
Female 3 (13%) 20 (87%)