@@ -29,11 +29,29 @@ class ChiSqStats:
2929 pair of attributes. The class is also used for ranking.
3030 """
3131 def __init__ (self , data , attr1 , attr2 ):
32- self .observed = get_contingency (data , attr1 , attr2 )
33- self .n = np .sum (self .observed )
34- self .probs_x = self .observed .sum (axis = 0 ) / self .n
35- self .probs_y = self .observed .sum (axis = 1 ) / self .n
36- self .expected = np .outer (self .probs_y , self .probs_x ) * self .n
32+ attr1 = data .domain [attr1 ]
33+ attr2 = data .domain [attr2 ]
34+ if attr1 .is_discrete and not attr1 .values or \
35+ attr2 .is_discrete and not data .domain [attr2 ].values :
36+ self .observed , self .n = np .nan , len (data )
37+ self .probs_x , self .probs_y = [], []
38+ if attr1 .values :
39+ observed_x = np .unique (data .get_column_view (
40+ data .domain .index (attr1 ))[0 ], return_counts = True )[1 ]
41+ self .probs_x = observed_x / self .n
42+ self .observed = observed_x
43+ if attr2 .values :
44+ observed_y = np .unique (data .get_column_view (
45+ data .domain .index (attr2 ))[0 ], return_counts = True )[1 ]
46+ self .probs_y = observed_y / self .n
47+ self .observed = observed_y
48+ self .expected = self .observed
49+ else :
50+ self .observed = get_contingency (data , attr1 , attr2 )
51+ self .n = np .sum (self .observed )
52+ self .probs_x = self .observed .sum (axis = 0 ) / self .n
53+ self .probs_y = self .observed .sum (axis = 1 ) / self .n
54+ self .expected = np .outer (self .probs_y , self .probs_x ) * self .n
3755 self .residuals = \
3856 (self .observed - self .expected ) / np .sqrt (self .expected )
3957 self .chisqs = self .residuals ** 2
@@ -447,6 +465,20 @@ def _oper(attr, txt):
447465 max_xlabel_h = max (int (xl .boundingRect ().height ()), max_xlabel_h )
448466 curr_x += width
449467
468+ if not disc_x .values and disc_y .values :
469+ curr_y = y_off
470+ for y in range (len (chi .probs_y ) - 1 , - 1 , - 1 ):
471+ py = chi .probs_y [y ]
472+ if py == 0 :
473+ continue
474+ text (disc_y .values [y ], x_off , curr_y + square_size * py / 2 ,
475+ Qt .AlignRight | Qt .AlignVCenter )
476+ curr_y += square_size * py
477+
478+ if not disc_x .values or not disc_y .values :
479+ text ("No data" , square_size / 2 + x_off + 30 ,
480+ square_size / 2 + y_off , Qt .AlignRight | Qt .AlignVCenter )
481+
450482 bottom = y_off + square_size + max_xlabel_h
451483 text (attr_y .name , 0 , y_off + square_size / 2 ,
452484 Qt .AlignLeft | Qt .AlignVCenter , bold = True , vertical = True )
0 commit comments