I would like to use Python3 etc. to test the uniqueness of the paired comparison method, but even if I start such statistics, I can't even read the introductory book without basic knowledge. Also, up to that point (from the actual counting procedure to the completion of the test), I can't find anything that explains it properly. So I hope I can write in this article from the minimum required basic knowledge to the actual calculation method and implementation. I didn't have any pinpoint information on how to actually perform the test from the aggregation, so the purpose is to leave it as a memo for myself.
I also posted it on Github ↓ https://github.com/Iovesophy/paired_comparison_method.git
(Also in Zenn) The first "test of uniqueness in paired comparison method" https://zenn.dev/_kazuya/articles/0e0c95f82cb931
The second "test of consistency in paired comparison method" https://zenn.dev/_kazuya/articles/66ef65022407ef
3rd "Paired comparison method, scaling using Thurston method, plotting (Python3 + Matplotlib)" https://zenn.dev/_kazuya/articles/a1179ed3f6e027
Final "Test of internal consistency in paired comparison method and Thurston method" https://zenn.dev/_kazuya/articles/0ad3de87944785
No matter which processing software you use, I don't think it will have much effect, but this time I used Python3.
Overview of paired comparison method [^ 1]
The ranking method requires all samples to be evaluated and ranked at once in order to measure the strength of sensation and preference. As the number of samples increases, it can be difficult to rank them all at once. In such cases, the two samples are paired and compared. The method of doing this for all pairs is the paired comparison method.
etc..
This time we will deal with the coefficient of uniqueness For example, if there are three samples A, B, and C, and A> B, B> C, then A> C should be. Now, let's actually test whether this is the case.
The following situations can occur when measuring human taste and moderation. For example, when evaluating three samples A, B, and C, if the actual evaluation is performed, A = C or A> C will be evaluated, resulting in a situation where consistent evaluation is not performed. Such a state in which the ranking cannot be assigned among the three parties is called a round triangle.
** A> B, B> C should be A> C, but sometimes A <C. ** **
In other words, ** A should be greater than B (A> B), B should be greater than C (B> C), then A should be greater than C (A> C) **, (I think this will happen even if you think intuitively)
But sometimes A is less than C (A <C).
When the number of samples is n Combine 3 each (A, B, C) When counting the number of round triangles,
If the probability of a round triangle is small enough, each sample can be ranked, In other words, it can be considered that the ranking was unique.
This test method is called a uniqueness test.
In particular,
Consider which of the six samples A to F you like better. The arrows in the figure indicate that A → B prefers B to A.
i>j | |||||||
---|---|---|---|---|---|---|---|
- | 1 | ||||||
1 | - | 1 | |||||
1 | 1 | - | 1 | ||||
1 | 1 | 1 | - | ||||
1 | 1 | 1 | - | 1 | |||
1 | 1 | - |
Also, the numerical value $ 1 $ in the table indicates that, for example, $ A_j $ in the first column and 1 in $ B_i $ in the second row prefer $ B_i $ to $ A_j $. At this time, consider whether it is safe to assume that there is a preferred ranking among the six samples. [^ 2] [^ 3]
(k is the number of samples) If $ k = 6
In the case of $ k = 7
In addition, when
Here, it is important to note when performing this test.
When
Also, it must first be recognized that when
The calculation formula is shown below [^ 2] [^ 3] The number d of round triangles is expressed by the following formula
$ k $ indicates the number of samples and $ a_i $ indicates the total number of votes obtained by sample i (see Table 1).
The degree of freedom $ f $ is expressed by the following formula
The uniqueness coefficient $ \ zeta $ is expressed by the following formula (when $ k $ is an even number)
The uniqueness coefficient $ \ zeta $ is expressed by the following formula (when $ k $ is odd)
The chi-square value is expressed by the following formula
From the chi-square distribution table (Table 2), for example, it is judged whether the judgment of the subject at the significance level of 5% can be said to be consistent.
|Degree of freedom|Significance level.05 |Significance level.01 | | :---: | :---: | :---: | | 1 | 3.841 | 6.635 | | 2 | 5.991 | 9.210 | | 3 | 7.815 | 11.345 | | 4 | 9.488 | 13.277 | | 5 | 11.070 | 15.086 | | 6 | 12.592 | 16.812 | | 7 | 14.067 | 18.475 | | 8 | 15.507 | 20.090 | | 9 | 16.919 | 21.666 | | 10 | 18.307 | 23.209 | | - | - | - | | 11 | 19.675 | 24.725 | | 12 | 21.026 | 26.217 | | 13 | 22.362 | 27.688 | | 14 | 23.685 | 29.141 | | 15 | 24.996 | 30.578 | | 16 | 26.296 | 32.000 | | 17 | 27.587 | 33.409 | | 18 | 28.869 | 34.805 | | 19 | 30.144 | 36.191 | | 20 | 31.410 | 37.566 | | - | - | - | | 21 | 32.671 | 38.932 | | 22 | 33.924 | 40.289 | | 23 | 35.172 | 41.638 | | 24 | 36.415 | 42.980 | | 25 | 37.652 | 44.314 | | 26 | 38.885 | 45.642 | | 27 | 40.113 | 46.963 | | 28 | 41.337 | 48.278 | | 29 | 42.557 | 49.588 | | 30 | 43.773 | 50.892 |
Quote: Takeshi Yamada, Junichiro Murai "Understanding Psychological Statistics" From Appendix 3 [^ 4]
Points to keep in mind when preparing the sample ** k represents the number of samples ** As mentioned above,
When
Also, it must first be recognized that when
When the sample is ready, the sample is verbalized or plotted so that it can be presented as an icon. It is best to make this icon easy for you and the subject to understand, and in the worst case, just arranging the alphabets will function as an icon. (For example, A to F mentioned above) And if one subject makes a paired comparison, it is known that "the judge has no discriminating power" can be rejected at the significance level of 5% when the number of round triangles in Table 3 is $ d $. There is. [^ 5]
k | 5 or less | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|
d | Significance level 5%Does not reach | 1 or less | 3 or less | 7 or less | 14 or less |
less than 10 | 20 | 35 | 56 | 84 |
Quote: "A Study on Paired Comparison Method in AHP Use of Paired Comparison Method in Sensory Test" from Hiroshi Iida
Immediately made "Paired comparison method data processing software, codename PCPS" as an experimental assistance application (hereinafter referred to as PCPS)
Experimental flow
paired_comparison_method/select_main.py
# -*- coding: utf8 -*-
# paired_comparison_method/select_main.py
# made by kazuya yuda.
import time
import datetime
import math
import itertools
import sys
import random
import pandas as pd
import csv
def welcome_mes(): #Message at startup
print("Welcome to paired comparison method experimental tabulation system ver2:2021,1,3")
print("Paired comparison method data processing software, PCPS")
print("made by kazuya yuda.")
def exit_all(): #End processing
sys.exit()
def combinations_count(n, r):
return math.factorial(n) // (math.factorial(n - r) * math.factorial(r))
def initial_data_set(): #Data initialization
data=[] #Data retention in an integrated manner
print("Enter subject information:",end=" ")
data.append(input()) #Store subject's name
print("Remarks:",end=" ")
data.append(input()) #Store remarks about the subject
print("Enter the number of samples:",end=" ")
n = input()
if int(n) < 2:
print("Not enough samples.")
exit_all()
data.append(int(n)) #Store the number of samples
print("%s set" % n)
return data
def material_get(n): #Sample loading
material=[]
print("Do you want to read sample information from csv??y,n:", end=" ")
if input() == n:
for i in range(int(n)):
count = i + 1
print("sample%Enter the information you want to present in d:" % count , end=" ")
material.append(input())
else:
csv_file = open("./sample_info.csv", "r", encoding="utf_8", errors="", newline="" )
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(f)
print(header) #Output header
count = 0
for row in f: #Data read
if count == int(n):
break
else:
count += 1
print(row)
material.append(row[1])
return material
def itertools_make_material(material): #Generation of comparative samples for paired comparison for the number of trials
itertools_material=[]
for i in itertools.permutations(material, r=2):
itertools_material.append(i)
random.shuffle(itertools_material)
return itertools_material
def confirmation(data): #Parameter confirmation phase
print("Check the parameters ↓")
caption = ["subject","Remarks","Number of samples:","sample:","Number of trials:"]
for i in range(5):
print(caption[i],end=' ')
print(data[i])
def start(): #Experiment start processing
print("Do you want to start the experiment? y,n:",end=" ")
if input() == "y":
print("Start the experiment.")
print("Start time:")
print(datetime.datetime.now())
start_time = datetime.datetime.now()
return start_time
else:
print("Suspend,Please start over.")
exit_all()
def process(itertools_material,main_data,count,i,option): #Main interface
print(itertools_material[i])
print("%dth Which sample was selected?:Left → 0,Right → 1,Back → r" % count)
ans = input()
if ans == "r" and i != 0 and option != "final":
print("How many times do you go back?:",end=" ")
count_val = input()
if str.isalpha(count_val):
print("Please enter a number")
l = process(itertools_material,main_data,count,i,option)
else:
count_change = int(count_val)
if count_change <= 0:
print("It cannot exist after the 0th time.")
l = process(itertools_material,main_data,count,i,option)
elif count_change >= count:
print("You can't go back more than the current number.Please request again on the finalize screen.")
l = process(itertools_material,main_data,count,i,option)
else:
i_change = count_change-1
l = process(itertools_material,main_data,count_change,i_change,option)
main_data[i_change]=l
if option == "final":
final_process(itertools_material,main_data,count,i,option)
else:
l = process(itertools_material,main_data,count,i,option)
elif ans == "0" or ans == "1":
l = list(itertools_material[i])
l.append(ans)
else:
print("Please enter the specified number,First time,You can't go back when finalizing.")
l = process(itertools_material,main_data,count,i,option)
return l
def final_process(itertools_material,main_data,countneo,i,option): #Finalize
print("That is all,Are you sure you want to finish?y,n:",end=" ")
ans = input()
if ans == "n" and i != 0 and ans != "0":
print("How many times do you go back?:",end=" ")
count_val = input()
if str.isalpha(count_val):
print("Please enter a number")
l = process(itertools_material,main_data,count,i,option)
else:
count_change = int(count_val)
if count_change <= 0:
print("It cannot exist after the 0th time.")
l = final_process(itertools_material,main_data,countneo,i,option)
elif count_change >= countneo:
print("You can't go back more than the current number.The specified number of times does not exist.")
l = final_process(itertools_material,main_data,countneo,i,option)
else:
option = "final"
i_change = count_change-1
l = process(itertools_material,main_data,count_change,i_change,option)
main_data[i_change]=l
l = final_process(itertools_material,main_data,countneo,i,option)
else:
print("Start the termination process.")
print("* Do not interrupt the program during processing")
return main_data
def process_end(): #End time record
end_time = datetime.datetime.now()
return end_time
def result_export_process(data,integration_data,end_time): #Export in CSV format
print(data[0:])
print(integration_data[0:])
Coulum = ['Comparison data left','Comparison data right','Selection result']
df_info = pd.DataFrame(data)
df_main = pd.DataFrame(integration_data,columns=Coulum)
df_info.to_csv("%s%s%s_result_info.csv" % (data[0],"-",end_time))
df_main.to_csv("%s%s%s_result_main.csv" % (data[0],"-",end_time))
def main(): #Main ops
welcome_mes() #welcome message generation
data = initial_data_set() #Store in data after initial data setting
material = material_get(data[2]) #Store sample information
data.append(material[0:])
N = int(data[2]) #Obtaining the number of samples
try_num = combinations_count(N,2) #Get the number of trials(Calculate combination)
data.append(try_num)
itertools_material = itertools_make_material(material) #Shuffle the sample,take out
confirmation(data) #Parameter confirmation phase
# start
data.append(start())
main_data=[] #For storing experimental data for paired comparison
option="none"
for i in range(try_num): #Iteration for the number of trials
count = i + 1
main_data.append(process(itertools_material,main_data,count,i,option))
#Start finalaize
option="final"
main_data = final_process(itertools_material,main_data,try_num+1,i,option)
integration_data = main_data
# end
end_time = process_end()
data.append(end_time)
# export
result_export_process(data,integration_data,end_time)
if __name__ == "__main__":
main()
Also, make a HID device (PCPS_selector) for PCPS using Arduino Leonardo (Pro Micro).
State to present
PCPS_selector.ino
#include "Keyboard.h"
#define select_left_0 5
#define select_right_1 6
void setup() {
Keyboard.begin();
pinMode(select_left_0, INPUT_PULLUP);
pinMode(select_right_1, INPUT_PULLUP);
}
void loop() {
if(digitalRead(select_left_0) == LOW){
Keyboard.write('0'); //
Keyboard.write('\n');
delay(100);
while(digitalRead(select_left_0) == LOW);
}
if(digitalRead(select_right_1) == LOW){
Keyboard.write('1'); //
Keyboard.write('\n');
delay(100);
while(digitalRead(select_right_1) == LOW);
}
delay(100);
}
Python3 library to use (some need to be installed with pip)
Library import
import time
import datetime
import math
import itertools
import sys
import random
import pandas as pd
import csv
Welcome message display, Here, I think it is good to describe the information you want to display and the confirmation points at the time of the experiment.
def welcome_mes(): #Message at startup
print("Welcome to paired comparison method experimental tabulation system ver2:2021,1,3")
print("Paired comparison method data processing software, PCPS")
print("made by kazuya yuda.")
A subroutine for terminating a program, mainly used to terminate when an error occurs in the parameter confirmation phase.
def exit_all(): #End processing
sys.exit()
Use the math library to calculate combinations to calculate the number of trials
def combinations_count(n, r):
return math.factorial(n) // (math.factorial(n - r) * math.factorial(r))
Initial settings such as inputting subject information and checking the number of samples By the way, it should be absolutely validated, but it is not implemented and will be improved if there is room. (Unit test etc. should also be done)
def initial_data_set(): #Data initialization
data=[] #Data retention in an integrated manner
print("Enter subject information:",end=" ")
data.append(input()) #Store subject's name
print("Remarks:",end=" ")
data.append(input()) #Store remarks about the subject
print("Enter the number of samples:",end=" ")
n = input()
if int(n) < 2:
print("Not enough samples.")
exit_all()
data.append(int(n)) #Store the number of samples
print("%s set" % n)
return data
Read as many samples as there are samples, and if not, generate them. It is also possible to read csv and acquire sample information At that time, it is necessary to prepare sample_info.csv in the same directory. Create a csv with the following contents ↓ (Example: Let's add an alphabetic icon and header of A to F with 6 samples)
sample_info.csv
No,Sample information
1,A
2,B
3,C
4,D
5,E
6,F
Create an array with the name material to store the presented sample icon (will continue to be used)
def material_get(n): #Sample loading
material=[]
print("Do you want to read sample information from csv??y,n:", end=" ")
if input() == n:
for i in range(int(n)):
count = i + 1
print("sample%Enter the information you want to present in d:" % count , end=" ")
material.append(input())
else:
csv_file = open("./sample_info.csv", "r", encoding="utf_8", errors="", newline="" )
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(f)
print(header) #Output header
count = 0
for row in f: #Data read
if count == int(n):
break
else:
count += 1
print(row)
material.append(row[1])
return material
Generation of comparative samples for paired comparison for the number of trials Also, since the sample to be presented needs to be determined randomly, shuffle the material mentioned earlier.
def itertools_make_material(material): #Generation of comparative samples for paired comparison for the number of trials
itertools_material=[]
for i in itertools.permutations(material, r=2):
itertools_material.append(i)
random.shuffle(itertools_material)
return itertools_material
Now that all the settings are complete, we will finally set up a phase to check various parameters and subject information. I refactored it later and summarized the caption, but up to the above all parameter information is in the data array When adding a function, you can basically refer to the data array.
def confirmation(data): #Parameter confirmation phase
print("Check the parameters ↓")
caption = ["subject","Remarks","Number of samples:","sample:","Number of trials:"]
for i in range(5):
print(caption[i],end=' ')
print(data[i])
Experiment start processing, record time as a role After going through the parameter confirmation phase, we also confirm whether it is really okay to start. By the way, if there is an error in the parameter, the process will be terminated once.
def start(): #Experiment start processing
print("Do you want to start the experiment? y,n:",end=" ")
if input() == "y":
print("Start the experiment.")
print("Start time:")
print(datetime.datetime.now())
start_time = datetime.datetime.now()
return start_time
else:
print("Suspend,Please start over.")
exit_all()
Phase of actually presenting and processing data It is also possible to respond when an input error occurs (if you make a HID device, you make a mistake in pressing the subject). This is basically achieved by recursion
def process(itertools_material,main_data,count,i,option): #Main interface
print(itertools_material[i])
print("%dth Which sample was selected?:Left → 0,Right → 1,Back → r" % count)
ans = input()
if ans == "r" and i != 0 and option != "final":
print("How many times do you go back?:",end=" ")
count_val = input()
if str.isalpha(count_val):
print("Please enter a number")
l = process(itertools_material,main_data,count,i,option)
else:
count_change = int(count_val)
if count_change <= 0:
print("It cannot exist after the 0th time.")
l = process(itertools_material,main_data,count,i,option)
elif count_change >= count:
print("You can't go back more than the current number.Please request again on the finalize screen.")
l = process(itertools_material,main_data,count,i,option)
else:
i_change = count_change-1
l = process(itertools_material,main_data,count_change,i_change,option)
main_data[i_change]=l
if option == "final":
final_process(itertools_material,main_data,count,i,option)
else:
l = process(itertools_material,main_data,count,i,option)
elif ans == "0" or ans == "1":
l = list(itertools_material[i])
l.append(ans)
else:
print("Please enter the specified number,First time,You can't go back when finalizing.")
l = process(itertools_material,main_data,count,i,option)
return l
Finalizing process, by the way, the reason why I wrote the phase is that I made a mistake during the last trial during the experiment, the process ended as it was, the end time could not be recorded correctly, and it was necessary to manually correct csv later. This is because the convenience has been significantly impaired. The basics are the same as the subroutine (process) above.
def final_process(itertools_material,main_data,countneo,i,option): #Finalize
print("That is all,Are you sure you want to finish?y,n:",end=" ")
ans = input()
if ans == "n" and i != 0 and ans != "0":
print("How many times do you go back?:",end=" ")
count_val = input()
if str.isalpha(count_val):
print("Please enter a number")
l = process(itertools_material,main_data,count,i,option)
else:
count_change = int(count_val)
if count_change <= 0:
print("It cannot exist after the 0th time.")
l = final_process(itertools_material,main_data,countneo,i,option)
elif count_change >= countneo:
print("You can't go back more than the current number.The specified number of times does not exist.")
l = final_process(itertools_material,main_data,countneo,i,option)
else:
option = "final"
i_change = count_change-1
l = process(itertools_material,main_data,count_change,i_change,option)
main_data[i_change]=l
l = final_process(itertools_material,main_data,countneo,i,option)
else:
print("Start the termination process.")
print("* Do not interrupt the program during processing")
return main_data
End time record
def process_end(): #End time record
end_time = datetime.datetime.now()
return end_time
Output to csv with pandas
def result_export_process(data,integration_data,end_time): #Export in CSV format
print(data[0:])
print(integration_data[0:])
Coulum = ['Comparison data left','Comparison data right','Selection result']
df_info = pd.DataFrame(data)
df_main = pd.DataFrame(integration_data,columns=Coulum)
df_info.to_csv("%s%s%s_result_info.csv" % (data[0],"-",end_time))
df_main.to_csv("%s%s%s_result_main.csv" % (data[0],"-",end_time))
Finally, call various subroutines in main
def main(): #Main ops
welcome_mes() #welcome message generation
data = initial_data_set() #Store in data after initial data setting
material = material_get(data[2]) #Store sample information
data.append(material[0:])
N = int(data[2]) #Obtaining the number of samples
try_num = combinations_count(N,2) #Get the number of trials(Calculate combination)
data.append(try_num)
itertools_material = itertools_make_material(material) #Shuffle the sample,take out
confirmation(data) #Parameter confirmation phase
# start
data.append(start())
main_data=[] #For storing experimental data for paired comparison
option="none"
for i in range(try_num): #Iteration for the number of trials
count = i + 1
main_data.append(process(itertools_material,main_data,count,i,option))
#Start finalaize
option="final"
main_data = final_process(itertools_material,main_data,try_num+1,i,option)
integration_data = main_data
# end
end_time = process_end()
data.append(end_time)
# export
result_export_process(data,integration_data,end_time)
By the way, the iteration of process is processed in main.
option="none"
for i in range(try_num): #Iteration for the number of trials
count = i + 1
main_data.append(process(itertools_material,main_data,count,i,option))
It is very simple to make, and the image of making a keyboard that allows you to enter the numerical values required to select a pair of PCPS presentation samples.
The following numbers are assigned to the selection. Left: 0 Right: 1
I created a device that allows you to enter 0 by pressing the left button and 1 by pressing the right button. It is easier to understand if the buttons are color-coded.
By the way, as a reference, we are the switch science version of Arduino Pro Micro
The following push button switches are available. mxuteuk 12 pcs 1A 250V AC 2 pin SPST 6 color normal open mini instant push button switch PBS-110-6C
See the following page for writing https://www.arduino.cc/en/Guide
PCPS_selector.ino
#include "Keyboard.h"
#define select_left_0 5
#define select_right_1 6
void setup() {
Keyboard.begin();
pinMode(select_left_0, INPUT_PULLUP);
pinMode(select_right_1, INPUT_PULLUP);
}
void loop() {
if(digitalRead(select_left_0) == LOW){
Keyboard.write('0');
Keyboard.write('\n');
delay(100);
while(digitalRead(select_left_0) == LOW);
}
if(digitalRead(select_right_1) == LOW){
Keyboard.write('1');
Keyboard.write('\n');
delay(100);
while(digitalRead(select_right_1) == LOW);
}
delay(100);
}
** Calculate the number of round triangles $ d $ from csv data ** ** Calculate degrees of freedom $ f $ from csv data ** ** Calculate uniqueness coefficient $ \ zeta $ from csv data ** ** Calculate chi-square value $ \ chi_o ^ 2 $ from csv data ** ** Test uniqueness using the calculated $ \ chi_o ^ 2 $ and the chi-square distribution table (Table 2) **
vote_aggregate.py
# -*- coding: utf8 -*-
# paired_comparison_method/vote_aggregate.py
# made by kazuya yuda.
import math
import itertools
import pandas as pd
import csv
import subprocess
import re
import numpy as np
def welcome_mes(): #Message at startup
print("Welcome to paired comparison method vote counting system ver2:2021,1,3")
print("paired comparison method vote data aggregate software, PCVS")
print("made by kazuya yuda.")
def import_csv(): #Sample loading
material=[]
info=[]
#File name confirmation
return_code = subprocess.check_output(['ls'])
code = return_code.split(b"\n")
for i in range(len(code)):
stdout_txt = str(code[i]).replace("b","").replace('\'',"")
if re.search("csv",stdout_txt) and stdout_txt != "sample_info.csv":
print(stdout_txt)
print("Enter the main data file name you want to analyze, including the extension")
filename = input()
print(filename,end=" ")
print("Loaded.")
print("Are you sure you want to start counting?y,n:", end=" ")
ans = input()
if ans == "n":
print("I'm done.")
elif ans == "y":
#Import main file
csv_file = open(filename, "r", encoding="utf_8", errors="", newline="" )
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(f)
#print(header[1:]) #Output header
for row in f: #Data read
#print(row[1:])
material.append(row[1:])
#Import info file
filename2 = filename.replace("main","info")
csv_file = open(filename2, "r", encoding="utf_8", errors="", newline="" )
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(f)
#print(header[1:]) #Output header
for row in f: #Data read
#print(row[1:])
info.append(row[1:])
else:
pass
#Summarize
material_result=['','']
material_result[0] = info
material_result[1] = material
return material_result
def get_k(info):
k = int(str(info[2]).replace("[","").replace("]","").replace("\'",""))
return k
def get_n(info):
n = int(str(info[4]).replace("[","").replace("]","").replace("\'",""))
return n
def f_calculation(info):
k = get_k(info)
k_1 = k * (k-1) * (k-2)
k_2 = (k-4) * (k-4)
f = float(k_1/k_2)
return f
def zeta_calculation(f,d,info):
k = get_k(info)
if k % 2 == 0:
print("Number of samples k: Even")
v_1 = 24*d
v_2 = (k^3) - (4*k)
v_3 = float(v_1/v_2)
zeta = 1 - v_3
else:
print("Number of samples k: Odd")
v_1 = 24*d
v_2 = (k^3) - (k)
v_3 = float(v_1/v_2)
zeta = 1 - v_3
return zeta
def chi_2_0_caluculation(f,d,info):
k = get_k(info)
v_1 = k-4
v_2 = k*(k-1)*(k-2)
v_3 = float(v_2/24)
chi_2_0 = float(8/v_1) * (float(v_3) - float(d) + 0.5) + float(f)
return chi_2_0
def make_vote_list_and_calculation(info,material):
#info to k,n read
k = get_k(info)
n = get_n(info)
#list Create horizontal axis
vote_list = []
for i in range(k+1):
vote_list.append('')
#list Create vertical axis
vote_list_all = []
for i in range(k+1):
vote_list_all.append(vote_list)
#Matrix transformation
vote_list_all_np = np.array(vote_list_all,dtype=object)
#Unnecessary line-Insert(For display)
for i in range(k+1):
vote_list_all_np[i][i] = '-'
#The vertical axis icon is larger than the horizontal axis icon(For display)
vote_list_all_np[0][0] = 'i>j'
#Presentation sample information extraction(For display)
get_icon = info[3]
icon = get_icon[0].replace("[","").replace("]","").replace("\'","").replace("\"","").replace(" ","").split(',')
#Presented sample information set(For display)
count = 0
for send_icon in icon:
vote_list_all_np[0][count+1] = send_icon
vote_list_all_np[count+1][0] = send_icon
count += 1
#Insert vote
for i in range(n):
selector = int(material[i][2])
yoko = icon.index(str(material[i][selector]))
selector2 = 0 if selector == 1 else 1
tate = icon.index(str(material[i][selector2]))
# add 1 point
vote_list_all_np[yoko+1][tate+1] = 1
# add 0 point
vote_list_all_np[tate+1][yoko+1] = 0
#Vote matrix display
print("Voting table")
print(vote_list_all_np)
#Calculation symbol → 0
for i in range(k+1):
vote_list_all_np[i][i] = 0
#Calculation symbol → 0
vote_list_all_np[0][0] = 0
#Presentation sample information for calculation → 0
count = 0
for send_icon in icon:
vote_list_all_np[0][count+1] = 0
vote_list_all_np[count+1][0] = 0
count += 1
vote_sum = np.sum(vote_list_all_np, axis=1)
print("Vote a_i:",end=" ")
print(vote_sum)
print("Vote Σa_i:",end=" ")
print(np.sum(vote_sum))
vote_calc_result = 0
for i in range(k):
vote_calc = vote_sum[i]*(vote_sum[i] - 1)
vote_calc_result += vote_calc
d = float(1/ 6) * float(k) * (float(k)-1.0) * (float(k)-2.0) - 0.5 * float(vote_calc_result)
return d
def main():
welcome_mes()
material = import_csv()
info = material[0]
main = material[1]
d = make_vote_list_and_calculation(info,main)
print("Number of round triangles:",end=" ")
print(d)
f = f_calculation(info)
print("Degrees of freedom f:",end=" ")
print(f)
zeta = zeta_calculation(f,d,info)
print("Uniqueness coefficient ζ:",end=" ")
print(zeta)
chi_2_0 = chi_2_0_caluculation(f,d,info)
print("Chi-square value:",end=" ")
print(chi_2_0)
if __name__ == "__main__":
main()
It will be displayed like this.
By the way, the data in the above figure is generated appropriately by the author to present it as an example. Of course, since the number of d is 1 or more, it can be seen that the answer is not unique.
Import of various libraries
import math
import itertools
import pandas as pd
import csv
import subprocess
import re
import numpy as np
Import csv file I think there is data for the subjects who completed the experiment, so check the data you want to analyze and enter it. At that time, execute the ls command using subprocess so that the csv file name of main can be confirmed. Filter the standard output and extract only the csv file.
def import_csv(): #Sample loading
material=[]
info=[]
#File name confirmation
return_code = subprocess.check_output(['ls'])
code = return_code.split(b"\n")
for i in range(len(code)):
stdout_txt = str(code[i]).replace("b","").replace('\'',"")
if re.search("csv",stdout_txt) and stdout_txt != "sample_info.csv":
print(stdout_txt)
print("Enter the main data file name you want to analyze, including the extension")
filename = input()
print(filename,end=" ")
print("Loaded.")
print("Are you sure you want to start counting?y,n:", end=" ")
ans = input()
if ans == "n":
print("I'm done.")
elif ans == "y":
#Import main file
csv_file = open(filename, "r", encoding="utf_8", errors="", newline="" )
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(f)
#print(header[1:]) #Output header
for row in f: #Data read
#print(row[1:])
material.append(row[1:])
#Import info file
filename2 = filename.replace("main","info")
csv_file = open(filename2, "r", encoding="utf_8", errors="", newline="" )
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(f)
#print(header[1:]) #Output header
for row in f: #Data read
#print(row[1:])
info.append(row[1:])
else:
pass
#Summarize
material_result=['','']
material_result[0] = info
material_result[1] = material
return material_result
Load the number of samples k and the number of trials n from info.csv output from PCPS
def get_k(info):
k = int(str(info[2]).replace("[","").replace("]","").replace("\'",""))
return k
def get_n(info):
n = int(str(info[4]).replace("[","").replace("]","").replace("\'",""))
return n
Degree of freedom f calculation
def f_calculation(info):
k = get_k(info)
k_1 = k * (k-1) * (k-2)
k_2 = (k-4) * (k-4)
f = float(k_1/k_2)
return f
The votes are totaled and the number d of the round triangles is calculated. Numpy is used to convert to a matrix at the time of aggregation.
def make_vote_list_and_calculation(info,material):
#info to k,n read
k = get_k(info)
n = get_n(info)
#list Create horizontal axis
vote_list = []
for i in range(k+1):
vote_list.append('')
#list Create vertical axis
vote_list_all = []
for i in range(k+1):
vote_list_all.append(vote_list)
#Matrix transformation
vote_list_all_np = np.array(vote_list_all,dtype=object)
#Unnecessary line-Insert(For display)
for i in range(k+1):
vote_list_all_np[i][i] = '-'
#The vertical axis icon is larger than the horizontal axis icon(For display)
vote_list_all_np[0][0] = 'i>j'
#Presentation sample information extraction(For display)
get_icon = info[3]
icon = get_icon[0].replace("[","").replace("]","").replace("\'","").replace("\"","").replace(" ","").split(',')
#Presented sample information set(For display)
count = 0
for send_icon in icon:
vote_list_all_np[0][count+1] = send_icon
vote_list_all_np[count+1][0] = send_icon
count += 1
#Insert vote
for i in range(n):
selector = int(material[i][2])
yoko = icon.index(str(material[i][selector]))
selector2 = 0 if selector == 1 else 1
tate = icon.index(str(material[i][selector2]))
# add 1 point
vote_list_all_np[yoko+1][tate+1] = 1
# add 0 point
vote_list_all_np[tate+1][yoko+1] = 0
#Vote matrix display
print("Voting table")
print(vote_list_all_np)
#Calculation symbol → 0
for i in range(k+1):
vote_list_all_np[i][i] = 0
#Calculation symbol → 0
vote_list_all_np[0][0] = 0
#Presentation sample information for calculation → 0
count = 0
for send_icon in icon:
vote_list_all_np[0][count+1] = 0
vote_list_all_np[count+1][0] = 0
count += 1
vote_sum = np.sum(vote_list_all_np, axis=1)
print("Vote a_i:",end=" ")
print(vote_sum)
print("Vote Σa_i:",end=" ")
print(np.sum(vote_sum))
vote_calc_result = 0
for i in range(k):
vote_calc = vote_sum[i]*(vote_sum[i] - 1)
vote_calc_result += vote_calc
d = float(1/ 6) * float(k) * (float(k)-1.0) * (float(k)-2.0) - 0.5 * float(vote_calc_result)
return d
Finally, calculate $ \ zeta $ and $ \ chi_o ^ 2 $
def zeta_calculation(f,d,info):
k = get_k(info)
if k % 2 == 0:
print("Number of samples k: Even")
v_1 = 24*d
v_2 = (k^3) - (4*k)
v_3 = float(v_1/v_2)
zeta = 1 - v_3
else:
print("Number of samples k: Odd")
v_1 = 24*d
v_2 = (k^3) - (k)
v_3 = float(v_1/v_2)
zeta = 1 - v_3
return zeta
def chi_2_0_caluculation(f,d,info):
k = get_k(info)
v_1 = k-4
v_2 = k*(k-1)*(k-2)
v_3 = float(v_2/24)
chi_2_0 = float(8/v_1) * (float(v_3) - float(d) + 0.5) + float(f)
return chi_2_0
Once uniqueness is found, a consistency test can be performed next to test whether the responses between valid subjects match.
I will write a consistency test in the next article. The second "test of consistency in paired comparison method" https://zenn.dev/_kazuya/articles/66ef65022407ef
[^ 1]: "Paired comparison method" Kansei/sensory evaluation system J-SEMS https://j-sems.com/%E4%B8%80%E5%AF%BE%E6%AF%94%E8%BC % 83% E6% B3% 95 /
[^ 2]: "About the seasonal feeling of the three primary colors seen on the PC screen" https://core.ac.uk/download/pdf/233608433.pdf
[^ 3]: Master's thesis "Method of presenting force feedback using pseudo-tactile sensation between augmented reality" Takashi Otsuka, Department of Electrical Engineering, Graduate School of Engineering, The University of Tokyo February 6, 2013
[^ 4]: "Understanding Psychological Statistics" Takeshi Yamada, Junichiro Murai Minerva Shobo
[^ 5]: "A Study on Paired Comparison Process in AHP Use of Paired Comparison Method in Sensory Test" Hiroshi Iida
Recommended Posts