与列表相比 Deedle/Series 慢是正确的吗?
Is it correct that Deedle/Series is slow compared to a list?
我正在开发数据 "intensive" 应用程序,我不确定是否应该使用 Series./DataFrame。这看起来很有趣,但它看起来也比用 List 完成的等效方法慢得多……但我在过滤时可能无法正确使用 Series。
请告诉我你的想法。
谢谢
type TSPoint<'a> =
{
Date : System.DateTime
Value : 'a
}
type TimeSerie<'a> = TSPoint<'a> list
let sd = System.DateTime(1950, 2, 1)
let tsd =[1..100000] |> List.map (fun x -> sd.AddDays(float x))
// creating a List of TSPoint
let tsList = tsd |> List.map (fun x -> {Date = x ; Value = 1.})
// creating the same as a serie
let tsSeries = Series(tsd , [1..100000] |> List.map (fun _ -> 1.))
// function to "randomise" the list of dates
let shuffleG xs = xs |> List.sortBy (fun _ -> Guid.NewGuid())
// new date list to search within out tsList and tsSeries
let d = tsd |> shuffleG |> List.take 1000
// Filter
d |> List.map (fun x -> (tsList |> List.filter (fun y -> y.Date = x)))
d |> List.map (fun x -> (tsSeries |> Series.filter (fun key _ -> key = x)))
这是我得到的:
列表 -> 真实:00:00:04.780,CPU:00:00:04.508,GC gen0:917,gen1:2,gen2:1
系列 -> 真实:00:00:54.386,CPU:00:00:49.311,GC gen0:944,gen1:7,gen2:3
一般来说,Deedle 系列和数据框确实比使用针对给定问题的最有效数据结构编写手工代码有一些额外的开销。有些操作的开销很小,有些操作的开销很大,所以这取决于你想做什么以及你如何使用 Deedle。
如果您按照预期的方式使用 Deedle,那么您将获得良好的性能,但是如果您 运行 大量操作不是特别有效,您可能会表现不佳。
在您的特定情况下,您 运行正在 Series.filter
处理 1000 个系列并创建一个新系列(这是此处幕后发生的事情)确实有一些开销。
但是,您的代码真正做的是使用 Series.filter
查找具有特定键的值。 Deedle 为此提供了一个基于键的查找操作(这是它已经优化的事情之一)。
如果按如下方式重写代码,使用 Deedle 的性能将比使用 list 的性能好得多:
d |> List.map (fun x -> tsSeries.[x])
// 0.001 seconds
d |> List.map (fun x -> (tsSeries |> Series.filter (fun key _ -> key = x)))
// 3.46 seconds
d |> List.map (fun x -> (tsList |> List.filter (fun y -> y.Date = x)))
// 40.5 seconds
我正在开发数据 "intensive" 应用程序,我不确定是否应该使用 Series./DataFrame。这看起来很有趣,但它看起来也比用 List 完成的等效方法慢得多……但我在过滤时可能无法正确使用 Series。 请告诉我你的想法。
谢谢
type TSPoint<'a> =
{
Date : System.DateTime
Value : 'a
}
type TimeSerie<'a> = TSPoint<'a> list
let sd = System.DateTime(1950, 2, 1)
let tsd =[1..100000] |> List.map (fun x -> sd.AddDays(float x))
// creating a List of TSPoint
let tsList = tsd |> List.map (fun x -> {Date = x ; Value = 1.})
// creating the same as a serie
let tsSeries = Series(tsd , [1..100000] |> List.map (fun _ -> 1.))
// function to "randomise" the list of dates
let shuffleG xs = xs |> List.sortBy (fun _ -> Guid.NewGuid())
// new date list to search within out tsList and tsSeries
let d = tsd |> shuffleG |> List.take 1000
// Filter
d |> List.map (fun x -> (tsList |> List.filter (fun y -> y.Date = x)))
d |> List.map (fun x -> (tsSeries |> Series.filter (fun key _ -> key = x)))
这是我得到的:
列表 -> 真实:00:00:04.780,CPU:00:00:04.508,GC gen0:917,gen1:2,gen2:1
系列 -> 真实:00:00:54.386,CPU:00:00:49.311,GC gen0:944,gen1:7,gen2:3
一般来说,Deedle 系列和数据框确实比使用针对给定问题的最有效数据结构编写手工代码有一些额外的开销。有些操作的开销很小,有些操作的开销很大,所以这取决于你想做什么以及你如何使用 Deedle。
如果您按照预期的方式使用 Deedle,那么您将获得良好的性能,但是如果您 运行 大量操作不是特别有效,您可能会表现不佳。
在您的特定情况下,您 运行正在 Series.filter
处理 1000 个系列并创建一个新系列(这是此处幕后发生的事情)确实有一些开销。
但是,您的代码真正做的是使用 Series.filter
查找具有特定键的值。 Deedle 为此提供了一个基于键的查找操作(这是它已经优化的事情之一)。
如果按如下方式重写代码,使用 Deedle 的性能将比使用 list 的性能好得多:
d |> List.map (fun x -> tsSeries.[x])
// 0.001 seconds
d |> List.map (fun x -> (tsSeries |> Series.filter (fun key _ -> key = x)))
// 3.46 seconds
d |> List.map (fun x -> (tsList |> List.filter (fun y -> y.Date = x)))
// 40.5 seconds