如何處理報表中的舍位平衡

在報表的數據統計中,常常會根據精度呈現或者單位換算等要求,需要對數據執行四捨五入的操作,這種操作稱爲舍位處理。簡單直接的舍位處理有可能會帶來隱患,原本平衡的數據關係可能會被打破。

爲了保證報表中數據關係的正確,就需要調整舍位之後的數據,使得數據重新變得平衡,這樣的調整就叫做舍位平衡。在這裏我們就討論一下如何利用集算器來處理舍位平衡問題。

舍位處理往往會採取四捨五入計算,這時就會產生誤差,而如果報表中有這些數據的合計數值,那麼舍位時產生的誤差就會積累,有可能導致舍位過的數據與其合計值無法匹配。例如,保留一位小數的原始的數據是4.5+4.5=9.0,而四捨五入只保留整數部分後,平衡關係就變爲5+5=9了,看上去明顯是荒謬的。在這樣的情況下,需要在保持合計值正確的條件下,調整非合計數據舍位後的結果,使得數據關係重新平衡,例如調整爲4+5=9。這個簡單的例子就是典型舍位平衡。

1. 單向舍位平衡

如果在數據統計時,每個數據只用於一次合計,那麼在處理舍位平衡時,只需要根據合計值的誤差,調整使用的各項數據就可以了,這屬於比較簡單的情況。例如:


A

B

C

1

[1.48,0,1.42,0.32,6.48,0.98,1.39]

=A1.sum()


2

=A1.(round(~))

=round(B1)

=A2.sum()

A1的序列中存儲了一些數據,在B1中計算了它們的合計值,結果如下:

現在,將數據取整,重新統計。A2中將序列中每個數據用round函數四捨五入取整,得到新的序列。在B2中則將B1中的結果取整,這是數據取整後應該獲得的結果。在C2中則只是簡單地用取整後的數據來求和。A2,B2和C2中結果分別如下:

顯然,舍位後誤差的累積導致數據不再平衡,將原始數據分別四捨五入後,總和由12變成了10。那麼,能不能把合計數直接改爲10呢?這是不行的,因爲這樣會使得最終結果與真實值完全不符。因此,爲了保證舍位後仍然能夠保持平衡關係,應該分別改變各個原始數據舍位後的結果。

舍位後總計產生的誤差,稱爲“平衡差”,舍位平衡其實就是消除平衡差的過程。處理舍位平衡的規則有很多,下面我們分別進行研究:

(1) 將平衡差整理到第一個數據中。即:


A

B

C

1

[1.48,0,1.42,0.32,6.48,0.98,1.39]

=A1.sum()


2

=A1.(round(~))

>A2(1)+=round(B1)-A2.sum()

=A2.sum()

B2中,把平衡差折算到舍位後的第一個數據中。整理後,在C2中重新計算了舍位平衡處理後的合計值。A2和C2中的結果如下:

這種舍位平衡的處理規則最爲簡單。但是,舍位後第1個數據由1.48變爲了3,明顯偏移了很多,因此這樣的處理不夠合理,特別是在數據很多的情況下,平衡差也有可能會累積的很大,進而致使第1個數據產生非常荒謬的偏移結果。

(2) 將平衡差按照“最小調整值”,對絕對值比較大的數據進行分擔調整。

所謂最小調整值,就是舍位後最小精度的單位值,例如在取整時,最小精度就是個位,最小調整值就是1或者-1。如果舍位後合計值變小,則需要將數據調大,那麼最小調整值就是1;如果舍位後合計值變大,則需要將數據調小,最小調整值就是-1。而調整隻針對絕對值比較大的數據,這樣它們的相對偏差就會比較小。具體調整幾個數,那就是合計值偏差除以最小調整值。

在這種規則下,前面問題的舍位平衡處理如下:


A

B

C

1

[1.48,0,1.42,0.32,6.48,0.98,1.39]

=A1.sum()


2

=A1.(round(~))

=round(B1)-A2.sum()

=sign(B2)

3

=A1.psort@z(abs(~))

