如何在Julia中使用分类数据?

Abh*_*ith 4 julia

如何在Julia中存储分类变量?例如,一个字符串数组["Apple", "Orange", "Banana", "Orange", "Apple", "Banana", "Apple"],是否有任何合适的数据结构将上述数组视为分类类型?例如,在处理DNA序列时,我们需要处理大量不同长度的序列,那么表示和处理这些数据的最有效方法是什么?

Mic*_*gge 5

有一点取决于你想要用它做什么.以下是一些可能有用的常用工具:

稀疏矩阵

我经常使用的一个工具是稀疏矩阵.如果您还不熟悉它们,那么基本的要点是它们是一种有效的存储方式(内存方式)并且使用大量零的(处理速度快)矩阵.当使用分类数据进行大多数统计分析时,即使它是由统计程序"在引擎盖下"完成的,稀疏矩阵也将用于分类变量的上下文中.具体而言,这些操作是将分类变量的每个值表示为数据矩阵中的单独列.对于统计分析,您通常还会将分类变量的一个值作为"基本"状态删除,以避免完美的共线性.

在任何情况下,下面是我为自己写的一个函数,我用它.它会将分类向量转换为稀疏矩阵.该功能有一些选项,你可以通过调整注释掉的部分来修改:

  • 包括矩阵中的所有值或将一个值作为"基本"状态.

  • 输出单独的列名列表,然后可以使用它们创建更大的总数据矩阵.

如果您有多个分类变量,您只需多次使用此函数,然后将最终的Array,DataFrame等拼接在一起.

这是一个"自己动手"的解决方案 - 很可能有一些软件包可以更容易地做你特别想做的事情,但也许不是.这样做的好处是可以为您提供一个非常通用且通用的数据结构,因此可以很容易地将其插入到您可能具有的数学方程式或算法中,从此处指定您的分析.

function OneHot(x::Vector; header::Bool = false, drop::Bool = true)
    UniqueVals = unique(x)  ## note: don't sort this - that will mess up order of vals to idx.  
    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 drop
        StartIdx = 2
    else
        StartIdx = 1
    end
    if header
        return (MySparse[:,StartIdx:end], UniqueVals[StartIdx:end])  ## I.e. gives you back 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[:,StartIdx:end]  ## use MySparse[:, 2:end] to drop a value
    end
end
Run Code Online (Sandbox Code Playgroud)

附加评论:

  • 如果你可以同时使用分类变量和连续变量,那么你可以将它们放在一个稀疏矩阵中,例如 sparse([A B])
  • 如果你要做到这一点,你的连续变量的存储类型Float32,Float64或者什么,那么你不妨改变从功能ones(Int32, length(x))来创建为任何类型的连续数据是的,因为那些只会得到转换成无论如何,当您将稀疏矩阵与连续数据组合在一起时.

PooledDataArray

在"自己动手"方面走向光谱的另一端,PooledDataArrayDataArrays包中有一个类型.使用具有许多重复值的分类变量来存储数据在内存方面更有效.

运行长度编码

另一个有用的工具是运行长度编码.如果你有一个值在一行中多次出现的向量,那么运行长度编码可以是一种更有效的存储和使用它的方法.Julia有一个RLEVectors包(见这里),我相信它的开发者有DNA和基因组学的东西作为他们的原始用例.


Ian*_*all 3

DataStructures 包中的计数器函数可能正是您所需要的。

julia> using DataStructures
julia> a = ["Apple", "Orange", "Banana", "Orange", "Apple",  "Banana", "Apple"]
julia> a_counter = counter(a)
DataStructures.Accumulator{ASCIIString,Int64}(Dict("Apple"=>3,"Orange"=>2,"Banana"=>2))
julia> a_counter["Apple"]
3
Run Code Online (Sandbox Code Playgroud)