我的Rust代码比同等的Python代码长得多,结果是错误的
当转换为锈蚀时,线的数量会增加,类型会发生很多变化,最糟糕的是,结果是错误的!我不确定我是否做错了什么,或者是否有办法优化它: 主要功能是:我的Rust代码比同等的Python代码长得多,结果是错误的,rust,Rust,当转换为锈蚀时,线的数量会增加,类型会发生很多变化,最糟糕的是,结果是错误的!我不确定我是否做错了什么,或者是否有办法优化它: 主要功能是: fn main() { let series = [ 30, 21, 29, 31, 40, 48, 53, 47, 37, 39, 31, 29, 17, 9, 20, 24, 27, 35, 41, 38, 27, 31, 27, 26, 21, 13, 21, 18, 33, 35, 40, 36, 22, 2
fn main() {
let series = [
30, 21, 29, 31, 40, 48, 53, 47, 37, 39, 31, 29, 17, 9, 20, 24, 27, 35, 41, 38, 27, 31, 27,
26, 21, 13, 21, 18, 33, 35, 40, 36, 22, 24, 21, 20, 17, 14, 17, 19, 26, 29, 40, 31, 20, 24,
18, 26, 17, 9, 17, 21, 28, 32, 46, 33, 23, 28, 22, 27, 18, 8, 17, 21, 31, 34, 44, 38, 31,
30, 26, 32,
];
triple_exponential_smoothing(&series, 12, 0.716, 0.029, 0.993, 24);
}
三重指数平滑
调用我测试过的另外两个函数,它们给出了正确的结果:
fn initial_trend(series: &[i32], slen: i32) -> f32 {
let mut sum = 0.0;
for i in 0..slen as usize { // in Python: for i in range(slen)
sum += (series[i + slen as usize] as f32 - series[i] as f32) / slen as f32;
}
return sum / slen as f32;
}
这是Python代码的转换:
def初始趋势(系列,slen):
总和=0.0
对于范围内的i(slen):
总和+=浮点(系列[i+slen]-系列[i])/slen
返回金额/slen
#>>>初始趋势(系列,12)
# -0.7847222222222222
第二个是:
fn initial_seasonal_components(series: &[i32], slen: i32) -> Vec<f32> {
let mut seasonals = Vec::new();
let n_seasons = series.len() as i32 / slen;
// # compute season averages
let season_chunks = series //season_averages
.chunks(slen as usize)
.collect::<Vec<_>>();
let season_averages = season_chunks
.iter()
.map(|chunk| chunk.iter().sum::<i32>() as f32 / chunk.len() as f32)
.collect::<Vec<f32>>();
// # compute initial values
for i in 0..slen as usize {
let mut sum_of_vals_over_avg = 0.0;
for j in 0..n_seasons as usize {
sum_of_vals_over_avg +=
series[i + j * slen as usize] as f32 - season_averages[j] as f32;
}
seasonals.push(sum_of_vals_over_avg / n_seasons as f32);
}
return seasonals;
}
此函数中似乎存在错误:
fn triple_exponential_smoothing(
series: &[i32],
slen: i32,
alpha: f32,
beta: f32,
gamma: f32,
n_preds: i32,
) {
let mut result: Vec<f32> = Vec::new();
let mut seasonals = initial_seasonal_components(&series, slen);
println!("The seasonalities are: {:#?}", seasonals);
let mut smooth = 0.0;
let mut trend = 0.0;
// for i in range(len(series)+n_preds):
for i in 0..(series.len() + n_preds as usize) as usize {
match i {
0 => {
// # initial values
smooth = series[0] as f32;
trend = initial_trend(&series, slen);
println!("The initial_trend is: {:#?}", trend);
result.push(series[0] as f32);
}
i if i >= series.len() => {
// # we are forecasting
let m = i - series.len() + 1;
result.push(
(smooth as usize + m * trend as usize) as f32 + seasonals[i % slen as usize],
)
}
_ => {
let val = series[i];
let last_smooth = smooth;
smooth = alpha * (val as f32 - seasonals[i % slen as usize])
+ (1.0 - alpha) * (smooth + trend);
trend = beta * (smooth - last_smooth) + (1.0 - beta) * trend;
seasonals[i % slen as usize] = gamma * (val as f32 - smooth)
+ (1 - gamma as usize) as f32 * seasonals[i % slen as usize];
result.push(smooth + trend + seasonals[i % slen as usize]);
}
}
}
println!("The forecast is: {:#?}", result);
}
我非常感谢您对优化代码和修复错误的任何评论。在Rust中,您一直在将所有内容转换为
usize
:
(1 - gamma as usize) as f32
如果您考虑这个问题,(1-gamma as usize)
只能是0
或1
,具体取决于gamma
的值。如果改为
(1.0 - gamma) as f32
也会改变
(smooth as usize + m * trend as usize) as f32
到
然后得到与Python中相同的结果
至于性能,这看起来是正确的,但是您可以引入一些临时变量来避免一直重新计算相同的内容(尽管优化器应该会有所帮助)。Rust的默认编译模式是debug,请务必切换到基准版本。我在这里发布了我收到的最佳评论和答案,希望对其他人有用: 尽量减少代码中“as”强制转换的数量(可能减少到零)。进入()/from()并尝试使用\u from()帮助 尝试用迭代器替换一些原始循环 triple_Indonential_smoothing函数的一些参数在调用点很容易混淆,因为Rust当前没有命名参数。为了避免这个问题,您可以尝试在结构/元组中打包一些参数 在函数末尾使用“return”并不是什么惯用法 另外,值得注意的是,在Python中,浮点类型是双浮点,在Rust中是f64。这可能会导致精度上的微小差异,尽管可能没有什么大的差异 替换矿井的功能代码如下所示:
fn main(){
let级数=[
30,21,29,31,40,48,53,47,37,39,31,29,17,9,20,24,27,35,41,38,
27,31,27,26,21,13,21,18,33,35,40,36,22,24,21,20,17,14,17,19,
26,29,40,31,20,24,18,26,17,9,17,21,28,32,46,33,23,28,22,27,
18,8,17,21,31,34,44,38,31,30,26,32];
三重指数平滑(和系列,12,0.716,0.029,0.993,24);
}
fn初始趋势(系列:&[i32],slen:usize)->f32{
series[…slen].iter().zip(&series[slen..)
.map(|)(&a,&b)|(b为f32-a为f32)/slen为f32)。总和:()/slen为f32
}
fn初始季节性组件(系列:&[i32],slen:usize)->Vec{
设n_seasures=series.len()/slen;
//#计算季节平均值
让季节平均值=系列//季节平均值
.区块(slen)
.map(| chunk | chunk.iter().sum::()作为f32/chunk.len()作为f32)
收集::();
//#计算初始值
(0..slen).map(| i |{
设平均值上的值之和=0.0;
对于0..n_季节中的j{
平均值+上的数值之和=系列[i+j*slen]作为f32-季节平均值[j]作为f32;
}
按f32计算的各季平均值之和
}).collect()
}
fn三重指数平滑(系列:&[i32],slen:usize,α:f32,β:f32,
gamma:f32,n_preds:usize){
让mut result:Vec=Vec::new();
设mut季节=初始季节分量(&系列,slen);
println!(“季节性为:{:#?}”,季节性);
让mut平滑=0.0;
让mut趋势=0.0;
对于0中的i..(series.len()+n_preds){
比赛一{
0=>{/#初始值
平滑=系列[0]为f32;
趋势=初始趋势(&系列,slen);
println!(“最初的趋势是:{:},趋势);
结果推送(系列[0]为f32);
},
如果我>=series.len()=>{/#我们正在预测
设m=i-级数.len()+1;
结果。推动((平滑+m为f32*趋势)+季节性[i%slen])
},
_ => {
设val=级数[i];
让最后一个平滑=平滑;
平滑=α*(val为f32-季节性[i%slen])+
(1.0-α)*(平滑+趋势);
趋势=β*(平滑-最后一次平滑)+(1.0-β)*趋势;
季节性[i%slen]=伽马*(val为f32-平滑)+
(1.0-伽马)*季节性[i%slen];
结果:推动(平稳+趋势+季节性[i%slen]);
}
}
}
println!(“预测为:{:#?}”,结果);
}
考虑……的最小方面。。。。这里有大量的代码…当你施放东西时要更加小心。
(smooth + m as f32 * trend)
fn main() {
let series = [
30,21,29,31,40,48,53,47,37,39,31,29,17,9,20,24,27,35,41,38,
27,31,27,26,21,13,21,18,33,35,40,36,22,24,21,20,17,14,17,19,
26,29,40,31,20,24,18,26,17,9,17,21,28,32,46,33,23,28,22,27,
18,8,17,21,31,34,44,38,31,30,26,32];
triple_exponential_smoothing(&series, 12, 0.716, 0.029, 0.993, 24);
}
fn initial_trend(series: &[i32], slen: usize) -> f32 {
series[..slen].iter().zip(&series[slen..])
.map(|(&a, &b)| (b as f32 - a as f32) / slen as f32).sum::<f32>() / slen as f32
}
fn initial_seasonal_components (series: &[i32], slen: usize) -> Vec<f32> {
let n_seasons = series.len() / slen;
// # compute season averages
let season_averages = series //season_averages
.chunks(slen)
.map(|chunk| chunk.iter().sum::<i32>() as f32 / chunk.len() as f32)
.collect::<Vec<f32>>();
// # compute initial values
(0..slen).map(|i| {
let mut sum_of_vals_over_avg = 0.0;
for j in 0..n_seasons {
sum_of_vals_over_avg += series[i + j * slen] as f32 - season_averages[j] as f32;
}
sum_of_vals_over_avg / n_seasons as f32
}).collect()
}
fn triple_exponential_smoothing(series: &[i32], slen: usize, alpha: f32, beta: f32,
gamma: f32, n_preds: usize) {
let mut result: Vec<f32> = Vec::new();
let mut seasonals = initial_seasonal_components(&series, slen);
println!("The seasonalities are: {:#?}", seasonals);
let mut smooth = 0.0;
let mut trend = 0.0;
for i in 0..(series.len() + n_preds) {
match i {
0 => { // # initial values
smooth = series[0] as f32;
trend = initial_trend(&series, slen);
println!("The initial_trend is: {:#?}", trend);
result.push(series[0] as f32);
},
i if i >= series.len() => { // # we are forecasting
let m = i - series.len() + 1;
result.push((smooth + m as f32 * trend) + seasonals[i % slen])
},
_ => {
let val = series[i];
let last_smooth = smooth;
smooth = alpha * (val as f32 - seasonals[i % slen]) +
(1.0 - alpha)*(smooth + trend);
trend = beta * (smooth - last_smooth) + (1.0 - beta) * trend;
seasonals[i % slen] = gamma * (val as f32 - smooth) +
(1.0 - gamma) * seasonals[i % slen];
result.push(smooth + trend + seasonals[i % slen]);
}
}
}
println!("The forecast is: {:#?}", result);
}