От нескольких записей для одного ID к одной в R

топ 100 блогов answer_42 — 19.09.2010 Таймыр называет это "перекрестным запросом", ну пусть будет хоть зеброй, главное чтоб работало. Итак.

Стандартная ситуация - есть записи в таблице, для каждой - ID, но некоторые записи имеют один ID. Например ситуация такая, есть таблица с почвами, некоторые - чистые, а некоторые комплексы, таким образом, каждый уникальный почвенный выдел (определяется по ID) может быть представлен одной или несколькими записями.

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

Пример:
x = data.frame(cbind(c(1,2,2,4),trunc(runif(4,0,10)),trunc(runif(4,0,10))),trunc(runif(4,0,10)))
names(x) = c("ID","A","B","C")
x
   ID A B C
1 1 0 0 4
2 2 5 4 5
3 2 1 4 7
4 4 2 7 6
Итак, у нас 4 записи, но 3 уникальных ID. Один из них, двойка - составной, представлен двумя записями. Решать будем так: 
  1.  Составим список уникальных идентификаторов
  2. Определим максимальное количество записей на один идентификатор - частотной таблицей
  3. По этому числу создадим эквивалентное количество наборов полей, т.е. если были поля A B C и макс=2, то будет A B C A2 B2 C2
  4. Дальше выбираем данные по идентификатору, распластываем, добавляем NA недостающие до макс. числа полей и т.д.
Результат (для примера выше):
   ID A B C A1 B1 C1
1 1 0 0 4 NA NA NA
2 2 5 4 5 1 4 7
3 4 2 7 6 NA NA NA
Полный код под катом
  x = data.frame(cbind(c(1,2,2,4),trunc(runif(4,0,10)),trunc(runif(4,0,10))),trunc(runif(4,0,10)))
names(x) = c("ID","A","B","C")

idfname = "ID"
idfpos = which(names(x) == idfname)

#determine number of unique IDs
ids = unique(x[,idfpos])

#determine maximum number of repeats
maxrepeats = max(as.vector(table(x[,idfpos])))

#add fields
nms = names(x)
nms2 = nms
for (i in 1:(maxrepeats-1)) {
    nms2 = c(nms2,paste(nms,i,sep="")[-1])
}
nms = nms2

res = NULL
for (id in ids) {
    d = subset(x,x$ID == id)
    y = as.numeric(d$ID[1])
    for (i in 1:dim(d)[1]) {
        y = c(y,as.numeric(d[i,2:length(d)]))
    }
    
    if (length(y) != length(nms)) {
        y = c(y,rep(NA,length(nms)-length(y)))
    }
    res = rbind(res,y)
}
res = data.frame(res)
names(res) = nms 

Оставить комментарий

Архив записей в блогах:
Эстонская компания Milrem Robotics, известная как разработчик безэкипажной гусеничной наземной платформы THeMIS, 6 января 2021 года сообщила о начале заводских испытаний первого опытного образца более крупной безэкипажной гусеничной наземной платформы под обозначением Type-X, ...
"«Демонстрация тела — самоубийство культуры». Священники осудили обнаженные тела в искусстве Статуи под прикрытием Новосибирский государственный университет архитектуры и дизайна (НГУАДИ) решил защитить делегацию Русской православной церкви от «непристойностей» и прикрыл все обнаженные ...
Странный призыв московского патриархата смотреть молебен по зомбоящику обнажает искусственность чекистской церкви и непричастность московских гостей к украинскому празднику. Киевский Патриархат счел странным призыв УПЦ МП к верующим смотреть молебен по телевизору В УПЦ ...
Пришла весна. Типа ура. Не очень я люблю весну в самом её начале. Точнее не люблю до того момента, пока эта белая дрянь не растает и не подсохнет вся грязь. А это не быстрый и довольно бесячий процесс. Ну и я заболела тут. Второй день страдаю. Жалеть не ...
Товар получила, теперь гостей намывает Покупателей )) Красотка! Еще и чистюля ...