>abs(B2).run(A2(A3(#))+=C2)

=A2.sum()

因爲只是取整操作,因此C2中計算的最小調整值就是合計值偏差的正負;

A3中,根據原始數據的絕對值從大到小做了一個排序,結果就是排序後的序號。

B3是最主要的,因爲只是取整操作,所以B2中的偏差絕對值是多少,就調整幾個數。以此循環,依照原始值的絕對值大小,依次分配最小調整值。

C3是對調整後的A2重新驗證了合計值。

調整後,A2和C3中的結果如下:

在這種方案中,平衡差由多個數據分擔,而選擇絕對值最大的數據會使得數據的相對變動最小。在結果中,1.48舍位後變爲了2,6.48舍位後變爲了7,調整平衡的結果還是比較理想的。

這種方案需要將數據按絕對值排序,執行效率不是很好,特別是在數據量比較大的情況下,排序會耗費較多時間。

(3) 將平衡差按照最小調整值,由不爲0的數據依次分擔。

在上一種調整舍位平衡的方案中,將誤差由絕對值最大的一些數據來分擔。在實際操作中,爲了提高效率,減少排序操作,就可以適當簡化,改爲由順序排在前幾位的數據來分擔。考慮到在四捨五入時,0並不會產生誤差,而且如果修改數據中的0,這樣的變動會比較明顯,因此在調整時將保留原始數據中的0不變。

在這種規則下,前面問題的舍位平衡處理如下:


A

B

C

1

[1.48,0,1.42,0.32,6.48,0.98,1.39]

=A1.sum()


2

=A1.(round(~))

=round(B1)-A2.sum()

=sign(B2)

3

=A2.pselect@a(~!=0)

>abs(B2).run(A2(A3(#))+=C2)

=A2.sum()

A3中選擇出原始數據中非0成員的序號,在B3中調整舍位後數據時,按順序分擔。調整後,A2和C3中的結果如下:

在結果中,1.48舍位後變爲了2,1.42舍位後變爲了2,調整平衡的結果比較合理。同時這種方案避免了排序操作,效率較高,因此這種舍位平衡的規則最爲常用。

 

在處理單向舍位平衡時,並非只有對一組序列求和的情況。更多的情況下,是對一批數據來求和,如下面的SalesRecord.txt中存儲的序表:


Name      Jan  Feb  Mar Apr

Allen      26106     49637     27760     33829

Billy       56611      50588     54765     76072

Charlie    21249     96825     28645     55958

Daisy      3413       49069     6279       98247

Flora       7590       12072     90034     64252


現在,需要統計每位員工4個月的總銷售額,統計時以千元爲單位,並處理舍位平衡。代碼如下:


A

B

C

D

1

=file("SalesRecord.txt").import@t()

=A1.derive(Jan+Feb+Mar+Apr:Sum)

=B1.derive()


2

>5.(C1.field(#+1,C1.field(#+1).(round(~/1000))))

=C1.derive(Jan+Feb+Mar+Apr:Sum2)



3

for B2

>func(A5,A3)



4

=B2.derive(Jan+Feb+Mar+Apr:Sum3)




5

func

=A5.Sum-A5.Sum2

=abs(B5)

=sign(B5)*1

6


for C5

=A5.field(1+B6)

>A5.field(1+B6,C6+D5)

分步執行代碼,A1中讀入序表後,在B1中添加合計字段Sum,結果如下:

在C1中將上面的序表複製,並在B1中將序表中的第2至第6個字段執行舍位計算到以千爲單位。此時,有可能由於四捨五入計算破壞平衡,在B2中再添加一個字段Sum2,計算舍位後4個月的合計值。B2中的序表如下:

可以看到,在此時,Sum與Sum2字段是有區別的,說明需要調整舍位平衡。在這裏雖然需要調整計算後序表中的數據,但是每個數據只用於計算員工合計,因此仍然屬於單向舍位平衡。

A5中的子程序用來處理一條記錄的舍位平衡,B5中計算平衡差,C5中計算出最小調整值。在B6中循環,將平衡差拆分到記錄中前幾個數據中,這裏簡單處理,並未判斷數據是否非零。

在A3中,循環序表B2中的記錄,分別調整舍位平衡。調整完畢後,在A4中再添加Sum3字段來驗證舍位平衡結果,A4中結果如下:

對比Sum與Sum3可以確認,結果調整,數據舍位後重新達成了平衡。

2. 雙向舍位平衡

如果數據在行向和列向兩個方向同時需要計算合計值,同時還需要計算所有數據的總計值,這種情況下處理舍位平衡時就複雜得多了。此時處理舍位平衡時,不僅要求最終的總計值準確,同時行向和列向計算的合計值也要與對應行、列的數據平衡,這種情況下的舍位平衡稱爲雙向舍位平衡。如在SalesRecord.txt的數據中,需要再統計每個月的總銷售額,代碼如下:


A

B

C

1

=file("SalesRecord.txt").import@t()

>A1.insert(0,"Total")

>4.(A1.m(-1).field(#+1,A1.field(#+1).to(,   5).sum()))

2

=A1.derive(Jan+Feb+Mar+Apr:Sum)

=A2.derive()

>5.(B2.field(#+1,B2.field(#+1).(round(~/1000))))

3

=B2.derive(Jan+Feb+Mar+Apr:Sum2)

=A3.derive(Sum2-Sum:Diff)

>B3.insert(0,"Total2")

4

>5.(B3.m(-1).field(#+1, A3.field(#+1).to(,5).sum()))

>B3.insert(0,"Diff")

>5.(B3.m(-1).field(#+1,B3(6).field(#+1)-   B3(7).field(#+1)))

A1中讀入序表,並在B1中添加一條記錄,用來在D1中計算各月總銷售額。再在A2中添加字段計算每位員工的銷售總額,以及總合計值後,結果如下:

在C2中根據上面的彙總數據,將結果舍位到以千元爲單位。再根據舍位後的數據,在A3中添加字段Sum2計算舍位後的員工合計值,在B3中添加字段Diff員工合計的平衡差。最後,再添加2條記錄,分別用來計算每個月的舍位合計值,以及平衡差。計算完成後,B3中結果如下:

可以看到,當橫向和縱向分別做彙總時,舍位後需要解決的平衡問題就複雜得多了。此時修改任何一個舍位數據,都會同時影響橫向和縱向兩個方向的合計計算,這樣的問題稱爲雙向舍位平衡。在上面的計算中,有一些平衡差只與合計值相關,如Total這一行中最右側的平衡差,只與各月的合計有關,這樣的平衡差稱爲合計平衡差。在雙向舍位平衡表中,只存在一橫一縱兩個合計平衡差。其它的平衡差都會和具體數據相關,如Feb這個月最下方的平衡差,這種平衡差稱爲非合計平衡差

 

我們先從一些比較簡單的情況開始研究雙向舍位平衡:

(1)橫向與縱向的非合計平衡差符號相同。如下面的情況:

1.44

1.35

2.79

1.2

0

1.2

2.64

1.35

3.99

上面的表格中,存儲着2行2列的初始數據,同時計算出了各行各列的合計值,以及所有數據的總計值。下面將這些數據四捨五入取整,並計算每一行/列的平衡差,結果如下:

1

1

3

+1

1

0

1


3

1

4


+1




這裏的“非合計平衡差”是指涉及原始數據的平衡差,此時合計數據及總計值都不需要調整。可以看到,此時只是第1行和第1列的合計值不平衡,而且都是合計值比舍位數據的和大1,這種情況下,只需要調整交叉點處的數據,根據平衡差符號加減最小調整值即可。具體操作是把交叉點處,即第1行第1列的數據舍位結果+1,就可獲得平衡,結果如下:

2

1

3

1

0

1

3

1

4

 

(2)同向的2個非合計平衡差符號相反。如下面的情況:

1.44

1.55

2.99

1.2

0.85

2.05

2.64

2.4

5.04

將這些數據四捨五入取整,並計算每一行/列的平衡差,結果如下:

1

2

3


1

1

2


3

2

5


+1

-1



這種情況下,仍然不需要調整總計值。由於第1列和第2列中的平衡差一正一負,只需要任選一行平衡差爲0的數據,將這兩列的數分別根據按平衡差的符號加減最小調整值。如選擇第1行,將第1列的舍位結果+1,將第2列的舍位結果-1,就可獲得平衡,結果如下:

2

1

3

1

1

2

3

2

5

 

(3)某個合計平衡差與另一方向的非合計平衡差符號相反。如下面的情況:

1.44

1.55

2.99

1.2

0.97

2.17

2.64

2.52

5.16

將這些數據四捨五入取整,並計算每一行/列的平衡差,結果如下:

1

2

3


1

1

2


3

3

5

-1

+1




這種情況下,說明交叉點處的合計數據需要調整,只需要調整交叉點處的合計數據,根據合計平衡差的符號加減最小調整值。在這裏,即修改第1列的合計結果,根據橫向的合計平衡差,將其-1,即可獲得平衡,結果如下:

1

2

3

1

1

2

2

3

5

 

(4)某個合計平衡差與同方向的非合計平衡差符號相同。如下面的情況:

1.48

1

2.48

2.11

1.01

3.12

3.59

2.01

5.6

將這些數據四捨五入取整,並計算每一行/列的平衡差,結果如下:

1

1

2


2

1

3


4

2

6


+1


+1


在這裏是列向的合計平衡差與另一列的平衡差符號相同,在這種情況下,可以任選1行平衡差爲0的數據,同時調整這2列的數據。如果選擇第1行,即同時調整第1行第1列,以及第1行的合計值,將它們分別+1即可獲得平衡,結果如下:

2

1

3

2

1

3

4

2

6

 

(5)兩個方向合計平衡差的符號相同。如下面的情況:

1.44

1.99

3.43

1.6

0.48

2.08

3.04

2.47

5.51

將這些數據四捨五入取整,並計算每一行/列的平衡差,結果如下:

1

2

3


2

0

2


3

2

6

+1



+1


此時,只有合計數據影響了結果的平衡。在這種情況下,可以任選一個非合計值,根據合計平衡差的符號加減最小調整值,同樣調整這個數據的橫向和縱向合計值。在上面例子中,可以任意選擇1個數據,如第2行第2列的值,根據平衡差將它+1,同時將第2行以及第2列的合計值同時都+1,這樣就可以獲得平衡,如下:

1

2

3

2

1

3

3

3

6

由於是任選數據,也有其它的處理方式,如選擇第1行第2列的數據修改,同樣可以獲得平衡,結果如下:

1

3

4

2

0

2

3

3

6

 

在處理雙向舍位平衡時,只有上面的5種情況可以調整平衡。對於其它的情況,說明計算有誤,是無法通過1次調整達成舍位平衡的。但是在實際處理中,上面的情況往往是混合出現的。因此,可以先處理第(1)種情況,即所有非合計行列平衡差符號相同的情況,再處理第(2)種情況,將非合計行/列中不同符號的平衡差消除。全部調整理完畢後,非合計行與非合計列的平衡差只能各爲一種符號。此時再處理第(3)種和第(4)種情況,將非合計行/列的平衡差與合計行/列的平衡差配合消除。最後,如果兩個方向行/列的平衡差仍未消除,再按照第(5)中情況處理。這樣,就可以對一般性的表格完成雙向舍位平衡處理了。

再回到這一節開始時的銷售數據表,下面的代碼將處理其中的舍位平衡:


A

B

C

D

E

1

=file("SalesRecord.txt").import@t()

>A1.insert(0,"Total")

>4.(A1.m(-1).field(#+1,A1.field(#+1).to(,   5).sum()))



2

=A1.derive(Jan+Feb+Mar+Apr:Sum)

=A2.derive()

>5.(B2.field(#+1,B2.field(#+1).(round(~/1000))))



3

=B2.derive(Jan+Feb+Mar+Apr:Sum2)

=A3.derive(Sum-Sum2:Diff)

>B3.insert(0,"Total2")



4

>5.(B3.m(-1).field(#+1,A3.field(#+1).to(,5).sum()))

>B3.insert(0,"Diff")

>5.(B3.m(-1).field(#+1,B3(6).field(#+1)-   B3(7).field(#+1)))



5

=B2.len()

=B2.fno()

=B3.(Diff).to(,A5)

=B3.m(-1).array().to(2,B5)


6

for A5-1

for B5-2

for C5(A6)*D5(B6)>0

=sign(C5(A6))

>func(A26,B2(A6),B6+1,D6)

7




>C5(A6)-=D6

>D5(B6)-=D6

8

for A5-2

for A5-1-A8

for C5(A8)*C5(A8+B8)<0

=sign(C5(A8))

=D5.pselect(~==0)

9




>func(A26,B2(A8),E8+1,D8)

>func(A26,B2(A8+B8),E8+1,-D8)

10




>C5(A8)-=D8

>C5(A8+B8)+=D8

11

for B5-3

for B5-2-A11

for D5(A11) * D5(A11+B11) < 0

=sign(D5(A11))

=C5.pselect(~==0)

12




>func(A26,B2(E11),A11+1,D11)

>func(A26,B2(E11),A11+B11+1,-D11)

13




>D5(A11)-=D11

>D5(A11+B11)+=D11

14

if C5(A5)!=0

for B5-2

for C5(A5)*D5(B14)<0

=sign(C5(A5))

>func(A26,B2(A5),B14+1,D14)

15




>C5(A5)-=D14

>D5(B14)+=D14

16

if D5(B5-1)!=0

for A5-1

for C5(B16)*D5(B5-1)<0

=sign(D5(B5-1))

>func(A26,B2(B16),B5,D16)

17




>D5(B5-1)-=D16

>C5(B16)+=D16

18

if C5(A5)!=0

for A5-1

for C5(A5)*C5(B18)>0

=sign(C5(A5))

=D5.pselect(~==0)

19




>func(A26,B2(B18),E18+1,D18)

>func(A26,B2(A5),E18+1,D18)

20




>C5(A5)-=D18

>C5(B18)-=D18

21

if D5(B5-1)!=0

for B5-2

for D5(B21)*D5(B5-1)>0

=sign(D5(B5-1))

=C5.pselect(~==0)

22




>func(A26,B2(E21),B5,D21)

>func(A26,B2(E21),B21+1,D21)

23




>D5(B5-1)-=D21

>D5(B21)-=D21

24

if C5(A5)*D5(B5 -1)>0

>func(A26,B2(1),2,C5(A5))

>func(A26,B2(1),B5,C5(A5))

>func(A26,B2(A5),2,C5(A5))


25


>C5(A5)=0

>D5(B5-1)=0



26

func





27


=A26.field(B26)

>A26.field(B26,B27+C26)



程序比較複雜,下面簡要說明一下功能。A26處的子程序用來修改序表中的1條記錄,將其指定位置的數據加上所需的調整值。由於用於計算的序表中,第一列爲Name,實際並不參與計算,因此整理數據時將其跳過。C5和D5中分別獲得橫向和縱向的平衡差序列。在第6、7行,循環處理第(1)種情況,如果兩個方向的平衡差符號相同,改變交叉點處的舍位結果。在第8~13行,分橫縱兩種情況,處理第(2)種情況,如果同向的兩個平衡差符號相反時,修改這兩行/列中的舍位結果。第14~17行,處理第(3)種情況,當合計平衡差與另一方向的非合計平衡差符號相反時,調整交叉點處的合計結果。在第18~23行,處理第(4)種情況,當合計平衡差與同方向的非合計平衡差符號相同時,修改這兩行/列中的數據。最後,在第24和25行,判斷前面的修改完成後,是否仍然存在兩個合計平衡差,此時相應調整第1個數據的舍位結果,同時調整第1行和第1列的合計值。

雙向舍位平衡處理完成後,在B2中可以查看最終結果:

運算時,處理過程如下:

Name

Jan

Feb

Mar

Apr

Sum

Diff

Allen

26.0

50.0

28.0

34.0

137.0

-1

Billy

57.0

51.0

55.0

76.0

238.0

-1

Charlie

21.0

97.0

29.0

56.0

203.0

0

Daisy

3.0

49.0

6.0

98.0

157.0

1

Flora

8.0

12.0

90.0

64.0

174.0

0

Total

115.0

258.0

207.0

328.0

909.0

1

Diff

0

-1

-1

0

0


執行第(1)步處理,將不同方向上符號相同的非合計平衡差消除後,結果如下:

Name

Jan

Feb

Mar

Apr

Sum

Diff

Allen

26.0

49.0

28.0

34.0

137.0

0

Billy

57.0

51.0

54.0

76.0

238.0

0

Charlie

21.0

97.0

29.0

56.0

203.0

0

Daisy

3.0

49.0

6.0

98.0

157.0

1

Flora

8.0

12.0

90.0

64.0

174.0

0

Total

115.0

258.0

207.0

328.0

909.0

1

Diff

0

0

0

0

0


這個例子中,執行第(1)步處理後,並沒有符號相反的非合計平衡差,不需執行第(2)步處理。在第(3)步處理中,查找合計平衡差是否與另一方向上的非合計平衡差符號相反的情況,同樣不存在。

在第(4)步處理中,查找合計平衡差與同向的非合計平衡差符號相同的情況,處理結果如下:

Name

Jan

Feb

Mar

Apr

Sum

Diff

Allen

26.0

49.0

28.0

34.0

137.0

0

Billy

57.0

51.0

54.0

76.0

238.0

0

Charlie

21.0

97.0

29.0

56.0

203.0

0

Daisy

4.0

49.0

6.0

98.0

157.0

0

Flora

8.0

12.0

90.0

64.0

174.0

0

Total

116.0

258.0

207.0

328.0

909.0

0

Diff

0

0

0

0

0


此時,所有的平衡差已經都變爲了0,說明各個方向上的計算已經恢復平衡,舍位平衡處理完成。如果仍未平衡,則需要進一步執行第(5)步處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章