Matrix 如何在列类型识别中将混合类型矩阵转换为数据帧

Matrix 如何在列类型识别中将混合类型矩阵转换为数据帧,matrix,dataframe,type-conversion,julia,Matrix,Dataframe,Type Conversion,Julia,DataFrames的一个很好的特性是,它可以存储不同类型的列,并且可以“自动识别”它们,例如: using DataFrames, DataStructures df1 = wsv""" parName region forType value vol AL broadL_highF 3.3055628012 vol AL con_highF 2.1360975151 vol AQ

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}
然而,当我尝试从矩阵(从电子表格导入)开始获得相同的结果时,我“松开”了自动转换:

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}
关于S.O.如何将矩阵转换为数据帧(例如),有几个问题,但没有一个答案涉及混合类型矩阵的转换

如何从自动识别列类型的矩阵创建数据帧

编辑:I:(1)转换df(使用字典或矩阵构造函数..第一个更快),然后应用try-catch进行类型转换(我的原始答案);(2) 转换为字符串,然后使用df.inlinetable(Dan Getz answer);(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)
因此,疯狂的是,最有效的解决方案似乎是“倒水”,并将问题简化为已经解决的问题;-)


感谢您提供的所有答案。

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

"""
    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 

虽然肯定不完整,但足以满足我的需要。

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

"""
    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 

虽然肯定不完整,但它足以满足我的需要。

虽然我认为可能有更好的方法来完成整个过程,但它应该满足你的需要

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

虽然我认为可能有更好的方法来处理整个事情,但这应该是你想要的

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

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

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
的列类型由DataFrame猜测


不相关,但这个答案提醒了我。

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

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
的列类型由DataFrame猜测

不相关,但这个答案让我想起了

似乎有效并且比@dan getz的答案更快(至少对于这个数据矩阵):)

-

似乎有效并且比@dan getz的答案更快(至少对于这个数据矩阵):)

-



为什么不从电子表格中保存一个csv文件并用csv.read()加载它呢?这应该可以解决。@MichaelK.Borregaard,因为我有一个模型,可以加载多个工作表中的所有设置和数据,我希望避免每次更改时都将它们全部导出到cvs。为什么不从电子表格中保存一个csv文件,并使用csv.read()加载它呢?这应该会解决的。@MichaelK.Borregaard因为我有一个模型,可以加载多个工作表中的所有设置和数据,我希望避免每次更改时都将它们导出到cvs。抱歉,这太糟糕了:joy:@MichaelK.Borregaard很好。。如果您有更好的解决方案…;-)@还有,如果你告诉我是什么或者为什么很糟糕。。我要学习;-)只是因为你滥用了try-catch语法。我仍然认为最好是使用CSV.jl这样的包,使用DataFrames中的内置工具以正确的格式导入数据。如何从电子表格导入数据?@MichaelK.Borregaard我开发了这个模块(它使用python
ezodf
模块)。现在,我将Dan Getz的答案集成到了其中,因此我可以将ods表读取为
df=ods\u read(iFile;sheetName=“mySheet”,retType=“DataFrame”)
抱歉,但这太可怕了:joy:@MichaelK.Borregaard well。。如果您有更好的解决方案…;-)@还有,如果你告诉我是什么或者为什么很糟糕。。我要学习;-)只是因为你滥用了try-catch语法。我仍然认为最好是使用CSV.jl这样的包,使用DataFrames中的内置工具以正确的格式导入数据。如何从电子表格导入数据?@MichaelK.Borregaard我开发了这个模块(它使用python
ezodf
模块)。我现在将Dan Getz的答案集成到它上面,这样我就可以把ods表读为
df=ods\u read(iFile;sheetName=“mySheet”,retType=“DataFrame”)
我所玩的解决方案是使用
writecsv
写入
IOBuffer
,然后从中读出来,让它一直在取笑我。这让人想起了这一点,但我认为cleaner.@MichaelK.Borregaard向IOBuffer写入也是这个解决方案的第一个版本(但在去掉尾随标签后编辑成这个版本让我很恼火)。啊-不相关-但是你是如何让
readtable
接受
IOBuffer
输入的?我可以做
a=IOBuffer();writecsv(a,数据矩阵);readcsv(take!(a),DataFrame))
,但我无法让它与
CSV一起工作。请阅读
readtable
。谢谢。只要一个音符。。如果在数据矩阵中可能出现
nothing
值,人们可以使用
s=join([join([(m[i,j]==nothing?NA:m[i,j])在索引(m,2)]中表示j,在索引(m,1)]中表示i,'\t'),'\n')
(时间+10%)来使代码更干净,一个辅助函数沿着这条线
getNA(val)=val==nothing?NA:val
会有帮助的。我所玩弄的解决方案是使用
writecsv
写入
IOBuffer
,然后
readtable
,让它一直在取笑我。这让人想起了这一点,但我认为cleaner.@MichaelK.Borregaard向IOBuffer写入也是这个解决方案的第一个版本(但在去掉尾随标签后编辑成这个版本让我很恼火)。啊-不相关-但是你是如何让
readtable
接受
IOBuffer
输入的?我可以做
a=IOBuffer();writecsv(a,数据矩阵);readcsv(take!(a),数据