在上一个问题(Working with heterogenous data in a statically typed language)中,我询问了F#如何处理数据分析中的标准任务,例如操作无类型的CSV文件。动态语言优于基本任务,如
data = load('income.csv')
data.log_income = log(income)
在F#中,最优雅的方法似乎是问号(?)运算符。不幸的是,在这个过程中我们失去了静态类型,并且仍然需要在这里和那里进行类型注释。
F#最令人兴奋的未来特征之一是Type Providers。在类型安全性损失最小的情况下,CSV类型提供程序可以通过动态检查文件来提供类型。
但数据分析通常并不止于此。我们经常通过一系列操作来转换数据并创建新的数据集。我的问题是,如果我们主要操纵数据,类型提供商可以提供帮助吗?例如:
open CSV // Type provider
let data = CSV(file='income.csv') // Type provider magic (syntax?)
let log_income = log(data.income) // works!
这可以工作,但会污染全局命名空间。考虑添加列而不是创建新变量通常更为自然。有办法吗?
let data.logIncome = log(data.income) // won't work, sadly.
当目标是创建新的派生或清理数据集时,类型提供程序是否允许使用(?)运算符?
也许是这样的:
let newdata = colBind data {logIncome = log(data.income)} // ugly, does it work?
其他想法?
答案 0 :(得分:6)
简短的回答是否定的,答案很长(但你不喜欢结果)。要记住的关键是 F#是一种静态类型语言,完全停止。
对于您提供的代码,newData具有哪些类型?如果它无法在编译时固定下来,那么你需要求助于从Obj进行转换。
// newdata MUST have a static type, even if obj
let newdata = colBind data {logIncome = log(data.income)}
想象一下colBind具有以下特征:
val colBind: Thingey<'a> -> 'b -> Thingey2<'a, 'b>
这实际上适用于某种方式,但它不会普遍适用。因为最终你需要一个在编译时不存在的类型。
F#类型提供程序允许您静态类型源自标准编译时环境之外的数据。但是,类型仍然是静态的。没有办法在运行时动态地改变这些类型*。
*您可以使用shenanigans在运行时修改对象 DynamicObject。但是,一旦你 开始走下你失去的道路 静态类型的所有好处 Intellisense等语言。 (这是首先使用F#的主要原因。)
从概念上讲,你想要做的就是直截了当。 System.Data.DataTable类型已经具有存储表格数据的概念,可以动态添加列。但由于在编译时不知道添加列的类型信息,因此必须将存储在这些列中的内容视为Obj并在运行时进行转换。
答案 1 :(得分:0)
或者,您可以创建&#39;来自&#39;和&#39;到&#39;带有表的表,具有所需列的表。这样,您就拥有了类型提供程序使用的静态类型查询和结果模式。