Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

The Analysis and Simulation of the Distribution of Amounts by Grabbing WeChat Red Envelopes

STATS 210

May 12th, 2022

I. Introduction

Red envelopes are popular in WeChat paying both for payments and entertainment. Among all kinds of red envelopes, random amount red envelopes are often used in WeChat groups, which means multiple money takers share one envelope offered by the sponsor. This report mainly simulates the distribution of random amounts according to the raw data collected by conducting 105 times of experiments.

II. Task 1: Experiment Process

In order to get the raw data, we cooperated with another group with members Sun Tianji, Sun Tianxuan, Hong Jiayi and Chen Xi. There were seven participants out of us, each of us offered 15 envelopes and each envelope had 5 yuan for 7 money takers. Finally, we got 105 groups of data and each group of data is arranged according to the order of grabbing the envelope.

III. Task 2: Experiment Result & Analysis

We put the 105 groups of data into an excel as below:

 

Figure 1: Screenshot of Part of the Table of Raw Data 

in which the labels in line (1, 2, …, 7) stand for the order to grab the red envelope, 1 is the first one to grab and 7 is the last one to grab; meanwhile the labels in column (1, 2, ...,43, …,105) stand for each experiment. After calculating with the relevant tools in excel, we got the expectations and variances for each number of money takers as follows:

 

1

2

3

4

5

6

7

E(X)

0.6893

0.8015

0.7131

0.6815

0.7436

0.6848

0.7861

Var(X)

0.1592

0.1416

0.1556

0.2083

0.2438

0.3263

0.3083

Table 1: The Expectation and Variance for Each Order of Money Takers 

It shows that the expectations of each number of money takers are different, and it may be caused by the inadequate sample size. The difference of variances shows that for the latter two money takers, there will be higher risk to grab an average amount of money.

Then we drew the histograms according to the raw data by coding in MATLAB. In order to make the calculation and statistics more convenient, each number in excel was rounded. Seven histograms corresponding to the order from 1 to 7 were figured as below:

                                          

                                      

   

Figure 2: Seven Histograms Ordered from 1st to 7th Money Takers

 From these we can see that the curve trend of each graph is high in the middle, low on both sides, and the highest value is in the front of the middle.

IV. Task 3: Mechanism Design & Verification

This section will first describe our assumptions about the WeChat red envelope generation mechanism, and secondly, we will combine our mechanism design with real experimental data to explain why our model is consistent with the experimental results.

a. Mechanism Design

The precondition of the mechanism is the amount in the generated envelopes is based on the remaining gross money and remaining number of money takers at the time of sending the “grab” command. Based on this, we propose the following mechanism to make it fit our experimental data as closely as possible:

The amount of the red envelope generated is uniformly distributed between 0.01 yuan and 2 times of the mean of the remaining envelopes.

We use i to represent the number of current remaining red packets and j represent the total amount remaining in the envelopes. Then, due to the mechanism design, the amount of the next envelope Qij will be uniformly distributed between 0.01 and 2*j/i, which is Qij ~ U(0.01,2*j/i).

In the following, we will numerically verify this mechanism to prove that it can well reflect the distribution of data. However, it is worth pointing out here that there is an apparent inconsistency in this mechanism. Because this mechanism shows that when the remaining money is j and the number of red envelopes is i, the maximum amount of the red envelopes that money takers can draw is 2*j/i. But in our experiment, there are some red greater than 2*j/i. Therefore, our mechanism can explain the distribution of experimental data to a large extent, but it is still different from the mechanism of WeChat red envelopes itself.

b. Verification

To validate our model, we first verify that the theoretical expected values calculated by the mechanism we established agree with the actual values. In the case of state (i, j) (that is, there are i red envelopes and j yuan left), Qij ~ U (0.01, ). Then, we have

* Note: Actually, Q is a discrete variable, but for the convenience of calculation, here we treat it as a continuous variable

Then, we use MATLAB to simulate the real expectation. Under certain states, we use

 

To calculate the expectation under each state.

 

Figure 3: The Comparison between Actual and Theoretical Data of Qij

By plotting the corresponding curves, it can be found that the two curves are very similar, especially when the abscissa is small. The deviation mainly occurs in the area with large abscissa. It is observed that the points in this part of the area are relatively sparse, so it is believed that the main reason for this part of the deviation is that we do not have enough experimental data. Based on this, we can conclude that our mechanism fits to the expectation of the actual red envelope amount well

Secondly, we use MATLAB to check whether the experiment data shows that Qij follows the uniform distribution under each state (i,j). The code in the figure below was used to test and we set the confidence interval to 95%. The results show that among the total 137 data points, a total of 122 groups of data follow the uniform distribution, and only 15 groups of data do not follow the uniform distribution, which indicates that 90% of the data satisfy the uniform distribution. Therefore, it can be seen that the designed mechanism is consistent with the experimental results.

