读取移动平均线前几行的字段
Reading fields in previous lines for moving average
主要问题
在另一个 AWK 程序中递归调用 AWK,然后将输出保存到(数字)变量的正确语法是什么?
我想使用 2/3 变量调用 AWK:
- N -> 可以从 Bash 或容器 AWK 脚本中读取。
- Linenum -> 从容器 AWK 程序中读取
- J -> 我想阅读的字段
这是我的尝试。
容器 AWk 程序:
BEGIN {}
{
...
# Loop in j
...
k=NR
# Call to other instance of AWK
var=(awk -f -v n="$n_steps" linenum=k input-file 'linenum-n {printf "%5.4E", $j}'
...
}
END{}
更一般性问题的背景:
我有一个文件,我想为其计算 n(例如 2280)步的移动平均值。
理想情况下,对于前 n 行,平均值是值 1 到 k,
其中 k <= n.
对于行 k > n,平均值将是最后 n 个值。
我最终会在很多大文件中执行代码,有几列,几千到几百万行,所以我有兴趣尽可能地精简代码。
代码摘录和说明
我尝试开发的代码如下所示:
NR>1
{
# Loop over fields
for (j in columns)
{
# Rows before full moving average is done
if ( <= n )
{
cumsum[j]=cumsum[j]+$j #Cumulative sum
$j=cumsum[j]/ # Average
}
#moving average
if ( > n )
{
k=NR
last[j]=(awk -f -v n="$n_steps" ln=k input-file 'ln-n {printf "%5.4E", $j}') # Obtain value that will get ubstracted from moving average
cumsum[j]=cumsum[j]+$j-last[j] # Cumulative sum adds last step and deleted unwanted value
$j=cumsum[j]/n # Moving average
}
}
}
我的输入文件包含几列。第一列包含行号,其他列包含值。
对于移动平均线的累加和:如果我在行k,我想把它加到累加和上,但也开始减去我第一个值不需要 (k-n)。
我不想为最后的步骤创建一个累加和数组,因为我觉得这会影响性能。我更喜欢直接 select 我想减去的值。
为此,我需要再次调用 AWK(但在不同的线路上)。我尝试在这一行中这样做:
k=NR
last[j]=(awk -f -v n="$n_steps" ln=k input-file 'ln-n {printf "%5.4E", $j}'
我确定此代码不正确。
讨论问题
获取 AWK 正在处理的前一行字段信息的最佳方法是什么?然后可以保存到变量中吗?
是否允许甚至推荐 AWK 的这种递归使用?
如果不是,更新累积和值的最有效方法是什么,以便我获得足够有效的代码?
示例输入和输出
这是输入(第二列)和所需输出(第三列)的示例。我使用 3 作为平均步数 (n)
N VAL AVG_VAL
1 1 1
2 2 1.5
3 3 2
4 4 3
5 5 4
6 6 5
7 7 6
8 8 7
9 9 8
10 10 9
11 11 10
12 12 11
13 13 12
14 14 13
14 15 14
如果你想对单个列进行运行平均,你可以这样做:
BEGIN{n=2280; c=7}
{ s += $c - a[NR%n]; a[NR%n] = $c }
{ print [=10=], s /(NR < n : NR ? n) }
在这里,我们将最后 n
个值存储在一个数组 a
中,并跟踪累积总和 s
。每次我们更新总和时,我们都会先从中删除最后一个值来更正。
如果您想对几列执行此操作,则必须稍微方便地跟踪数组
BEGIN{n=2280; c[0]=7; c[1]=8; c[2]=9}
{ for(i in c) { s[i] += $c[i] - a[n*i + NR%n]; a[n*i + NR%n] = $c[i] } }
{ printf [=11=]
for(i=0;i<length(c);++i) printf OFS (s[i]/(NR < n : NR ? n))
printf ORS
}
但是,您提到您必须添加数百万个条目。这就是它变得有点棘手的地方。当您一点一点地降低精度时(当您添加浮点数时),对很多值求和会引入数字错误。所以在这种情况下,我建议实施 Kahan summation.
对于单列,您将获得:
BEGIN{n=2280; c=7}
{ y = $c - a[NR%n] - k; t = s + y; k = (t - s) - y; s = t; a[NR%n] = $c }
{ print [=12=], s /(NR < n : NR ? n) }
或扩展为:
BEGIN{n=2280; c=7}
{ y = $c - k; t = s + y; k = (t - s) - y; s = t; }
{ y = -a[NR%n] - k; t = s + y; k = (t - s) - y; s = t; }
{ a[NR%n] = $c }
{ print [=13=], s /(NR < n : NR ? n) }
对于多列问题,现在直接调整上面的脚本就可以了。你只需要知道 y
和 t
是临时值, k
是需要存储在内存中的补偿项。
主要问题
在另一个 AWK 程序中递归调用 AWK,然后将输出保存到(数字)变量的正确语法是什么?
我想使用 2/3 变量调用 AWK:
- N -> 可以从 Bash 或容器 AWK 脚本中读取。
- Linenum -> 从容器 AWK 程序中读取
- J -> 我想阅读的字段
这是我的尝试。
容器 AWk 程序:
BEGIN {}
{
...
# Loop in j
...
k=NR
# Call to other instance of AWK
var=(awk -f -v n="$n_steps" linenum=k input-file 'linenum-n {printf "%5.4E", $j}'
...
}
END{}
更一般性问题的背景:
我有一个文件,我想为其计算 n(例如 2280)步的移动平均值。
理想情况下,对于前 n 行,平均值是值 1 到 k, 其中 k <= n.
对于行 k > n,平均值将是最后 n 个值。
我最终会在很多大文件中执行代码,有几列,几千到几百万行,所以我有兴趣尽可能地精简代码。
代码摘录和说明
我尝试开发的代码如下所示:
NR>1
{
# Loop over fields
for (j in columns)
{
# Rows before full moving average is done
if ( <= n )
{
cumsum[j]=cumsum[j]+$j #Cumulative sum
$j=cumsum[j]/ # Average
}
#moving average
if ( > n )
{
k=NR
last[j]=(awk -f -v n="$n_steps" ln=k input-file 'ln-n {printf "%5.4E", $j}') # Obtain value that will get ubstracted from moving average
cumsum[j]=cumsum[j]+$j-last[j] # Cumulative sum adds last step and deleted unwanted value
$j=cumsum[j]/n # Moving average
}
}
}
我的输入文件包含几列。第一列包含行号,其他列包含值。
对于移动平均线的累加和:如果我在行k,我想把它加到累加和上,但也开始减去我第一个值不需要 (k-n)。
我不想为最后的步骤创建一个累加和数组,因为我觉得这会影响性能。我更喜欢直接 select 我想减去的值。
为此,我需要再次调用 AWK(但在不同的线路上)。我尝试在这一行中这样做:
k=NR
last[j]=(awk -f -v n="$n_steps" ln=k input-file 'ln-n {printf "%5.4E", $j}'
我确定此代码不正确。
讨论问题
获取 AWK 正在处理的前一行字段信息的最佳方法是什么?然后可以保存到变量中吗?
是否允许甚至推荐 AWK 的这种递归使用?
如果不是,更新累积和值的最有效方法是什么,以便我获得足够有效的代码?
示例输入和输出
这是输入(第二列)和所需输出(第三列)的示例。我使用 3 作为平均步数 (n)
N VAL AVG_VAL
1 1 1
2 2 1.5
3 3 2
4 4 3
5 5 4
6 6 5
7 7 6
8 8 7
9 9 8
10 10 9
11 11 10
12 12 11
13 13 12
14 14 13
14 15 14
如果你想对单个列进行运行平均,你可以这样做:
BEGIN{n=2280; c=7}
{ s += $c - a[NR%n]; a[NR%n] = $c }
{ print [=10=], s /(NR < n : NR ? n) }
在这里,我们将最后 n
个值存储在一个数组 a
中,并跟踪累积总和 s
。每次我们更新总和时,我们都会先从中删除最后一个值来更正。
如果您想对几列执行此操作,则必须稍微方便地跟踪数组
BEGIN{n=2280; c[0]=7; c[1]=8; c[2]=9}
{ for(i in c) { s[i] += $c[i] - a[n*i + NR%n]; a[n*i + NR%n] = $c[i] } }
{ printf [=11=]
for(i=0;i<length(c);++i) printf OFS (s[i]/(NR < n : NR ? n))
printf ORS
}
但是,您提到您必须添加数百万个条目。这就是它变得有点棘手的地方。当您一点一点地降低精度时(当您添加浮点数时),对很多值求和会引入数字错误。所以在这种情况下,我建议实施 Kahan summation.
对于单列,您将获得:
BEGIN{n=2280; c=7}
{ y = $c - a[NR%n] - k; t = s + y; k = (t - s) - y; s = t; a[NR%n] = $c }
{ print [=12=], s /(NR < n : NR ? n) }
或扩展为:
BEGIN{n=2280; c=7}
{ y = $c - k; t = s + y; k = (t - s) - y; s = t; }
{ y = -a[NR%n] - k; t = s + y; k = (t - s) - y; s = t; }
{ a[NR%n] = $c }
{ print [=13=], s /(NR < n : NR ? n) }
对于多列问题,现在直接调整上面的脚本就可以了。你只需要知道 y
和 t
是临时值, k
是需要存储在内存中的补偿项。