📦 Questionnaire-Auto-Filling
┣ 📂 src
┃ ┣ 📜 choice_question.py - 单选题、多选题类
┃ ┣ 📜 questionnaire.py - 根据实际问卷生成答案
┃ ┣ 📜 environments.py - 包含问卷链接与Chrome Dirver地址,被.gitignore忽略,需手动重新创建
┃ ┣ 📜 auto_filler.py - 自动填写一份问卷
┃ ┗ 📜 auto_filler_multithreading.py - 使用5个线程填写共100个问卷
┣ 📂 images
┣ 📜 README.md
┣ 📜 .gitignore
┣ 📜 requirements.txt - 项目依赖
-
安装依赖
pip install -r requirements.txt
-
生成
./src/environments.py
定义两个变量——问卷链接
url_survey
和 Chrome Driver 地址binary_path
。例如:
# ./src/environments.py url_survey = 'https://www.wenjuan.com/s/你的问卷地址/' binary_path = 'X:\\XXXXX\\chromedriver-winXX\\chromedriver.exe'
-
根据你的问卷题目修改
./src/questionnaire.py
-
如果只想填写一份问卷,运行
auto_filler.py
python ./src/auto_filler.py
-
如果填写若干份问卷,需要自行设置
auto_filler_multithreading.py
中的线程池数量以及一个worker
的循环数def worker(thread_id): for i in range(20): def main(): max_threads = 5 with concurrent.futures.ThreadPoolExecutor(max_threads) as executor: for thread_id in range(max_threads): executor.submit(worker, thread_id)
python ./src/auto_filler.py
对于若干个选项 A、B、C、D......,它们的得分为连续的正整数。现在给定选项的平均得分与方差,现在需要模拟出一套选项对应的概率。
首先以平均值为众数模拟三角分布算出初步的概率分布,然后需要分别从平均值、方差两个方面进行微调得到最后的概分布
平均值微调忽略
对于方差的微调,我提出了shopkeeper的虹吸算法
,实现在维持平均值不变的情况下调大或者调小方差。以将整体方差调小为例,这个算法就如同虹吸效应一样将远离平均值的概率吸收转移到平均值附近的项目中。
对于一系列连续的正整数
一次虹吸为将位于序列两端的元素
由于一次虹吸中转移的概率相同,所以这种方法称为等量虹吸。
同理,第二次虹吸将
每经过一次虹吸,整体的方差就会缩小。我们可以定义一轮虹吸操作,一步一步地将虹吸的概率转移至平均值附近。每一步虹吸都可以判断当前的方差是否微调至符合要求的范围。以下为伪代码说明。
float dp = 概率微调单元
for (i = 0; i < a - 1 && (n - i) > a; i++){
P[i]-=dp;
p[i+1]+=dp;
p[n-i]-=dp;
p[n-i-1]+=dp;
auto variance = getVariance();
if (variance<= errorPrecision){break;}
}
我们期待的结果是将
然而实际上平均值等于中位数的情况并不常见,因此上面的循环会在当i < a - 1 && (n - i) > a
这个条件不成立时终止。如下图。
经过多轮等量虹吸操作后,概率会累计在
称 虹吸中心
。非等量虹吸的思想是,虹吸中心分别只从一侧进行概率吸取,且吸取的概率所导致的平均值变化互为相反数(可以相互抵消)。考虑特殊情况a-1=0
或a=n
时,虹吸中心落在概率累计函数的边缘,使得某一虹吸中心无法吸取概率的情况,现在设定虹吸中心
虹吸中心不同距离的概率值对平均值的贡献程度,称为贡献值。贡献值与距离成正比。
例如,对于 a-0=a
,而 a-(a-1)=1
。
设对于概率
则虹吸中心
同理,虹吸中心
其中
由此可以得到非等量虹吸的虹吸过程。为了求值方便,假设对于一个虹吸中心,其虹吸的概率对应的概率微调单元
float dp = Pa对应的概率微调单元
float influence=0;
float p_a=0;
for (i = 0; i < a; i++){
P[i]-=dp;
P[a]+=dp;
influence+=dp*(a-i);
}
float dp_a_minus_1 = influence/((1+n-a+1)*(n-a)/2);
for (int i = a;i<=n;i++){
P[i]-=dp_a_minus_1;
P[a-1]+=dp_a_minus_1;
}
在实际操作中,还需要考虑概率必须符合[0,1]之间的限制条件。