V. Task 4:  Mechanism Simulation & Results Comparison

a. Computer Simulation Using Python Program

In order to check the feasibility of our mechanism, our group wrote a simple python program to simulate the process. We first defined a function redpocket, which takes two doubles—the gross money assigned to all the red pockets and the number of the red pockets as input and returns a list of possible realizations of the process. Based on our mechanism, the amount of money that the nth red pocket can get should be a random number uniformly distributed between 0.01 yuan and 2 times of the remaining average yuan. In order to simulate this distribution, we called the python’s built-in function random.uniform, and generated the amount of money for each pocket according to our mechanism. However, for the last pocket, the amount that it can get is already decided by the previous samples. Therefore, instead of calling the random.uniform function again, we should use the total amount of money in all the pockets to minus the amount that it has already spread in the previous red pockets. After defining the function, we used a for loop to call it for 105 times, which is the same number of tests that we conducted in the group and put the results in the Excel table to draw the graphs. The code is as shown below.

 

Figure 5: Python Simulation Code 

b. Results and Comparison

Compared to our result from the WeChat group test, despite some minor differences, the overall tendency of the variance remains the same–it will become greater for the latter picks. Beside this, most of the groups’ variance had similar values compared to our WeChat Group experiments. To have a more vivid view, the variance of the groups in our simulation compared to the WeChat experiments are shown as below

 

Figure 6(a): Variance of the Wechat Group Experiment

 

Figure 6(b): Variance of the Python Simulation

(Note: From the left to right are the first to the last groups)

On the contrary, we didn’t find a very clear relationship for the mean values, although most of the group’s mean value are about 0.6 to 0.8yuan, which is similar to what we obtained from the WeChat Group experiments, when the order of the sequence is fixed, there is still non negligible differences in value between the two. Also, both our simulation results and experiments results didn’t show a clear trend for how the expectation is developed. For the WeChat Group Experiments, the expectation is maximized at the second and last groups and minimized at the fifth group; while for the simulation, the expectation is maximized at the fourth group, and minimized at the sixth group. Therefore, we can barely draw a simple conclusion on where the expectations’ critical points should be located.

The expectations are shown as below

 

Figure 7(a):Expectations for the WeChat Group Experiments

 

Figure 7(b): Expectations for the Python Simulation

After reflection, we concluded the reasons for this difference in two parts: 1. Both the WeChat group tests and computer simulation did not have a really big amount of database, and only had 105 sets of data for each. 2. It is possible that the money of a red pocket can get beyond 2 times the remaining average, and this situation is not considered in our mechanism.

However, the discrepancy in expectation is not to prove our model to be wrong. From our previous discussion, we know that our mechanism works at least when discussing the variance in the red pockets’ problem. Therefore, to further explore the fitting degree of our mechanism, we used the MATLAB again to draw the distribution of our simulation and compared the histograms to the WeChat Group experiments.

The comparison is made below:

 

WeChat Experiments

Python Simulation

 

 

 

 

Group 1

 

 

 

 

 

 

Group 2

 

 

 

 

 

 

Group 3

 

 

 

 

 

 

Group 4

 

 

 

 

 

 

Group 5

 

 

 

 

 

 

Group 6

 

 

 

 

 

 

Group 7

 

 

Table 2: Comparison Between WeChat Group Experiments and Python Simulation

In general, most of the groups shared similar distributions–even though the maximized and minimized points are not always equal, the distribution trend follows the same pattern for most of the groups. If we just consider the modulation curves, which is the connection between the maximum points for the histograms, this trend seems to be even more obvious. For example, for groups 5,6 and 7, the modulation curve first goes up, and then goes down; while group 1 is flatter, and group two goes down. Those similarities proved that our mechanism works well when it comes to the distribution patterns.

VI. Task 5: Additional Analysis

Based on our theory and the data collected from the WeChat Group experiments, we find that the variance of the money that each person gets shows an increasing trend in the present WeChat’s mechanism, making it an unfair game for the participants. However, this unfairness seems rather hard to be eliminated–it is never possible for us to design a mechanism that can make the game fair when the total amount of money is fixed, since the last red pocket’s money always linearly dependent on the previous ones, and this makes it impossible to let the money have a same distribution for all the people. Therefore, instead of trying to develop a fairer mechanism, what is more meaningful is to find a better strategy for the participants with different goals. In fact, during our experiments, we found a very interesting phenomenon–the latter grabs have much higher probabilities to get higher amounts of money than the earlier grabs! In the computer simulation, the red pockets with an amount of money larger than 1.6 yuan only exists in the last three groups; and in the last group, there even appeared a record of a 2.4-yuan red pocket! Based on this finding, we concluded the strategies as below:

