# -*- coding: iso8859-2 -*- """ Skript zobrazí místo adjustovaných reziduí v kontingenční tabulce znaménkové schéma. Vstupem skriptu je tabulka z procedury Crosstabs, která obsahuje adjustovaná rezidua. Výstupem je tabulka, ve které jsou místo adjustovaných reziduí znaménka, a to podle tohoto schématu je-li |z| < 1.96, je přepsáno na "o" je-li 1.96 =< |z| < 2.58, je přepsáno na "+", resp. "-" je-li 2.58 =< |z| < 3.29, je přepsáno na "++", resp. "--" je-li |z| >= 3.29, je přepsáno na "+++", resp. "---" Skript nejdříve najde označenou tabulku. Jsou-li statistiky v řádcích, zpivotuje tabulku tak, aby statistiky byly v řádcích na nejvyšší úrovni. Pak nalezne podtabulku obsahující adjustovaná rezidua a postupně ji prochází a přepisuje rezidua na znaménka. Jsou-li adjustovaná rezidua ve vrstvách, tabulka se nepivotuje, pouze se adjustovaná rezidua přepíšou na znaménka. Při zpracování je přislušná tabulka zavřená, po ukončení zpracování se znovu otevře. Skript lze použít na více vybraných tabulek. Nově je možná adjustace pomocí Holmovy metody. Výběr se řídí úvodním dialogem. V kombinaci s Holmovou metodou nelze skript použít pro tabulky se zapnutou funkcí Split file - Compare groups. Holmova sekvenční metoda testuje největší reziduu (v absolutní hodnotě) na požadované hladině děleno počtem všech reziduí. Nelze-li zamítnout nulovou hypotézu (tj. reziduum je menší než příslušná kritická hodnota), pak nelze zamítnout nulovou hypotézu ani u ostatních reziduí. Zamítne-li se nulová hypotéza u největšího rezidua, postupuje se k druhému největšímu reziduu, které se testuje na požadované hladině děleno počet všech reziduí - 1. Dále se postupuje analogicky prvnímu kroku. V případě shody reziduí se tato testují na nejmenší hladině příslušné těmto reziduím. Tato metoda je popsaná např. v knize Řehák, Řeháková (1986): Analýza kategorizovaných dat v sociologii. """ __author__ = 'Eliska Kalinova ekalinova@acrea.cz' __version__ = '8.0' __date__ = '28.7.2011' from Tkinter import * import sys import SpssClient from math import sqrt class Dialog: """ Trida pro zobrazeni uvodniho dialogu. """ def start(self): ### Parametry okna windowWidth=270 windowHeight=180 bgColor='#f0f0f0' ### Parametry objektů ###### Ohraničení masterRelief=GROOVE framewidth=200 ###### Fonty titleFont = "Arial 14 bold" titleFontColor='#23238E' frameFont = "Arial 10 bold" frameFontColor='#cc0000' objectFont = "Arial 8" objectFontColor='#000000' ###### Odsazení outerPadX=10 outerPadY=10 innerPadX=10 innerPadY=10 ###### Barvy masterColor='#f0f0f0' subColor='#f0f0f0' ### Okno úvodního dialogu self.okno = Tk() w=self.okno.winfo_screenwidth() h=self.okno.winfo_screenheight() self.okno.geometry("%dx%d+%d+%d" % ( windowWidth, windowHeight, (w-windowWidth)/2, (h-windowHeight)/2 ) ) #okno uprostřed obrazovky self.okno.title('ACREA CR') self.okno.config(bg=bgColor) self.okno.resizable(0,0) self.okno.protocol('WM_DELETE_WINDOW', sys.exit ) #funkce při zavření křížkem ### Rám titulku fTitle = LabelFrame(self.okno) fTitle.config(relief=FLAT,padx=0,pady=0,bg=subColor) info= Label(fTitle , text=u'Znaménkové schéma', bg=subColor, font = titleFont ,fg=titleFontColor) info.pack(side=LEFT) fTitle.pack(anchor=NW, expand=1, fill=X, padx=outerPadX, pady=0) ### Rám OptionButton self.Holm = IntVar() self.Holm.set(0) fOptionButton = LabelFrame(self.okno,text=u'Použít Holmovu metodu') fOptionButton.config(relief=masterRelief,padx=innerPadX,pady=innerPadY,bg=subColor,font=frameFont,fg=frameFontColor,width=framewidth) OptionButton1=Radiobutton(fOptionButton, text=u'ne', bg=subColor, font=objectFont, fg=objectFontColor, variable=self.Holm, value=0) OptionButton1.select() OptionButton1.pack(anchor=W) OptionButton2=Radiobutton(fOptionButton, text=u'ano', bg=subColor, font=objectFont, fg=objectFontColor, variable=self.Holm, value=1) OptionButton2.pack(anchor=W) fOptionButton.pack(anchor=W, padx=outerPadX, pady=outerPadY) ### Rám NavButton fNavButton = LabelFrame(self.okno) fNavButton.config(relief=FLAT,padx=0,pady=0,bg=subColor) fNavButton.pack(anchor = SW, fill=X, expand=1, pady=0, padx=0) ### Tlačítka Button(fNavButton, text="OK", command=self.callOkButton, width = 8).pack(side=LEFT, padx=5, pady=5) Button(fNavButton, text="Storno", command=self.callCancelButton, width = 8).pack(side=LEFT, padx=5, pady=5) ### Copyright cop = Label(fNavButton , text= u'Copyright ACREA CR', bg=subColor, font = "Arial 8 italic" ,fg='#000000') cop.pack(side=RIGHT) self.okno.mainloop() ### Funkce tlačítka OK včetně načtení slovníku def callOkButton(self): """ Povoleni pokracovani skriptu. """ ## self.okno.quit() self.okno.destroy() ### Funkce tlačítka Cancel def callCancelButton(self): """ Zruseni pokracovani skriptu. """ ## self.okno.quit() sys.exit() class Warning: """ Trida pro zobrazeni chyboveho hlaseni. """ # Parametry okna windowWidth=270 windowHeight=90 bgColor='#f0f0f0' # Parametry objektů ### fonty objectFont = "Arial 8" objectFontColor='#000000' ### odsazení outerPadX=10 outerPadY=10 ### barvy masterColor='#f0f0f0' subColor='#f0f0f0' # Text chybového hlášení hlaska = u"Nevhodná tabulka." def start(self): """ Zobrazeni dialogu s popisem chyby. """ # Okno s popisem chyby při načítání slovníku self.okno = Tk() w=self.okno.winfo_screenwidth() h=self.okno.winfo_screenheight() self.okno.geometry("%dx%d+%d+%d" % ( self.windowWidth, self.windowHeight, (w-self.windowWidth)/2, (h-self.windowHeight)/2 ) ) #okno uprostřed obrazovky self.okno.title('ACREA CR') self.okno.config(bg=self.bgColor) self.okno.resizable(0,0) self.okno.protocol('WM_DELETE_WINDOW', sys.exit) #funkce při zavření křížkem # Text chybového hlášení hlaseni = Label(self.okno, font=self.objectFont, text=self.hlaska) hlaseni.pack(padx=self.outerPadX, pady=self.outerPadY) # Rám NavButton fNavButton = LabelFrame(self.okno) fNavButton.config(relief=FLAT,padx=0,pady=0,bg=self.subColor) fNavButton.pack(anchor=SW, fill=X, expand=1, pady=0, padx=0) # Tlačítko OK Button(fNavButton, text="OK", command=self.callOkButton, width=8).pack(side=LEFT, padx=5, pady=5) # Copyright cop= Label(fNavButton , text= u'Copyright ACREA CR', bg=self.subColor, font = "Arial 8 italic" ,fg='#000000') cop.pack(side=RIGHT) self.okno.mainloop() # Funkce tlačítka OK def callOkButton(self): """ Potvrzeni dialogu. """ self.okno.quit() def vypocet_signifikance_norm(x): """ Provadi vypocet signifikance pro standardni normalni rozdeleni. """ a1 = 0.0705230784 a2 = 0.0422820123 a3 = 0.0092705272 a4 = 0.0001520143 a5 = 0.0002765672 a6 = 0.0000430638 if abs(x) <= 14.14: Z = sqrt(2)/2 * abs(x) else: Z = 10 return((1+Z*(a1+Z*(a2+Z*(a3+Z*(a4+Z*(a5+Z*(a6)))))))**(-16))*0.5 def SignScheme(objPivotTable): """ Prepsani adjustovanych rezidui na znamenkove schema. """ start = 0 objPivotTable.SetUpdateScreen(False) # Nalezení podtabulky obsahující adjustovaná rezidua objSpssLabels = objPivotTable.RowLabelArray() i = 0 while i < objSpssLabels.GetNumRows(): if objSpssLabels.GetValueAt(i,1) == "Adjusted Residual": start = i # Index, od kterého začíná podtabulka s adjustovanými rezidui objSpssLabels.SetValueAt(i,1,"Sign Scheme") i = objSpssLabels.GetNumRows() else: i = i + 1 if Holm == 0: # Bez adjustace. # Průchod podtabulkou obsahující adjustovaná rezidua znamenka = [] objDataCells = objPivotTable.DataCellArray() objPivotTable.ClearSelection() for i in range(start,objDataCells.GetNumRows()): for j in range(objDataCells.GetNumColumns()): try: s = objDataCells.GetUnformattedValueAt(i,j) z = float(s) # Konverze stringu na floating point if abs(z) < 1.96: objDataCells.SetValueAt(i,j,"o") znamenka.append("o") elif abs(z) < 2.58: if z > 0: objDataCells.SetValueAt(i,j,"+") znamenka.append("+") else: objDataCells.SetValueAt(i,j,"-") znamenka.append("-") elif abs(z) < 3.29: if z > 0: objDataCells.SetValueAt(i,j,"++") znamenka.append("++") else: objDataCells.SetValueAt(i,j,"--") znamenka.append("--") else: if z > 0: objDataCells.SetValueAt(i,j,"+++") znamenka.append("+++") else: objDataCells.SetValueAt(i,j,"---") znamenka.append("---") except: pass # Závěrečné formátování for i in range(start,objDataCells.GetNumRows()): for j in range(objDataCells.GetNumColumns()): try: z = objDataCells.GetValueAt(i,j) objDataCells.SetTextSizeAt(i,j,11) objDataCells.SetTextStyleAt(i,j,SpssClient.SpssTextStyleTypes.SpssTSBold) objDataCells.SetHAlignAt(i,j,SpssClient.SpssHAlignTypes.SpssHAlCenter) if z == "+" or z == "++" or z == "+++": objDataCells.SetTextColorAt(i,j,255) if z == "-" or z == "--" or z == "---": objDataCells.SetTextColorAt(i,j,32768) except: pass else: # Načtení reziduí a aplikace Holmovy sekvenční metody. rezidua = [] # Tento list bude obsahovat absolutní hodnotu rezidua, reziduum, původní pořadí rezidua v tabulce, signifikanci, hladinu testu, znaménko, barvu znaménka. objDataCells = objPivotTable.DataCellArray() objPivotTable.ClearSelection() for i in range(start,objDataCells.GetNumRows()): for j in range(objDataCells.GetNumColumns()): try: z = float(objDataCells.GetUnformattedValueAt(i,j)) rezidua.append([abs(z),z,len(rezidua)]) except: pass rezidua.sort(reverse=True) # Seřazení sestupně dle absolutní hodnoty rezidua, což je ekvivalentní vzestupného řazení dle signifikancí. jmenovatel = [] jmenovatel.append(len(rezidua)) for i in xrange(1,len(rezidua)): if rezidua[i][0] == rezidua[i-1][0]: jmenovatel.append(jmenovatel[i-1]) else: jmenovatel.append(len(rezidua)-i) ### Porovnání s hladinou 0.05. i = 0 while i < len(rezidua): rezidua[i].append(2*vypocet_signifikance_norm(rezidua[i][0])) if rezidua[i][-1] >= 0.05/jmenovatel[i]: rezidua[i].append(0.05/jmenovatel[i]) rezidua[i].append("o") rezidua[i].append(0) for j in xrange(i+1,len(rezidua)): rezidua[j].append(2*vypocet_signifikance_norm(rezidua[j][0])) rezidua[j].append(0.05/jmenovatel[j]) rezidua[j].append("o") rezidua[j].append(0) i = len(rezidua) else: i += 1 ### Porovnání s hladinou 0.01. i = 0 while i < len(rezidua): if rezidua[i][3] >= (0.01/jmenovatel[i]) and rezidua[i][3] < (0.05/jmenovatel[i]): j = i while j < len(rezidua): rezidua[j].append(0.01/jmenovatel[j]) if rezidua[j][1] > 0: rezidua[j].append("+") rezidua[j].append(255) else: rezidua[j].append("-") rezidua[j].append(32768) j = j+1 if j < len(rezidua) and rezidua[j][3] >= (0.05/jmenovatel[j]): j = len(rezidua) i = len(rezidua) else: i += 1 ### Porovnání s hladinou 0.001. i = 0 while i < len(rezidua): if rezidua[i][3] >= (0.001/jmenovatel[i]) and rezidua[i][3] < (0.01/jmenovatel[i]): j = i while j < len(rezidua): rezidua[j].append(0.001/jmenovatel[j]) if rezidua[j][1] > 0: rezidua[j].append("++") rezidua[j].append(255) else: rezidua[j].append("--") rezidua[j].append(32768) j = j+1 if j < len(rezidua) and rezidua[j][3] >= (0.01/jmenovatel[j]): j = len(rezidua) i = len(rezidua) else: i += 1 ### Zbytek po porovnání s hladinou 0.001. i = 0 while i < len(rezidua): if rezidua[i][3] < (0.001/jmenovatel[i]): rezidua[i].append(0.001/jmenovatel[i]) if rezidua[i][1] > 0: rezidua[i].append("+++") rezidua[i].append(255) else: rezidua[i].append("---") rezidua[i].append(32768) i = i+1 else: i = len(rezidua) rezidua.sort(key=lambda x:x[2]) # Návrat k původnímu řazení. # Předání znamének do tabulky. k = 0 for i in range(start,objDataCells.GetNumRows()): for j in range(objDataCells.GetNumColumns()): if objDataCells.GetValueAt(i,j) != "": objDataCells.SetValueAt(i,j,rezidua[k][-2]) objDataCells.SetTextSizeAt(i,j,11) objDataCells.SetTextStyleAt(i,j,SpssClient.SpssTextStyleTypes.SpssTSBold) objDataCells.SetHAlignAt(i,j,SpssClient.SpssHAlignTypes.SpssHAlCenter) objDataCells.SetTextColorAt(i,j,rezidua[k][-1]) k = k + 1 #objPivotTable.SetCaptionText("Znaménkové schéma bylo vytvořeno pomocí Holmovy sekvenční metody.") objPivotTable.SetUpdateScreen(True) def pivote(objPivotTable): """ Pivotace tabulky. """ # Pivotace tabulky - statistiky do nejvyšší úrovně v řádcích objPivotManager = objPivotTable.PivotManager() for i in range(objPivotManager.GetNumRowDimensions()): objRowDim = objPivotManager.GetRowDimension(i) if objRowDim.GetDimensionName() == "Statistics": objRowDim.MoveToRow(objPivotManager.GetNumRowDimensions()) objRowDim.HideLabel() break def test(objPivotTable): """ Test pritomnosti adjustovanych rezidui a zapnuti funkce Split file. """ found = 0 # Indikátor, zda tabulka obsahuje adjustovaná rezidua: 0 = ne, 1 = ano. split = 0 # Indikátor, zda není zapnuta funkce Split file - Compare groups: 0 = ne, 1 = ano. objPivotTable.SetUpdateScreen(False) # Nalezení podtabulky obsahující adjustovaná rezidua: # ve vrstvách objPivotManager = objPivotTable.PivotManager() if objPivotManager.GetNumLayerDimensions() > 0: objLayerDim = objPivotManager.GetLayerDimension(0) objRowLabels = objPivotTable.RowLabelArray() if objRowLabels.GetNumColumns() > 3: split = 1 if objLayerDim.GetCategoryValueAt(0) == "Adjusted Residual" and (split == 0 or Holm == 0): objLayerLabels = objPivotTable.LayerLabelArray() objLayerLabels.SetValueAt(0,0,"Sign Scheme") found = 1 # Nalezana adjustovaná rezidua start = 0 # Adjustovaná rezidua začínají na indexu 0 # v řádcích else: objSpssLabels = objPivotTable.RowLabelArray() for i in range(objSpssLabels.GetNumRows()): for j in range(objSpssLabels.GetNumColumns()): if objSpssLabels.GetValueAt(i,j) == "Adjusted Residual": found = 1 # Nalezana adjustovaná rezidua pivote(objPivotTable) break if objSpssLabels.GetNumColumns() > 5: split = 1 if split == 1 and Holm == 1: objPivotTable.SetUpdateScreen(True) chyba_tabulka = Warning() chyba_tabulka.windowWidth = 260 chyba_tabulka.windowHeight = 95 chyba_tabulka.hlaska = u"Nelze zpracovat tabulku vytvořenou s použitím \nfunkce Split file - Compare groups." chyba_tabulka.start() else: if found == 1: objPivotTable.SetUpdateScreen(True) SignScheme(objPivotTable) else: objPivotTable.SetUpdateScreen(True) chyba_tabulka = Warning() chyba_tabulka.windowWidth = 230 chyba_tabulka.windowHeight = 80 chyba_tabulka.hlaska = u"Tabulka neobsahuje adjustovaná rezidua." chyba_tabulka.start() try: uvod = Dialog() uvod.start() Holm = uvod.Holm.get() SpssClient.StartClient() pocet = 0 # Načtení výstupového okna a jeho obsahu objOutputDoc = SpssClient.GetDesignatedOutputDoc() objOutputItems = objOutputDoc.GetOutputItems() # Nalezení označené kontingenční tabulky for index in range(objOutputItems.Size()): objOutputItem = objOutputItems.GetItemAt(index) if objOutputItem.IsSelected() \ and objOutputItem.GetSubType() == "Crosstabulation" : objOutputItem.SetVisible(False) objPivotTable = objOutputItem.GetSpecificType() pocet = pocet + 1 test(objPivotTable) objPivotTable.Autofit() objOutputItem.SetVisible(True) if pocet == 0: chyba_tabulka = Warning() chyba_tabulka.windowWidth = 210 chyba_tabulka.windowHeight = 80 chyba_tabulka.hlaska = u"Nebyla vybrána kontingenční tabulka." chyba_tabulka.start() except: pass finally: SpssClient.StopClient()