2016-06-13 44 views
5

Vorrei creare una matrice di incidenza.
Ho un file con 3 colonne, come:come posso creare una matrice di incidenza in Julia

id x y 
A 22 2 
B 4 21 
C 21 360 
D 26 2 
E 22 58 
F 2 347 

E voglio una matrice simile (senza nomi Col e riga):

2 4 21 22 26 58 347 360 
A 1 0 0 1 0 0 0 0 
B 0 1 1 0 0 0 0 0 
C 0 0 1 0 0 0 0 1 
D 1 0 0 0 1 0 0 0 
E 0 0 0 1 0 1 0 0 
F 1 0 0 0 0 0 1 0 

ho iniziato il codice come:

haps = readdlm("File.txt",header=true)  
hap1_2 = map(Int64,haps[1][:,2:end])  
ID = (haps[1][:,1])      
dic1 = Dict() 

for (i in 1:21) 
    dic1[ID[i]] = hap1_2[i,:] 
end 

X=[zeros(21,22)];  #the original file has 21 rows and 22 columns 
X1 = hcat(ID,X) 

Il problema ora è che non so come riempire la matrice con 1s nelle colonne specifiche come nell'esempio sopra.
Non sono nemmeno sicuro di essere sulla buona strada.

Qualche suggerimento che potrebbe aiutarmi ??

Grazie!

+0

Avete esaminato le funzioni 'ModelFrame()' e 'ModelMatrix()' nel pacchetto DataFrames? Potrebbero avere la funzionalità di cui hai bisogno. Esiste anche la funzione sparse() per la creazione di matrici sparse (che è ciò che stai cercando di creare). Funzionerebbe qui, ma è un po 'più complicato da implementare. –

+1

La colonna identica per x = 2 e y = 2 nella matrice di incidenza è intenzionale? –

+0

È molto meglio per l'inferenza di tipo e l'efficienza mantenere la matrice di incidenza di un singolo tipo specifico, come Int o Bool, e non mescolare le etichette che sono stringhe. –

risposta

2

NamedArrays è un pacchetto ordinato che consente di denominare sia righe che colonne e sembra adattarsi alla bolletta per questo problema. Supponiamo che i dati sono in data.csv, qui è un metodo per andare su di esso (installazione NamedArrays con Pkg.add("NamedArrays")):

data,header = readcsv("data.csv",header=true); 
# get the column names by looking at unique values in columns 
cols = unique(vec([(header[j+1],data[i,j+1]) for i in 1:size(data,1),j=1:2])) 
# row names from ID column 
rows = data[:,1] 

using NamedArrays 
narr = NamedArray(zeros(Int,length(rows),length(cols)),(rows,cols),("id","attr")); 
# now stamp in the 1s in the right places 
for r=1:size(data,1),c=2:size(data,2) narr[data[r,1],(header[c],data[r,c])] = 1 ; end 

ora abbiamo (nota che ho recepito narr per una migliore stampa):

julia> narr' 
10x6 NamedArray{Int64,2}: 
attr ╲ id │ A B C D E F 
──────────┼───────────────── 
("x",22) │ 1 0 0 0 1 0 
("x",4) │ 0 1 0 0 0 0 
("x",21) │ 0 0 1 0 0 0 
("x",26) │ 0 0 0 1 0 0 
("x",2) │ 0 0 0 0 0 1 
("y",2) │ 1 0 0 1 0 0 
("y",21) │ 0 1 0 0 0 0 
("y",360) │ 0 0 1 0 0 0 
("y",58) │ 0 0 0 0 1 0 
("y",347) │ 0 0 0 0 0 1 

Ma , se sono necessari DataFrames, si dovrebbero applicare trucchi simili.

---------- ---------- UPDATE

Nel caso la colonna di un valore deve essere ignorato cioè x = 2 e Y = 2 dovrebbe impostati un 1 su colonna per il valore 2, quindi il codice diventa:

using NamedArrays 
data,header = readcsv("data.csv",header=true); 
rows = data[:,1] 
cols = map(string,sort(unique(vec(data[:,2:end])))) 
narr = NamedArray(zeros(Int,length(rows),length(cols)),(rows,cols),("id","attr")); 
for r=1:size(data,1),c=2:size(data,2) narr[data[r,1],string(data[r,c])] = 1 ; end 

dono:

julia> narr 
6x8 NamedArray{Int64,2}: 
id ╲ attr │ 2 4 21 22 26 58 347 360 
──────────┼─────────────────────────────────────── 
A   │ 1 0 0 1 0 0 0 0 
B   │ 0 1 1 0 0 0 0 0 
C   │ 0 0 1 0 0 0 0 1 
D   │ 1 0 0 0 1 0 0 0 
E   │ 0 0 0 1 0 1 0 0 
F   │ 1 0 0 0 0 0 1 0 
+0

Grazie mille. La versione UPDATE è ciò che cercava. C'è un modo per stampare solo la matrice, senza i nomi di colonna e riga? Grazie! –

+0

NamedArrays è supportato da array regolari, il che significa che è possibile convertirli in una normale Matrix con poco overhead. Usa: 'array (narr)'. –

+0

Puoi anche scegliere di non usare NamedArrays e limitarti a utilizzare le variabili 'rows',' cols' e creare una matrice regolare. Usa 'narr = zeros (Int, length (rows), length (cols)'. L'unico bit difficile è trovare la colonna giusta per archiviare la matrice. Se segui questa strada avrai bisogno di una sorta di tabella di ricerca (o Dict) –

1

Ecco una leggera variazione su qualcosa che io uso per la creazione di matrici sparse di variabili categoriali per le analisi di regressione . La funzione include una varietà di commenti e opzioni per adattarla alle tue esigenze. Nota: come scritto, tratta le apparizioni di "2" e "21" in xey separate. È molto meno elegante nel nominare e nell'apparenza rispetto alla bella risposta di Dan Getz. Il vantaggio principale qui è che funziona con matrici sparse quindi se i tuoi dati sono enormi, questo sarà utile per ridurre lo spazio di archiviazione e il tempo di calcolo.

function OneHot(x::Array, header::Bool) 
    UniqueVals = unique(x) 
    Val_to_Idx = [Val => Idx for (Idx, Val) in enumerate(unique(x))] ## create a dictionary that maps unique values in the input array to column positions in the new sparse matrix. 
    ColIdx = convert(Array{Int64}, [Val_to_Idx[Val] for Val in x]) 
    MySparse = sparse(collect(1:length(x)), ColIdx, ones(Int32, length(x))) 
    if header 
     return [UniqueVals' ; MySparse] ## note: this won't be sparse 
     ## alternatively use return (MySparse, UniqueVals) to get a tuple, second element is the header which you can then feed to something to name the columns or do whatever else with 
    else 
     return MySparse ## use MySparse[:, 2:end] to drop a value (which you would want to do for categorical variables in a regression) 
    end 
end 

x = [22, 4, 21, 26, 22, 2]; 
y = [2, 21, 360, 2, 58, 347]; 

Incidence = [OneHot(x, true) OneHot(y, true)] 

7x10 Array{Int64,2}: 
22 4 21 26 2 2 21 360 58 347 
    1 0 0 0 0 1 0 0 0 0 
    0 1 0 0 0 0 1 0 0 0 
    0 0 1 0 0 0 0 1 0 0 
    0 0 0 1 0 1 0 0 0 0 
    1 0 0 0 0 0 0 0 1 0 
    0 0 0 0 1 0 0 0 0 1 
+0

Grazie per il tuo aiuto L'unico problema è che non vorrei avere valori duplicati nella prima riga (come 2 2) –

+0

@GersonOliveiraJunior Ok, certo, non preoccuparti. Sembra che la soluzione di Dan arrivi più a quello che stai cercando. Questo è solo un frammento di codice che ho avuto da un altro progetto e ho pensato di buttarlo là fuori nel caso fosse utile. –

Problemi correlati