2015-11-22 19 views
7

Ho un frame di dati con due colonne come qui sotto:R - corrispondenza a un valore combinando valori di una colonna

Col1  Col2 
1 7197.36 14.00 
2  NA 5173.94 
3  NA 13333.06 
4 7004.38 473.32 
5  NA 4980.61 
6 26355.52 110.05 
7  NA 1307.32 
8  NA 6531.06 
9  NA 3777.65 
10  NA 7827.44 
11 8753.22 85.00 
12  NA  1.86 
13  NA 2009.42 
14  NA 502.89 
15  NA 3182.86 
16  NA  NA 

Volevo trovare righe corrispondenti nella colonna 'Col2' corrispondente al singolo valore in ' Col1' . Ad esempio, 7197,36 = 14.00 + 5173,94 + 2009.42 (righe 1,2,13 in 'Col2')

Qui, somma di 'Col1' = somma delle 'Col2'

Il frame di dati finale dovrebbe così:

Col1 Col2 
1 7197.36 14.00 
2  NA 5173.94 
3  NA 2009.42 
4 7004.38 473.32 
5  NA 6531.06 
6 26355.52 110.05 
7  NA 1307.32 
8  NA 13333.06 
9  NA 3777.65 
10  NA 7827.44 
11 8753.22 85.00 
12  NA  1.86 
13  NA 4980.61 
14  NA 502.89 
15  NA 3182.86 
16  NA  NA 

Qualcuno può aiutarmi?

+0

Aggiornamento della domanda con il frame di dati previsto. – Jay

risposta

2

Ecco un modo utilizzando combinations da gtools(non sarà molto efficace per enormi insiemi di dati)

library(gtools) 
library(zoo) 
library(splitstackshape) 

data$Col1_mod = na.locf(data$Col1) 

df = stack(
    lapply(split(data, f = data$Col1_mod), 
    function(x){ 
     tmp1 = data.frame(
       combinations(
        length(data$Col2[!is.na(data$Col2)]), 
        length(x$Col2[!is.na(x$Col2)]), 
        data$Col2[!is.na(data$Col2)])); 
     tmp1$rowsums = rowSums(tmp1); 
     tmp2 = tmp1[tmp1$rowsums == unique(x$Col1_mod),]; 
     toString(tmp2[,!colnames(tmp2) %in% 'rowsums']) 
    })) 

questo darà

#> df 
#          values  ind 
#1        473.32, 6531.06 7004.38 
#2      14, 2009.42, 5173.94 7197.36 
#3   1.86, 85, 502.89, 3182.86, 4980.61 8753.22 
#4 110.05, 1307.32, 3777.65, 7827.44, 13333.06 26355.52 

si può rimodellare utilizzando cSplit da splitstackshape

out = cSplit(setDT(df), 'values', ',', 'long') 

#>out 
#  values  ind 
#1: 473.32 7004.38 
#2: 6531.06 7004.38 
#3: 14.00 7197.36 
#4: 2009.42 7197.36 
#5: 5173.94 7197.36 
#6:  1.86 8753.22 
#7: 85.00 8753.22 
#8: 502.89 8753.22 
#9: 3182.86 8753.22 
#10: 4980.61 8753.22 
#11: 110.05 26355.52 
#12: 1307.32 26355.52 
#13: 3777.65 26355.52 
#14: 7827.44 26355.52 
#15: 13333.06 26355.52 
+0

Questo probabilmente diventerà un gran casino per un set di dati un po 'più grande. Trovare tutte le combinazioni non è quasi mai una soluzione IMO –

+0

@DavidArenburg sì, sto cercando di renderlo più semplice se possibile. Ma mi è piaciuta la risposta di G.Grothendieck –

7

Lo risolviamo tramite la programmazione lineare di interi risolvendo il problema di trovare il valore obiettivo minimo maggiore o uguale al target e se si trova all'interno di precisione numerica restituirlo; altrimenti, restituisci NULL.

library(lpSolve) 

obj <- na.omit(DF$Col2) 
targets <- na.omit(DF$Col1) 
L <- lapply(targets, function(value) { 
    iobj <- 100 * obj 
    ivalue <- 100 * value 
    res <- lp("min", iobj, t(iobj), ">=", ivalue, all.bin = TRUE) 
    ok <- isTRUE(all.equal(ivalue, res$objval)) 
    if (ok) obj[res$solution == 1] 
}) 
names(L) <- targets 

dando:

> L 

$`7197.36` 
[1] 14.00 5173.94 2009.42 

$`7004.38` 
[1] 473.32 6531.06 

$`26355.52` 
[1] 13333.06 110.05 1307.32 3777.65 7827.44 

$`8753.22` 
[1] 4980.61 85.00 1.86 502.89 3182.86 

Nota 1: In seguito la questione è stato modificato per richiedere questa forma di uscita:

transform(stack(L), Col1 = ifelse(duplicated(ind), NA, as.numeric(paste(ind))), 
        Col2 = values)[3:4] 

Nota 2: Abbiamo usato questo come DF

Lines <- " Col1  Col2 
1 7197.36 14.00 
2  NA 5173.94 
3  NA 13333.06 
4 7004.38 473.32 
5  NA 4980.61 
6 26355.52 110.05 
7  NA 1307.32 
8  NA 6531.06 
9  NA 3777.65 
10  NA 7827.44 
11 8753.22 85.00 
12  NA  1.86 
13  NA 2009.42 
14  NA 502.89 
15  NA 3182.86 
16  NA  NA" 

DF <- read.table(text = Lines, header = TRUE) 
+0

Questa è una soluzione quasi perfetta. Perché 26355.52 non è stato trovato. Come tale, tutti gli elementi per questo valore sono presenti in Col2: $ '26355.52' 110.05 1307.32 13333.06 3777.65 7827.44. – Jay

+0

OK. Buona pesca. Ho risolto. –

+0

Nota 1 fornisce il formato di output richiesto rivisto. –

Problemi correlati