想知道如何每天计算供应商80%-20%的规则贡献。
Input.csv
Date,Region,Vendor,Amount
5-Apr-15,east,cc,50
5-Apr-15,east,dd,15
5-Apr-15,south,bb,15
5-Apr-15,south,aa,10
7-Apr-15,east,cc,123
7-Apr-15,south,bb,88
7-Apr-15,south,aa,40
7-Apr-15,west,ss,30
7-Apr-15,west,rr,20
在上面的输入中,基于$ 1字段需要填充运行总额金额,然后计算当天金额的运行总和的百分比
Date,Region,Vendor,Amount,RunningSum,%RunningSum
5-Apr-15,east,cc,50,50,56% (RunningSum=50 , %RunningSum=50/90(Total Amount for the day)
5-Apr-15,east,dd,15,65,72% (RunningSum=50+15, %RunningSum=65/90)
5-Apr-15,south,bb,15,80,89% (RunningSum=65+15, %RunningSum=80/90)
5-Apr-15,south,aa,10,90,100% (RunningSum=80+10, %RunningSum=90/90)
一旦得出80%或首次击中80%以上需要考虑为80%贡献剩余的项目需要考虑为20%的贡献。
预期产出:
Date,Countof80%Vendor, SumOf80%Vendor, Countof20%Vendor, SumOf20%Vendor
5-Apr-15,3,80,1,10
7-Apr-15,3,251,2,50
任何建议......
答案 0 :(得分:3)
$ cat tst.awk
BEGIN { FS=OFS="," }
NR==FNR { tot[$1] += $NF; next }
FNR==1 { print $0, "RunningSum", "%RunningSum"; next }
{ sum[$1]+=$NF; print $0, sum[$1], int(0.5+sum[$1]*100/tot[$1])"%" }
$ awk -f tst.awk file file
Date,Region,Vendor,Amount,RunningSum,%RunningSum
5-Apr-15,east,cc,50,50,56%
5-Apr-15,east,dd,15,65,72%
5-Apr-15,south,bb,15,80,89%
5-Apr-15,south,aa,10,90,100%
7-Apr-15,east,cc,123,123,41%
7-Apr-15,south,bb,88,211,70%
7-Apr-15,south,aa,40,251,83%
7-Apr-15,west,ss,30,281,93%
7-Apr-15,west,rr,20,301,100%
我在问题的第一部分提供了上面的答案,但我不知道从Once it is derived 80%
开始的部分是如何与它相关的。在给定相同输入的情况下,您想要输出到另一个文件的其他内容吗?附加到上面的输出?一个不同的脚本?别的什么?
答案 1 :(得分:2)
这在awk
中相对比较复杂,但现在这样做了。
awk -F , '{vals[$1,++nums[$1]]=$4}END{
for(d in nums){
tot=0
for(i=1;i<=nums[d];i++)tot+=vals[d,i]
n=0;s=0
for(i=1;i<=nums[d];i++){
n++;s+=vals[d,i]
if(s>=tot*0.8){s80=s;n80=n;s=0;n=0}
}
printf("%s,%d,%d,%d,%d\n",d,n80,s80,n,s)
}
}' vendors.txt
这会为每个日期创建独立的值列表,并在收集所有数据循环后通过这些列表并计算出80%点的位置。
这假设该文件仅包含数据(没有“Date,Region,Vender ..”标题)。如果你想要一个单行版本用于复制和粘贴,那么它是:
awk -F , '{vals[$1,++nums[$1]]=$4}END{for(d in nums){tot=0;for(i=1;i<=nums[d];i++)tot+=vals[d,i];n=0;s=0;for(i=1;i<=nums[d];i++){n++;s+=vals[d,i];if(s>=tot*0.8){s80=s;n80=n;s=0;n=0}};printf("%s,%d,%d,%d,%d\n",d,n80,s80,n,s)}}' vendors.txt
编辑:如果你想为每个地区分别计算,你只需要将$ 1部分改为$ 1“,”$ 2,以连接日期和地区:
awk -F , '{a=$1","$2;vals[a,++nums[a]]=$4}END{for(d in nums){tot=0;for(i=1;i<=nums[d];i++)tot+=vals[d,i];n=0;s=0;for(i=1;i<=nums[d];i++){n++;s+=vals[d,i];if(s>=tot*0.8){s80=s;n80=n;s=0;n=0}};printf("%s,%d,%d,%d,%d\n",d,n80,s80,n,s)}}' vendors.txt
说实话,不过,我有点不清楚你究竟要用这个衡量什么。例如,构成销售额80%的供应商数量并不是唯一定义的 - 这取决于您对它们进行排序的顺序。如果您先对所有小额销售进行排序,那么您获得的数字将大于排序时的数量。大销量第一。如果您不按任何特定顺序对它们进行排序,您将得到一些中间的东西。如果您想要的是有多少最大的供应商占销售额的80%,那么您需要在计算之前对数组进行排序。
答案 2 :(得分:2)
在日期发生变化时,这是一个awk脚本:
#!/usr/bin/awk -f
BEGIN {
FS=OFS=","
print "Date" OFS "Countof80%Vendor" OFS "SumOf80%Vendor" OFS "Countof20%Vendor" OFS "SumOf20%Vendor"
}
FNR==1 { next } # skip the header
last_1 != $1 && FNR > 2 {
output( a, cnt, tot, last_1 )
cnt = tot = 0
delete( a )
}
{ tot += $4; a[++cnt] = tot; last_1 = $1 }
END { output( a, cnt, tot, last_1 ) }
func output( a, cnt, tot, last_date, perc80, i, runsum ) {
perc80 = .8 * tot
for(i=1; i<=cnt; i++) {
runsum = a[i]
if(runsum >= perc80) {
print last_date OFS i OFS runsum OFS (cnt-i) OFS (tot-runsum)
break
}
}
}
以下是细分:
BEGIN
- 将FS
和OFS
设置为,
,然后打印标题FNR==1
- 跳过标题行last_1 != $1 && FNR > 2
- 只要$1
字段更改值,就可以通过调用函数output
打印出运行总计。然后,清除cnt
,tot
变量并删除数组a
。$4
中的tot
总和。然后设置a[++cnt] = tot
以捕获到目前为止读取的元素数量的索引处的运行总计。最后,在完成所有其他处理后,将last_1
变量重置为$1
。END
- 捕获最终日期分组并使用output
关于函数output
:
perc80
- 计算tot
值的80%标记。a
和i
行走cnt
数组元素。a[i]
的值存入runsum
以明确/减少a[i]
来电if(runsum >= perc80)
打印输出行然后中断。运行此脚本会提供以下输出:
Date,Countof80%Vendor,SumOf80%Vendor,Countof20%Vendor,SumOf20%Vendor
5-Apr-15,3,80,1,10
7-Apr-15,3,251,2,50