如何混合型矩阵转换为数据帧中的朱莉娅承认列类型

如何混合型矩阵转换为数据帧中的朱莉娅承认列类型

问题描述:

DataFrames的一个很好的特性是,它可以存储不同类型的列,它可以“自动识别”出来的,例如:如何混合型矩阵转换为数据帧中的朱莉娅承认列类型

using DataFrames, DataStructures 

df1 = wsv""" 
parName region forType    value 
vol  AL  broadL_highF  3.3055628012 
vol  AL  con_highF   2.1360975151 
vol  AQ  broadL_highF  5.81984502 
vol  AQ  con_highF   8.1462998309 
""" 
typeof(df1[:parName]) 
DataArrays.DataArray{String,1} 
typeof(df1[:value]) 
DataArrays.DataArray{Float64,1} 

当我尝试做不过来达到相同的结果从一开始矩阵(从电子表格导入)I“松”即自动转换:

dataMatrix = [ 
    "parName" "region" "forType"  "value"; 
    "vol"  "AL"  "broadL_highF" 3.3055628012; 
    "vol"  "AL"  "con_highF"  2.1360975151; 
    "vol"  "AQ"  "broadL_highF" 5.81984502; 
    "vol"  "AQ"  "con_highF"  8.1462998309; 
] 
h = [Symbol(c) for c in dataMatrix[1,:]] 
vals = dataMatrix[2:end, :] 
df2 = convert(DataFrame,OrderedDict(zip(h,[vals[:,i] for i in 1:size(vals,2)]))) 

typeof(df2[:parName]) 
DataArrays.DataArray{Any,1} 
typeof(df2[:value]) 
DataArrays.DataArray{Any,1} 

上有SO几个问题关于如何将矩阵转换为数据框(例如DataFrame from Array with Header,Convert Julia array to dataframe),但没有任何答案处理混合类型矩阵的转换。

如何从矩阵自动识别列的类型创建一个数据框? (1)转换df(使用字典或矩阵构造函数..第一个更快)然后应用try-catch进行类型转换(我的原始答案); (2)转换为字符串,然后使用df.inlinetable(丹Getz答案); (3)检查每个元素的类型和列的一致性(Alexander Morley答案)。

这些结果如下:

# second time for compilation.. further times ~ results 
@time toDf1(m) # 0.000946 seconds (336 allocations: 19.811 KiB) 
@time toDf2(m) # 0.000194 seconds (306 allocations: 17.406 KiB) 
@time toDf3(m) # 0.001820 seconds (445 allocations: 35.297 KiB) 

那么,疯狂的是,最有效的解决方案似乎是“倒出来的水”问题缩小到一个已经解决了一个;-)

谢谢你所有的答案。

+0

你为什么不只是保存电子表格中的csv文件并使用CSV.read()加载它?这应该照顾它。 –

+0

@ MichaelK.Borregaard,因为我有一个模型可以加载来自多张工作表的所有设置和数据,并且我希望在每次进行更改时都避免将它们全部导出到CVS。 – Antonello

另一种方法是重用工作解决方案,即将矩阵转换为适合DataFrames使用的字符串。在代码中,这是:

using DataFrames 

dataMatrix = [ 
    "parName" "region" "forType"  "value"; 
    "vol"  "AL"  "broadL_highF" 3.3055628012; 
    "vol"  "AL"  "con_highF"  2.1360975151; 
    "vol"  "AQ"  "broadL_highF" 5.81984502; 
    "vol"  "AQ"  "con_highF"  8.1462998309; 
] 

s = join(
    [join([dataMatrix[i,j] for j in indices(dataMatrix, 2)] 
    , '\t') for i in indices(dataMatrix, 1)], '\n') 

df = DataFrames.inlinetable(s; separator='\t', header=true) 

所得df具有由数据帧猜到其列类型。

无关,但这个答案让我想起how a mathematician boils water joke

+0

我正在使用'writecsv '写一个'IOBuffer',然后''readtable',让它不停地取笑我。这让人想起这一点,但我认为更清洁。 –