(a) For people who wish to avoid being the unluckiest ones, they should grab the red pockets earlier in the beginning to reduce the variance.

(b) For people who want to take risks to get more money, they can try to grab the red pockets in the end, however, they should also be aware that a higher variance may also lead them to super small red pockets.

VII. Conclusion

In conclusion, we conducted an experiment using WeChat Red Envelope and then simulated the process. The experiment results showed that the order by which one picks up the Red Envelope affects the outcome significantly. The latter the person grabs the envelope, the higher are risks of getting amount of money which is close to average. Ironically, our further analysis showed that grabbing the envelope later can also increase chances of getting large amount of money. After conducting the experiment, we created an algorithm that can replicate the Red Envelope mechanism. We proposed to use uniform distribution as the core of amount generation algorithm. To verify the correctness of our mechanism, we simulated the Red Envelope process in Python, and collected results. Having analyzed and compared simulation results, we came to conclude that our mechanism design matches the real experiment results. Nevertheless, further research is needed into the patterns of mean values of experiment results since there were no particular patterns observed.

Appendix

Division of Work

Yuan Shan: Presentation of Task 3 part + mechanism verification and coding.

Yuhe Fu: Presentation of Task 2 + Task 1&2 coding and plotting.

Gezhi Wang: Presentation of task 4 + Code of simulation (Task 4) and mechanism design.

Jeff Ulmasov: Presentation of Task 1 and conclusion + Conclusion part of report.

Raw Code

Task 3 Mechanism verification

M = csvread('red_envelope.csv');
R = zeros(105,7);
for i = 1:105
    for j = 1:7
        if j == 1
            R(i,j) = 5;
        else
            R(i,j) = R(i,j-1)-M(i,j-1);
        end
    end
end
RR = round(R,1);
num = zeros(7,51,7,51);
for i = 1:105
    for j = 1:6
        %disp(int8(RR(i,j+1)*10));
        num( 8-j, int8(RR(i,j)*10)+1, 8-j-1, int8(RR(i,j+1)*10)+1 ) = ...
        num( 8-j, int8(RR(i,j)*10)+1, 8-j-1, int8(RR(i,j+1)*10)+1 )+1;
    end
end
P_ij = num/105;
%{
for i = 2:7
    for j = 1:51
        for m = 1:51
            if (P_ij(i,j,i-1,m) ~= 0)
                disp("i="+i+" j="+j+" i-1="+(i-1)+" m="+m+" P_ij="+P_ij(i,j,i-1,m));
            end
        end
    end
end
%}
numn = zeros(7,51,51);
pn = zeros(7,51,51);
MM = round(M,1);
%%disp(MM);
for i = 1:105
    for j = 1:7
        %disp(int8(RR(i,j+1)*10));
        numn( 8-j, int8(RR(i,j)*10)+1, min(int8(RR(i,j)*10)+1,int8(MM(i,j)*10)+1)) = ...
        numn( 8-j, int8(RR(i,j)*10)+1, min(int8(RR(i,j)*10)+1,int8(MM(i,j)*10)+1))+1;
    end
end
sumn = zeros(7,51);
for i = 1:7
    for j = 1:51
        for k = 1:51
            sumn(i,j) = sumn(i,j)+ numn(i,j,k);
        end
    end
end

for i = 1:7
    for j = 1:51
        for k = 1:51
            if numn(i,j,k) ~=0
                pn(i,j,k) = numn(i,j,k)/sumn(i,j);
            end
        end
    end
end
%%pn[i][j][k],i represents the remianing envelops, (j-1)/10 is the
%%remaining money and (k-1)/10 is the grabbed money this time.
%{
for i = 1:7
    for j = 1:51
        for m = 1:51
            if (pn(i,j,m) ~= 0)
                disp("i="+i+" j="+j+" m="+m+" Pn="+pn(i,j,m));
            end
        end
    end
end
%}

Exp = zeros(7,51);
x = zeros(1,1000000);
endx = 1;
y = zeros(1,1000000);
endy = 1;
for i = 1:7
    for j = 1:51
        for k = 1:51
            if (pn(i,j,k) ~= 0)
                Exp(i,j) =  Exp(i,j) + (k-1)/10 * pn(i,j,k);
            end
        end
        if (Exp(i,j) ~=0 )
            x(endx) = ((j-1)/10) / i;
            endx = endx+1;
            y(endy) = Exp(i,j);
            endy = endy+1;
        end
    end
