Создание конкретной кросс-таблицы в R?

У меня есть кадр данных, который содержит информацию о финансовых взносах политическим кандидатам (обозначенным в данных как «канд») и политическим организациям (обозначенным в данных как «комм»). Фрейм данных также включает уникальный идентификатор для каждого участника, при этом каждая строка в данных обозначает один сделанный вклад. Что я хочу сделать, так это получить перекрестную таблицу, которая показывает для каждой политической (некандидатской) организации, сколько доноров этих организаций также внесли свой вклад в каждого политического кандидата в фрейме данных. Фрейм данных выглядит так:

 contributor ID .      organization
 1                     cand1
 2                     cand2
 3                     comm1
 3                     cand1
 4                     cand1
 5                     cand2
 5                     cand1
 5                     comm2

То, что я хочу создать, выглядит примерно так:

  Comm .              Cand
               Cand1 .     Cand2
  Comm1        1           0
  Comm2        1           1

(Поскольку 1 человек — идентификатор № 3 — внес вклад как в comm1, так и в cand1, а 1 человек — идентификатор № 5 — внес вклад в comm1, cand1 и cand2.)

Я думал о способах сделать это с помощью агрегата или dplyr, но я не уверен. У кого-нибудь есть советы?


person hans91    schedule 26.11.2016    source источник
comment
Если память доступна, вы можете начать с crossprod(table(dat)) - как в здесь- и соответственно подмножество, например crossprod(table(dat))[startsWith(levels(dat$org), "comm"), startsWith(levels(dat$org), "cand")]   -  person alexis_laz    schedule 27.11.2016
comment
Спасибо за это. Я получаю следующую ошибку с этим кодом: Ошибка в таблице (таблице): попытка создать таблицу с ›= 2^31 элементом. Есть ли у вас какие-либо предложения?   -  person hans91    schedule 27.11.2016
comment
В том же духе вы можете попробовать разреженную альтернативу -- library(Matrix); tab = xtabs( ~ contributorID + organization, dat, sparse = TRUE); crossprod(tab[, startsWith(colnames(tab), "comm")], tab[, startsWith(colnames(tab), "cand")])   -  person alexis_laz    schedule 27.11.2016
comment
Вы решили проблему? Если да, то не могли бы вы принять один из ответов?   -  person Joe    schedule 30.07.2019


Ответы (3)


Вам нужно использовать что-то вроде тидыр. Вам нужно сделать переменную для каждого комитета и по одной для каждого кандидата. Ваши данные уже в длинном формате, но теперь вам нужно создать широкий фрейм данных, используя организацию и идентификатор донора в качестве уникального идентификатора. Вы можете делать перекрестные таблицы.

person Elin    schedule 26.11.2016

dfs = read.table(text = "contributor organization
1 cand1
2 cand2
3 comm1
3 cand1
4 cand1
5 cand2
5 cand1
5 comm2", sep = " ", stringsAsFactors = FALSE, header = TRUE)

# select only comms with their contributor
comms = dfs[grep("^comm", dfs$organization), ]
colnames(comms)[2] = "comms"
# select only cands
cands = dfs[grep("^cand", dfs$organization), ]
colnames(cands)[2] = "cands"

# combine comms and candidates
new_dfs = merge(comms, cands, all = TRUE)
with(new_dfs, table(comms, cands))

Обновлять. Старайтесь избегать создания большой матрицы с помощью table

library(tidyr)
library(dplyr)
dfs = read.table(text = "contributor organization
1 cand1
2 cand2
3 comm1
3 cand1
4 cand1
5 cand2
5 cand1
5 comm2", sep = " ", stringsAsFactors = FALSE, header = TRUE)

# select only comms with their contributor
comms = dfs %>% filter(grepl("^comm", organization))

# select only cands
cands = dfs %>% 
    filter(grepl("^cand", organization)) %>% 
    mutate(
        value = 1
    ) %>% 
    spread(key  = organization, value = value, fill = 0)

left_join(comms, cands)
person Gregory Demin    schedule 26.11.2016
comment
Я понимаю интуицию, стоящую за этим кодом, но сталкиваюсь с тем же, что и с другими предложениями: Ошибка в таблице (comms, cands): попытка создать таблицу с ›= 2 ^ 31 элементами - person hans91; 27.11.2016

Вот одно из возможных решений с использованием tidyr, dplyr и table(). Сначала мы подсчитываем общее количество участников cand и com.

library(tidyr)
library(dplyr)

df_summary <- 
df %>% mutate(ct = 1) %>% spread(organization, ct) %>% 
transmute(
  comm1_cand1 = ifelse(cand1 + comm1 > 0, 1, 0),
  comm2_cand1 = ifelse(cand1 + comm2 > 0, 1, 0),
  comm1_cand2 = ifelse(cand2 + comm1 > 0, 1, 0),
  comm2_cand2 = ifelse(cand2 + comm2 > 0, 1, 0)) %>%
gather() %>%
separate(key, into = c("comm", "cand"), sep = "_")

Это дает двусторонний категориальный фрейм данных, который выглядит следующим образом:

#    comm  cand value
#1  comm1 cand1    NA
#2  comm1 cand1    NA
#3  comm1 cand1     1
#4  comm1 cand1    NA
#5  comm1 cand1    NA
#6  comm2 cand1    NA
#7  comm2 cand1    NA
# etc

Теперь мы делаем нашу двустороннюю таблицу из данных.

table(df_summary)

#   cand
#comm    cand1 cand2
#  comm1     1     0
#  comm2     1     1
person Joe    schedule 27.11.2016
comment
Это решение кажется отличным, но я получил следующую ошибку: Ошибка: повторяющиеся идентификаторы для строк... Есть ли у вас какие-либо мысли по этому поводу? - person hans91; 28.11.2016
comment
ХОРОШО. Можете ли вы предоставить большую выборку ваших данных, которая вызывает эту проблему? Я использовал только ваши исходные 8 наблюдений, думая, что их можно будет масштабировать, но, похоже, это не так. - person Joe; 28.11.2016