我想计算 .txt 文件中特定列的中值,输出该值,并说明该输出值是否正常。我可以执行初始步骤并输出中值,但是不能说明输出值是否在可接受的范围内。
我收到包含以下代码的语法错误消息:
sort -nk9 filename | awk '{a[i++]=$9;} END {x=int((i+1)/2); y=((a[x-1] + a[x])/2); z=(a[x-1]);
if ((y >= 0.5 && y <= 2) || (z >= 0.5 && z <=2));
{if (x < (i+1)/2)
print "Median OR =", y "ALL OK";
else print "Median OR =", z "ALL OK"};
else print "ERROR - OR outside range 0.5 - 2.0"}'
答案1
我想这就是你想要的
awk '{sum+=$9;a[x++]=$9;b[$9]++}b[$9]>Mode{Mode=$9}END{print "Mean: " sum/x "\nMedian: "a[int((x-1)/2)]"\nMode: " Mode}' file
布置得比较整齐
awk '
{
sum+=$9
a[x++]=$9
b[$9]++
}
b[$9]>Mode{Mode=$9}
END{
print "Mean: " sum/x
print "Median: "a[int((x-1)/2)]
print "Mode: " Mode
}' file
另外,我将为比较添加一些逻辑,但我实际上不知道您要比较什么,因为您的变量只是称为 x,y,z 并且可能有也可能没有正确的方程
答案2
我很感激所提供的代码user78605
,因为它指导我如何在查询中找到中位数。然而,上述代码忽略了正确计算中位数所需的某些条件。
问题:
- 不应计算空白尾行(如果它们存在于文件中),因为对它们进行计数会影响数据大小,从而影响平均值、中位数、众数以及其他统计量。对于没有数值的行(id est:
"abc"
、"28b"
、"h2f"
、""
等),很可能应该执行相同的操作。 - 中位数不是原始数据集的中间值,而是有序数据集。也就是说,要找到中位数的数据必须首先排序。
- 如果有序数据集中值的数量是偶数,则必须取中间两个值的平均值。
- 众数是频率最高的值。数据集可能具有不止一种众数,在这种情况下,需要将两个或多个值列为众数。
以下是我对代码的扩展,考虑到上述条件:
awk -F',' '
{col=$1}{if((col ~ /^-?[0-9]*([.][0-9]+)?$/) && ($0!=""))
{
sum+=col;
a[x++]=col;
b[col]++
if(b[col]>hf){hf=b[col]}
}
}
END{n = asort(a);idx=int((x+1)/2)
print "Mean: " sum/x
print "Median: " ((idx==(x+1)/2) ? a[idx] : (a[idx]+a[idx+1])/2)
for (i in b){if(b[i]==hf){(k=="") ? (k=i):(k=k FS i)}{FS=","}}
print "Mode: " k
}' file
解释:
问题 #1 的解决方案:
col=$1
#如果存储在变量中,则更容易更改列。
(col ~ /^-?[0-9]*([.][0-9]+)?$/)
#字符串只能包含数字、句点(小数分隔符)或破折号(减号)。 [仅忽略科学记数法。]
($0!="")
#整行不能为空。
对符合条件的行执行以下循环操作:
sum+=col
#(缩写sum=sum+col
。)所有值的总和。
a[x++]=col
#每个值都存储到一个数组中。
b[col]++
# 中的值col
被视为 array 的代理键b
。因此 中 的元素b
数量与 中唯一值的数量一样多col
。该迭代器创建频率计数数组。 (缩写b[col]=b[col]+1
。)
if(b[col]>hf){hf=b[col]}
#让hf
代表“最高频率”。循环遍历所有频率并hf
仅在找到更高频率时更新。hf
最初是“”(什么也没有)。
问题 #2 的解决方案:
循环操作完成后:
对数组中存储的值进行排序:
值得注意的是,数组的原始索引范围n = asort(a)
a
是从“0”到“x-1”。除了排序之外,新的索引范围是从“1”到“x”。这就是为什么我使用int((x+1)/2)
而不是int((x-1)/2)
作为保存中位数的索引 - 或两个数字中较小的一个,将平均为中位数。
问题 #3 的解决方案:
((idx == (x+1)/2) ? a[idx] : (a[idx]+a[idx+1])/2)
这是 if-else 结构的简写符号:
如果int((x+1)/2)
等于,(x+1)/2
则值的数量为奇数,中位数为a[idx]
。如果不是这样,int()
将向下舍入(x+1)/2
到最接近的整数,表示值的数量是偶数。在这种情况下,a[idx]
和的平均值a[idx]+1
将是中位数。
问题 #4 的解决方案:
for (i in b) {if(b[i]==hf){(k=="") ? (k=i):(k=k FS i)}{FS=","}}
由于hf
是代表数据集中最高频率的值,因此如果 b 的任何值等于hf
,则其代理键是众数,或至少其中一个众数。
此代码连接所有与i
条件匹配的代理键 ,并将它们存储到变量 中,k
该变量可以打印在标题为“Mode”的一行上。
进一步调整:
-F
应根据文件中用作列分隔符的字符进行调整。
如果文件的第一行有标题,请NR > 1
在{col=$1}
.
FS
用于将两个变量连接在一起。FS
当选择不使用分隔符时,使用尤为有用。那是,FS=""
。
数据
以下数据用于实验以创建脚本:
10
20
10
20.5
50
30
40
50
10
30
20.5
-h
h
4.35
-537
0
-0
30
d
.
结果:
Mean: -13.2281
Median: 20.25
Mode: 10,30