-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataFrameExtensionsRolling.cs
More file actions
90 lines (76 loc) · 3.01 KB
/
DataFrameExtensionsRolling.cs
File metadata and controls
90 lines (76 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using System;
using System.Collections.Generic;
using System.Numerics;
using Microsoft.Data.Analysis;
namespace Dimension.DataFrame.Extensions;
/// <summary>
/// Methods for adding rolling calculations extension methods to make Microsoft's DataFrame a little more user-friendly.
/// </summary>
public static class DataFrameExtensionsRolling
{
/// <summary>
/// Applies a function (operation) to a rolling window of a column
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="column"></param>
/// <param name="windowSize"></param>
/// <param name="operation"></param>
/// <returns></returns>
public static PrimitiveDataFrameColumn<T> Rolling<T>(this PrimitiveDataFrameColumn<T> column,
int windowSize,
Func<IEnumerable<T?>, T> operation)
where T : unmanaged, INumber<T>
{
var result = new PrimitiveDataFrameColumn<T>(column.Name + "_Rolling", column.Length);
// Pre-allocate a reusable buffer to avoid repeated allocations
var windowBuffer = new T?[windowSize];
for (var i = 0; i < column.Length; i++)
{
if (i < windowSize - 1)
{
result[i] = null; // Not enough values to fill the window
continue;
}
// Reuse the buffer instead of creating new List
var windowCount = 0;
for (var j = i - windowSize + 1; j <= i; j++)
{
if (column[j].HasValue)
{
windowBuffer[windowCount++] = column[j];
}
}
if (windowCount > 0)
{
// Create a span/array view of only the valid values
var window = new ArraySegment<T?>(windowBuffer, 0, windowCount);
var opResult = operation(window);
result[i] = opResult;
}
else
{
result[i] = null;
}
}
return result;
}
public static RollingWindow<T> Rolling<T>(this PrimitiveDataFrameColumn<T> column, int windowSize)
where T : unmanaged, INumber<T>
{
return new RollingWindow<T>(column, windowSize);
}
public static PrimitiveDataFrameColumn<T> GetRange<T>(this PrimitiveDataFrameColumn<T> column, int startIndex, int count)
where T : unmanaged
{
if (startIndex < 0 || startIndex >= column.Length)
throw new ArgumentOutOfRangeException(nameof(startIndex), "Start index is out of range.");
if (count < 0 || startIndex + count > column.Length)
throw new ArgumentOutOfRangeException(nameof(count), "Count is out of range.");
var result = new PrimitiveDataFrameColumn<T>(column.Name + "_Range", count);
for (int i = 0; i < count; i++)
{
result[i] = column[startIndex + i];
}
return result;
}
}