2017-02-13 11 views
4

Я пытаюсь найти способ создания последовательных Group_ID на основе «перекрывающихся» переменных. Самый простой способ описать это - использовать пример дома, кредита и заемщика.Рекурсивная группировка в R

Предположим, мы имеем следующий пример

df <- data.frame(house  = c('H_01','H_02','H_03','H_04','H_05'), 
       loan  = c('L_01','L_02','L_02','L_03','L_04'), 
       borrower = c('B_01','B_01','B_02','B_03','B_04')) 

Предположим, что один будет иметь отношения многие ко многим между всеми переменными (дом, кредит, заемщик) Так, например, дом 1 (H_01) связан с Кредит 1 (L_01) и Заемщик 1 (B_01). Но B_01 также связан с L_02, который сам связан с H_02, но также связан с H_03 - поэтому первые 3 строки в моей таблице должны быть помечены G_01 (для группы 1).

H_04 связан с L_03, который не принадлежит ни к одной другой записи, и ни делает B_03 связаны с какой-либо другой записи, так что четвёртая запись должна быть в G_02. И с аналоговой разведкой, мы должны видеть, что запись 5 принадлежит в своей подгруппе G_03

Есть ли способ элегантно иметь dplyr (предпочтительно, но не обязательно) достижения этой группировки G_01, G_02 и G_03?

+3

Не моя форте, но звучит как сети/igraph. – alistaire

+0

Для этого простого примера базовый R-код 'cumsum (pmin (c (1, diff (df $ loan)), c (1, diff (df $ заемщик))))' будет вычислять группы. Однако это не будет работать в целом, если, например, у раннего заемщика есть несколько займов и обменивается этими кредитами с несколькими заемщиками, рано или поздно. – lmo

ответ

4

Вы ищете "подключенные компоненты". Мы можем рассматривать отношения как график, сначала переупорядочив данные (melt), а затем попросим хорошо внедренную библиотеку графов (igraph) выполнить работу.

library(reshape2) 
library(igraph) 

components(graph.data.frame(melt(df,id="house")[,c(1,3)]))$membership[df$house] 

    # H_01 H_02 H_03 H_04 H_05 
    # 1 1 1 2 3 

Обобщить вы можете склеить отношения со значением в «цвет» узлы, например,

with(melt(df,id="house"),data.frame(x=house,y=paste(variable,value,sep="."))) 

перед созданием графика.

+0

Спасибо @ A.Webb - это прекрасно работает и также очень элегантно. Я откладывал погружение в базы данных графов, но это лишь убедительный пример того, что я пропустил. В качестве бонусного вопроса; имеет значение, с какой переменной я начинаю _anchor_ от (в коде, который вы начинаете с «Дома», - но если бы у меня было n переменных, изменилось бы то, что я выбрал для плавки вокруг/из? – Olivier

+0

Не должно иметь значения Это немного ярлык по нескольким причинам: во-первых, график по умолчанию направлен, что означает, что мы указали ребро от H_01 до L_01, а не наоборот. Мы могли бы/должны указывать 'direct = FALSE', но' Компоненты 'по умолчанию проверяют слабосвязанные, т. е. как если бы направленные направления были неориентированы вместо этого. Во-вторых, отношения в первой строке на самом деле H_01 - L_01, H_01 - B_01 и L_01 - B_01, но мы включили только первые два как ребра. Это не имеет значения, потому что связь транзитивна, как и связность. –

1

Решение A. Webb очевидно превосходит его. Но так как я разработал решение a, я поставлю его здесь.

df = data.frame(apply(df, 2, as.character), stringsAsFactors = FALSE) 
g = 1 
df$group[1] = paste("G",g,sep = "") 

#Find out unique groups and assign "CHECK" to rows in same groups 
for (i in 2:nrow(df)){ 
    if (any(df[i,1:3] %in% unlist(df[1:(i-1),1:3]))){ 
     df$group[i] = "CHECK" 
    } else { 
     g = g + 1 
     df$group[i] = paste("G",g,sep = "") 
    } 
} 

#Assign groups to rows in same group 
for (i in 1:nrow(df)){ 
    if (df$group[i] != "CHECK"){ 
     next 
    } 
    if (df$house[i] %in% df$house[1:i]){ 
     df$group[i] = df$group[match(df$house[i], df$house[1:i])]   
    } 
    if (df$loan[i] %in% df$loan[1:i]){ 
     df$group[i] = df$group[match(df$loan[i], df$loan[1:i])]   
    } 
    if (df$borrower[i] %in% df$borrower[1:i]){ 
     df$group[i] = df$group[match(df$borrower[i], df$borrower[1:i])]  
    } 
} 

#> df$group 
#[1] "G1" "G1" "G1" "G2" "G3" 
+1

также спасибо @ d.b - хорошо продуманное решение, хотя и немного сложнее реализовать переменные _n_. Спасибо за ваш очень быстрый ответ – Olivier