end
x = sort(x);
y = sort(y);
plot(x,x)
hold;
plot(x,y);
ylabel("E[Q_ij]");
xlabel("j/i");
legend("Theoretical value","Actual value");
cnt = 0;
cntf = 0;
for i = 1:7
    for j = 1:51
        A = zeros(1,106);
        endA = 1;
        for k = 1:51
            if(numn(i,j,k) ~= 0)
                tmp = numn(i,j,k);
                for p = 1:tmp
                    A(endA) = k;
                    endA = endA+1;
                end
            end
        end
        %%disp("i="+i+" j="+j+" A:"+A);
        if endA>1
            A = A(1:endA);
            A = A.';
            [ahat, bhat] = unifit(A);
            p1 = unifcdf(A, ahat, bhat);
            [h1, s1] = kstest(A, [A, p1], 0.05);
            if h1==0
            %disp('The set of data follows the uniform distribution')
            cnt = cnt+1;
            else
            %disp('The set of data doesn't follow the uniform distribution')
            cntf = cntf+1;
            end
        end
        %}
    end
end
disp("In total there are "+cnt+ " groups of data follow the uniform distribution");
disp("In total there are "+cntf+ " groups of data don't follow the uniform distribution");

Row Data:

M = csvread('reddata.csv');
M = round(M,1);
%%Need to sheld other parts when plot a part, or only the plot of the last
%%part will be printed
A=[];
for i=1:105
    a=M(i,1);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:14
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0.1:0.1:1.4;
y=D;
bar(x,y);

A=[];
for i=1:105
    a=M(i,2);
    A=[A,a];
    i=i+1;
end
B=sort(A);
disp(B)
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:15
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
disp(D)
x=0.1:0.1:1.5;
y=D;
bar(x,y);

A=[];
for i=1:105
    a=M(i,3);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:16
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0.1:0.1:1.7;
y=[D(1:15),0,D(16)];
bar(x,y);
A=[];
for i=1:105
    a=M(i,4);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:19
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:2.0;
y=[D(1:17),0,D(18),0,D(19)];
bar(x,y);
A=[];
for i=1:105
    a=M(i,5);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
disp(C);
D=[];
for j=1:18
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0.1:0.1:2.6;
y=[D(1:14),0,0,D(15),0,D(16:17),0,0,0,0,0,D(18)];
bar(x,y);
A=[];
for i=1:105
    a=M(i,6);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
disp(C);
D=[];
for j=1:22
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:2.7;
y=[D(1:18),0,0,D(19),0,D(20:21),0,0,0,D(22)];
bar(x,y);

A=[];
for i=1:105
    a=M(i,7);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
disp(C);
D=[];
for j=1:22
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:2.6;
y=[D(1:17),0,D(18:19),0,0,0,D(19:20),0,D(21)];
bar(x,y);

Task 4 Comparison

Task 4:

M = csvread('newdata.csv');
M = round(M,1);
A=[];
for i=1:105
    a=M(i,1);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:15
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:1.4;
y=D;
bar(x,y);
%{
A=[];
for i=1:105
    a=M(i,2);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:16
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:1.5;
y=D;
bar(x,y);
A=[];
for i=1:105
    a=M(i,3);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:17
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:1.6;
y=D;
bar(x,y);
A=[];
for i=1:105
    a=M(i,4);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:17
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:1.6;
y=D;
bar(x,y);
A=[];
for i=1:105
    a=M(i,5);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:22
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:2.3;
y=[D(1:19),0,D(20:21),0,D(22)];
bar(x,y);

A=[];
for i=1:105
    a=M(i,6);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:18
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:1.7;
y=D;
bar(x,y);
A=[];
for i=1:105
    a=M(i,7);
    A=[A,a];
    i=i+1;
end
B=sort(A);
C=[B(1)];
for i=1:104
    if B(i)~=B(i+1)
        C=[C,B(i+1)];
    end
end
D=[];
for j=1:21
    cnt=0;
    m=C(j);
    for i=1:105
        if B(i)==m
            cnt = cnt+1;
        else
        end
    end
    D=[D,cnt];
end
x=0:0.1:2.4;
y=[D(1:19),0,0,0,D(20),0,D(21)];
bar(x,y);
%}

Simulation (Task4)

import random

def redpocket(money,number):

    over=[]

    n=number

    k=money

    if money>0 and money<=5:

        for i in range(number):

            if n>1:

                n=n-1

                m=random.uniform(0.01,2*money/(1+n))

                money=money-m

                m=round(m,2)

                over.append(m)

            elif n>0:

                n=n-1

                j=0

                for i in range(len(over)):

                    j+=over[i]

                    j=round(j,2)

                m=k-j

                m=round(m,2)

                over.append(m)

        return over

for i in range(105):

    a=redpocket(5,7)

    print(a)