+1

@ MichaelK.Borregaard写给IOBuffer也是这个解决方案的第一个版本(但是在摆脱尾随选项卡时,编辑到这个版本让我恼火)。 –

+0

啊 - 无关 - 但你是如何获得'readtable'来接受'IOBuffer'输入的?我可以做'a = IOBuffer(); writecsv(a,dataMatrix); readcsv(take!(a),DataFrame))',但我无法使用'CSV.read'或'readtable'工作。 –

虽然我没有找到一个完整的解决方案,部分之一,是尝试将各列事后转换:

""" 
    convertDf!(df) 

Try to convert each column of the converted df from Any to In64, Float64 or String (in that order).  
""" 
function convertDf!(df) 
    for c in names(df) 
     try 
      df[c] = convert(DataArrays.DataArray{Int64,1},df[c]) 
     catch 
      try 
       df[c] = convert(DataArrays.DataArray{Float64,1},df[c]) 
      catch 
       try 
        df[c] = convert(DataArrays.DataArray{String,1},df[c]) 
       catch 
       end 
      end 
     end 
    end 
end 

尽管肯定不完整的,这是足以让我的需求。

+0

对不起,但这太可怕了:快乐: –

+0

@ MichaelK.Borregaard好..如果你有更好的解决方案...... ;-) – Antonello

+0

@ MichaelK.Borregaard ..还有,如果你告诉我什么是或为什么它是可怕的..我会学习;-) – Antonello

虽然我认为可能有更好的方式去做所有事情,这应该做你想做的事情。

df = DataFrame() 
for (ind,s) in enumerate(Symbol.(dataMatrix[1,:])) # convert first row to symbols and iterate through them. 
    # check all types the same else assign to Any 
    T = typeof(dataMatrix[2,ind]) 
    T = all(typeof.(dataMatrix[2:end,ind]).==T) ? T : Any 
    # convert to type of second element then add to data frame 
    df[s] = T.(dataMatrix[2:end,ind]) 
end 

mat2df(mat) = 
    DataFrame([[mat[2:end,i]...] for i in 1:size(mat,2)], Symbol.(mat[1,:])) 

似乎工作,且比@丹 - 盖茨的答案(至少在这个数据矩阵):)

using DataFrames, BenchmarkTools 

dataMatrix = [ 
    "parName" "region" "forType"  "value"; 
    "vol"  "AL"  "broadL_highF" 3.3055628012; 
    "vol"  "AL"  "con_highF"  2.1360975151; 
    "vol"  "AQ"  "broadL_highF" 5.81984502; 
    "vol"  "AQ"  "con_highF"  8.1462998309; 
] 

mat2df(mat) = 
    DataFrame([[mat[2:end,i]...] for i in 1:size(mat,2)], Symbol.(mat[1,:])) 

function mat2dfDan(mat) 
    s = join([join([dataMatrix[i,j] for j in indices(dataMatrix, 2)], '\t') 
       for i in indices(dataMatrix, 1)],'\n') 

    DataFrames.inlinetable(s; separator='\t', header=true) 
end 

更快 -

julia> @benchmark mat2df(dataMatrix) 

BenchmarkTools.Trial: 
    memory estimate: 5.05 KiB 
    allocs estimate: 75 
    -------------- 
    minimum time:  18.601 μs (0.00% GC) 
    median time:  21.318 μs (0.00% GC) 
    mean time:  31.773 μs (2.50% GC) 
    maximum time:  4.287 ms (95.32% GC) 
    -------------- 
    samples:   10000 
    evals/sample:  1 

julia> @benchmark mat2dfDan(dataMatrix) 

BenchmarkTools.Trial: 
    memory estimate: 17.55 KiB 
    allocs estimate: 318 
    -------------- 
    minimum time:  69.183 μs (0.00% GC) 
    median time:  81.326 μs (0.00% GC) 
    mean time:  90.284 μs (2.97% GC) 
    maximum time:  5.565 ms (93.72% GC) 
    -------------- 
    samples:   10000 
    evals/sample:  1