Dataframe 如何在Julia中将IndexedTable转换为数据帧?

Dataframe 如何在Julia中将IndexedTable转换为数据帧?,dataframe,type-conversion,julia,Dataframe,Type Conversion,Julia,在快速解释工作中,IndexedTables处理单个元素(例如选择或“更新”)似乎比DataFrames快得多,但是DataFrames具有更好的功能生态系统,例如绘图、导出 因此,在工作流的某一点上,我想将IndexedTable转换为数据帧,例如 using DataFrames, IndexedTables, IndexedTables.Table tn = Table( Columns( param = String["price","price","pric

在快速解释工作中,
IndexedTables
处理单个元素(例如选择或“更新”)似乎比
DataFrames
快得多,但是
DataFrames
具有更好的功能生态系统,例如绘图、导出

因此,在工作流的某一点上,我想将IndexedTable转换为数据帧,例如

using DataFrames, IndexedTables, IndexedTables.Table

tn = Table(
    Columns(
        param  = String["price","price","price","price","waterContent","waterContent"],
        item   = String["banana","banana","apple","apple","banana", "apple"],
        region = Union{String,DataArrays.NAtype}["FR","UK","FR","UK",NA,NA]
    ),
    Columns(
       value2000 = Float64[2.8,2.7,1.1,0.8,0.2,0.7],
       value2010 = Float64[3.2,2.9,1.2,0.8,0.2,0.8],
    )
)
至>>

至>>

我可以找到各个“行”值在表上与
pair()
交互:

然而,我无法获得列的名称和类型,我想按列工作会更有效率

编辑:我确实用上面的代码获得了“column”类型,现在我只需要获得列名,如果有的话:

colTypes = Union{Union,DataType}[]

for item in tn.index.columns
  push!(colTypes, eltype(item))
end
for item in tn.data.columns
  push!(colTypes, eltype(item))
end
EDIT2:根据要求,这是一个IndexedTable示例,使用(当前)Dan Getz answer无法转换列名,因为“索引”列命名为元组,“数据”列为正常元组:

t_named_idx = Table(
    Columns(
        param  = String["price","price","price","price","waterContent","waterContent"],
        item   = String["banana","banana","apple","apple","banana", "apple"],
        region = Union{String,DataArrays.NAtype}["FR","UK","FR","UK",NA,NA]
    ),
    Columns(
       Float64[2.8,2.7,1.1,0.8,0.2,0.7],
    )
)
问题似乎出现在可索引的API中,特别是在不区分索引和值的
columns(t)
函数中。

丑陋、快速和肮脏的“解决方案”(我希望它在其他方面是可行的):

julia>df=DataFrame(

permutedims(#这里它是编写转换函数的初始附件。它保留列名和类型。如果它可以作为
convert(DataFrame,t::IndexedArray)
在DataFrame或IndexedTable包中进行清理和实现,那就太好了


以下转换功能:

toDataFrame(cols::Tuple, prefix="x") = 
  DataFrame(;(Symbol("$prefix$c") => cols[c] for c in fieldnames(cols))...)

toDataFrame(cols::NamedTuples.NamedTuple, prefix="x") = 
  DataFrame(;(c => cols[c] for c in fieldnames(cols))...)

toDataFrame(t::IndexedTable) = toDataFrame(columns(t))
给出(在问题中定义了
tn
t
的Julia 0.6上):

类型信息大部分被保留:

julia> typeof(df_tn[:,1])
DataArrays.DataArray{String,1}

julia> typeof(df_tn[:,4])
DataArrays.DataArray{Float64,1}
对于未命名列:

julia> t
───────────────────────────────┬─────────
"price"         "apple"   "FR" │ 1.1  1.2
"price"         "apple"   "UK" │ 0.8  0.8
"price"         "banana"  "FR" │ 2.8  3.2
"price"         "banana"  "UK" │ 2.7  2.9
"waterContent"  "apple"   NA   │ 0.7  0.8
"waterContent"  "banana"  NA   │ 0.2  0.2

julia> df_t = toDataFrame(t)
6×5 DataFrames.DataFrame
│ Row │ x1             │ x2       │ x3   │ x4  │ x5  │
├─────┼────────────────┼──────────┼──────┼─────┼─────┤
│ 1   │ "price"        │ "apple"  │ "FR" │ 1.1 │ 1.2 │
│ 2   │ "price"        │ "apple"  │ "UK" │ 0.8 │ 0.8 │
│ 3   │ "price"        │ "banana" │ "FR" │ 2.8 │ 3.2 │
│ 4   │ "price"        │ "banana" │ "UK" │ 2.7 │ 2.9 │
│ 5   │ "waterContent" │ "apple"  │ NA   │ 0.7 │ 0.8 │
│ 6   │ "waterContent" │ "banana" │ NA   │ 0.2 │ 0.2 │
编辑:@Antonello指出,混合命名元组和未命名元组的大小写处理不正确。要正确处理,我们可以定义:

toDataFrame(t::IndexedTable) = 
  hcat(toDataFrame(columns(keys(t)),"y"),toDataFrame(columns(values(t))))
然后,混合情况给出如下结果:

julia> toDataFrame(tn2)
6×5 DataFrames.DataFrame
│ Row │ param          │ item     │ region │ x1  │ x2  │
├─────┼────────────────┼──────────┼────────┼─────┼─────┤
│ 1   │ "price"        │ "apple"  │ "FR"   │ 1.1 │ 1.2 │
│ 2   │ "price"        │ "apple"  │ "UK"   │ 0.8 │ 0.8 │
│ 3   │ "price"        │ "banana" │ "FR"   │ 2.8 │ 3.2 │
│ 4   │ "price"        │ "banana" │ "UK"   │ 2.7 │ 2.9 │
│ 5   │ "waterContent" │ "apple"  │ NA     │ 0.7 │ 0.8 │
│ 6   │ "waterContent" │ "banana" │ NA     │ 0.2 │ 0.2 │

只需安装iTerablables,然后

using IterableTables
df = DataFrames.DataFrame(it)

谢谢..我正在“研究”它..事实上,转换后的df由
任何
列组成,它不存储最终的列名..Dan的解决方案似乎很好。你测试过了吗?如果数据是向量,是否有问题?顺便说一句,我们有可能会有“胶水”请参阅:@Liso Ok,我尝试了一下,Dan Gets的解决方案效果很好(对于大型数据集也是微秒级),除非只有一个{index,data}是一个名为元组的,所有列都被转换为席名。你可以添加一个小的例子,它不与列名一起工作吗?@利索补充说……我的丑陋的解决方案仍然适用于所有情况……但它很丑陋;-(而且丹得到的回答速度慢)它比我的解决方案工作得快(对于大数据集来说,微秒也是如此)显然要优雅得多,但当只有{index,data}中的一个是一个NamedTuple,所有列都被转换成席名字。一般来说,这个答案告诉我们,最好是看一个模块的API,而不是尝试用它的内部来抛出一个对象。我注意到混合命名和非命名元组的问题,事实上,这个解决方案的早期迭代处理得很好。调整了一点来处理它。我来看看。在答案中添加了一个编辑来处理混合的情况。效果很好(除了在那里复制/粘贴似乎是一个感谢。很遗憾,“胶水包”的问题由@Liso链接的问题还没有解决,否则这应该真的解决..摆脱了恼人的不可见字符。很高兴听到IterableTables(和require.jl!),但它只在源代码可还原为命名元组时才会转换。在我的示例中,它可以与
tn
一起使用,但不能(至少在没有初步转换的情况下)使用
t
# NDSparse creation...
content = [["banana","banana","apple","apple","orange"],["us",missing,"us","eu","us"],[1.1,2.2,3.3,missing,5.5]]
dimNames = ["item","region"]
t = NDSparse(content...,names=Symbol.(dimNames))

# NDSparse conversion to df...
names = vcat(keys(keys(t)[1])...,:value)
cols  = columns(t)
df    = DataFrame(map((n,v) -> Pair(n,v), names, cols))
toDataFrame(cols::Tuple, prefix="x") = 
  DataFrame(;(Symbol("$prefix$c") => cols[c] for c in fieldnames(cols))...)

toDataFrame(cols::NamedTuples.NamedTuple, prefix="x") = 
  DataFrame(;(c => cols[c] for c in fieldnames(cols))...)

toDataFrame(t::IndexedTable) = toDataFrame(columns(t))
julia> tn
param           item      region │ value2000  value2010
─────────────────────────────────┼─────────────────────
"price"         "apple"   "FR"   │ 1.1        1.2
"price"         "apple"   "UK"   │ 0.8        0.8
"price"         "banana"  "FR"   │ 2.8        3.2
"price"         "banana"  "UK"   │ 2.7        2.9
"waterContent"  "apple"   NA     │ 0.7        0.8
"waterContent"  "banana"  NA     │ 0.2        0.2

julia> df_tn = toDataFrame(tn)
6×5 DataFrames.DataFrame
│ Row │ param          │ item     │ region │ value2000 │ value2010 │
├─────┼────────────────┼──────────┼────────┼───────────┼───────────┤
│ 1   │ "price"        │ "apple"  │ "FR"   │ 1.1       │ 1.2       │
│ 2   │ "price"        │ "apple"  │ "UK"   │ 0.8       │ 0.8       │
│ 3   │ "price"        │ "banana" │ "FR"   │ 2.8       │ 3.2       │
│ 4   │ "price"        │ "banana" │ "UK"   │ 2.7       │ 2.9       │
│ 5   │ "waterContent" │ "apple"  │ NA     │ 0.7       │ 0.8       │
│ 6   │ "waterContent" │ "banana" │ NA     │ 0.2       │ 0.2       │
julia> typeof(df_tn[:,1])
DataArrays.DataArray{String,1}

julia> typeof(df_tn[:,4])
DataArrays.DataArray{Float64,1}
julia> t
───────────────────────────────┬─────────
"price"         "apple"   "FR" │ 1.1  1.2
"price"         "apple"   "UK" │ 0.8  0.8
"price"         "banana"  "FR" │ 2.8  3.2
"price"         "banana"  "UK" │ 2.7  2.9
"waterContent"  "apple"   NA   │ 0.7  0.8
"waterContent"  "banana"  NA   │ 0.2  0.2

julia> df_t = toDataFrame(t)
6×5 DataFrames.DataFrame
│ Row │ x1             │ x2       │ x3   │ x4  │ x5  │
├─────┼────────────────┼──────────┼──────┼─────┼─────┤
│ 1   │ "price"        │ "apple"  │ "FR" │ 1.1 │ 1.2 │
│ 2   │ "price"        │ "apple"  │ "UK" │ 0.8 │ 0.8 │
│ 3   │ "price"        │ "banana" │ "FR" │ 2.8 │ 3.2 │
│ 4   │ "price"        │ "banana" │ "UK" │ 2.7 │ 2.9 │
│ 5   │ "waterContent" │ "apple"  │ NA   │ 0.7 │ 0.8 │
│ 6   │ "waterContent" │ "banana" │ NA   │ 0.2 │ 0.2 │
toDataFrame(t::IndexedTable) = 
  hcat(toDataFrame(columns(keys(t)),"y"),toDataFrame(columns(values(t))))
julia> toDataFrame(tn2)
6×5 DataFrames.DataFrame
│ Row │ param          │ item     │ region │ x1  │ x2  │
├─────┼────────────────┼──────────┼────────┼─────┼─────┤
│ 1   │ "price"        │ "apple"  │ "FR"   │ 1.1 │ 1.2 │
│ 2   │ "price"        │ "apple"  │ "UK"   │ 0.8 │ 0.8 │
│ 3   │ "price"        │ "banana" │ "FR"   │ 2.8 │ 3.2 │
│ 4   │ "price"        │ "banana" │ "UK"   │ 2.7 │ 2.9 │
│ 5   │ "waterContent" │ "apple"  │ NA     │ 0.7 │ 0.8 │
│ 6   │ "waterContent" │ "banana" │ NA     │ 0.2 │ 0.2 │
using IterableTables
df = DataFrames.DataFrame(it)