【问题标题】:how can I create an incidence matrix in Julia如何在 Julia 中创建关联矩阵
【发布时间】:2016-06-13 19:43:10
【问题描述】:

我想创建一个关联矩阵。
我有一个包含 3 列的文件,例如:

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

我想要一个类似的矩阵(没有列名和行名):

  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   

我已经开始了这样的代码:

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)

现在的问题是我不知道如何在上面的示例中的特定列中用 1 填充矩阵。
我也不确定我是否走对了。

有什么建议可以帮到我吗?

谢谢!

【问题讨论】:

  • 您是否查看过 DataFrames 包中的 ModelFrame()ModelMatrix() 函数?它们很可能具有您需要的功能。还有用于创建稀疏矩阵的 sparse() 函数(这是您要创建的)。这可以在这里工作,但实现起来有点复杂。
  • 关联矩阵中 x=2 和 y=2 的同一列是故意的吗?
  • 保持单一特定类型(如 Int 或 Bool)的关联矩阵,而不是混入作为字符串的标签,对于类型推断和效率来说要好得多。

标签: matrix julia


【解决方案1】:

NamedArrays 是一个简洁的包,它允许命名行和列,似乎适合这个问题。假设数据在data.csv,这是一种解决方法(安装NamedArraysPkg.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

现在我们有了(注意我转置了narr 以获得更好的打印输出):

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

但是,如果DataFrames 是必要的,则应该应用类似的技巧。

--------- 更新 ----------

如果值的列应被忽略,即 x=2 和 y=2 都应在列上为值 2 设置 1,则代码变为:

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

给予:

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

【讨论】:

  • 非常感谢。 UPDATE 版本正是我们所寻找的。有没有办法只打印矩阵,没有列名和行名?谢谢!
  • NamedArrays 由常规数组支持,这意味着您可以以很少的开销将它们转换为常规矩阵。使用:array(narr).
  • 您也可以选择不使用 NamedArrays,而只使用 rowscols 变量并制作一个常规数组。使用narr = zeros(Int,length(rows),length(cols)。唯一棘手的一点是找到正确的列来归档矩阵。如果你走这条路,你将需要某种查找表(或字典)。
【解决方案2】:

这是我用来从分类变量创建稀疏矩阵以进行回归分析的东西的细微变化。该功能包括各种 cmets 和选项,以满足您的需求。注意:正如所写,它将“2”和“21”在 x 和 y 中的出现视为分开。它在命名和外观上远没有 Dan Getz 的漂亮回应那么优雅。这里的主要优点是它适用于稀疏矩阵,因此如果您的数据很大,这将有助于减少存储空间和计算时间。

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

【讨论】:

  • 感谢您的帮助。唯一的问题是我不想在第一行有重复的值(比如 2 2 )。
  • @GersonOliveiraJunior 好的,当然,不用担心。看起来 Dan 的解决方案更符合您的需求。这只是我从另一个项目中获得的代码片段,我想我会把它扔在那里以防万一它有用。
猜你喜欢
  • 2021-11-20
  • 1970-01-01
  • 2017-04-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多