Short demo of psydata functions


In [1]:
import seaborn as sns
import psyutils as pu

%load_ext autoreload
%autoreload 2

%matplotlib inline

sns.set_style("white")
sns.set_style("ticks")

I'll demo some functions here using a dataset I simulated earlier.


In [2]:
# load data:
dat = pu.psydata.load_psy_data()
dat.info()


<class 'pandas.core.frame.DataFrame'>
Int64Index: 7000 entries, 0 to 6999
Data columns (total 8 columns):
Unnamed: 0     7000 non-null int64
subject        7000 non-null object
contrast       7000 non-null float64
sf             7000 non-null float64
target_side    7000 non-null object
response       7000 non-null object
unique_id      7000 non-null object
correct        7000 non-null int64
dtypes: float64(2), int64(2), object(4)
memory usage: 492.2+ KB

Bin bernoulli trials, compute binomial statistics

Compute binomial trials for each combination of contrast and sf, averaging over subjects:


In [3]:
pu.psydata.binomial_binning(dat, y='correct', 
                            grouping_variables=['contrast', 'sf'])


Out[3]:
contrast sf n_successes n_trials prop_corr ci_min ci_max error_min error_max
0 0.002479 0.500000 106 200 0.530 0.460792 0.598640 0.069208 0.068640
1 0.002479 1.495349 93 200 0.465 0.396452 0.534211 0.068548 0.069211
2 0.002479 4.472136 99 200 0.495 0.426002 0.564093 0.068998 0.069093
3 0.002479 13.374806 103 200 0.515 0.445840 0.583876 0.069160 0.068876
4 0.002479 40.000000 95 200 0.475 0.406274 0.544199 0.068726 0.069199
5 0.005704 0.500000 103 200 0.515 0.445840 0.583876 0.069160 0.068876
6 0.005704 1.495349 129 200 0.645 0.577555 0.709698 0.067445 0.064698
7 0.005704 4.472136 110 200 0.550 0.480825 0.618228 0.069175 0.068228
8 0.005704 13.374806 97 200 0.485 0.416124 0.554160 0.068876 0.069160
9 0.005704 40.000000 104 200 0.520 0.450817 0.588804 0.069183 0.068804
10 0.013124 0.500000 105 200 0.525 0.455801 0.593726 0.069199 0.068726
11 0.013124 1.495349 162 200 0.810 0.752948 0.861183 0.057052 0.051183
12 0.013124 4.472136 146 200 0.730 0.666540 0.789103 0.063460 0.059103
13 0.013124 13.374806 122 200 0.610 0.541607 0.676309 0.068393 0.066309
14 0.013124 40.000000 96 200 0.480 0.411196 0.549183 0.068804 0.069183
15 0.030197 0.500000 155 200 0.775 0.714772 0.830020 0.060228 0.055020
16 0.030197 1.495349 199 200 0.995 0.981634 0.999873 0.013366 0.004873
17 0.030197 4.472136 192 200 0.960 0.928870 0.982487 0.031130 0.022487
18 0.030197 13.374806 152 200 0.760 0.698597 0.816479 0.061403 0.056479
19 0.030197 40.000000 104 200 0.520 0.450817 0.588804 0.069183 0.068804
20 0.069483 0.500000 196 200 0.980 0.956578 0.994497 0.023422 0.014497
21 0.069483 1.495349 200 200 1.000 NaN NaN NaN NaN
22 0.069483 4.472136 200 200 1.000 NaN NaN NaN NaN
23 0.069483 13.374806 194 200 0.970 0.942342 0.988856 0.027658 0.018856
24 0.069483 40.000000 134 200 0.670 0.603469 0.733310 0.066531 0.063310
25 0.159880 0.500000 200 200 1.000 NaN NaN NaN NaN
26 0.159880 1.495349 200 200 1.000 NaN NaN NaN NaN
27 0.159880 4.472136 200 200 1.000 NaN NaN NaN NaN
28 0.159880 13.374806 200 200 1.000 NaN NaN NaN NaN
29 0.159880 40.000000 192 200 0.960 0.928870 0.982487 0.031130 0.022487
30 0.367879 0.500000 200 200 1.000 NaN NaN NaN NaN
31 0.367879 1.495349 200 200 1.000 NaN NaN NaN NaN
32 0.367879 4.472136 200 200 1.000 NaN NaN NaN NaN
33 0.367879 13.374806 200 200 1.000 NaN NaN NaN NaN
34 0.367879 40.000000 200 200 1.000 NaN NaN NaN NaN

Notice that you can't compute binomial confidence intervals if the proportion success is 0 or 1. We can fix this using Laplace's Rule of Succession -- add one success and one failure to each observation (basically a prior that says that both successes and failures are possible).


In [4]:
pu.psydata.binomial_binning(dat, y='correct', 
                            grouping_variables=['contrast', 'sf'],
                            rule_of_succession=True)


Out[4]:
contrast sf n_successes n_trials prop_corr ci_min ci_max error_min error_max
0 0.002479 0.500000 107 202 0.529703 0.460837 0.598011 0.068866 0.068308
1 0.002479 1.495349 94 202 0.465347 0.397129 0.534215 0.068218 0.068868
2 0.002479 4.472136 100 202 0.495050 0.426391 0.563801 0.068659 0.068752
3 0.002479 13.374806 104 202 0.514851 0.446034 0.583391 0.068818 0.068539
4 0.002479 40.000000 96 202 0.475248 0.406855 0.544104 0.068392 0.068856
5 0.005704 0.500000 104 202 0.514851 0.446034 0.583391 0.068818 0.068539
6 0.005704 1.495349 130 202 0.643564 0.576412 0.708023 0.067152 0.064459
7 0.005704 4.472136 111 202 0.549505 0.480671 0.617411 0.068834 0.067906
8 0.005704 13.374806 98 202 0.485149 0.416609 0.553966 0.068539 0.068818
9 0.005704 40.000000 105 202 0.519802 0.450962 0.588271 0.068840 0.068469
10 0.013124 0.500000 106 202 0.524752 0.455896 0.593145 0.068856 0.068392
11 0.013124 1.495349 163 202 0.806931 0.749871 0.858237 0.057060 0.051307
12 0.013124 4.472136 147 202 0.727723 0.664446 0.786729 0.063277 0.059006
13 0.013124 13.374806 123 202 0.608911 0.540836 0.674943 0.068075 0.066032
14 0.013124 40.000000 97 202 0.480198 0.411729 0.549038 0.068469 0.068840
15 0.030197 0.500000 156 202 0.772277 0.712139 0.827311 0.060139 0.055034
16 0.030197 1.495349 200 202 0.990099 0.972594 0.998793 0.017505 0.008694
17 0.030197 4.472136 193 202 0.955446 0.923085 0.979324 0.032360 0.023878
18 0.030197 13.374806 153 202 0.757426 0.696146 0.813878 0.061280 0.056453
19 0.030197 40.000000 105 202 0.519802 0.450962 0.588271 0.068840 0.068469
20 0.069483 0.500000 197 202 0.975248 0.949833 0.991875 0.025414 0.016627
21 0.069483 1.495349 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
22 0.069483 4.472136 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
23 0.069483 13.374806 195 202 0.965347 0.936163 0.985886 0.029184 0.020539
24 0.069483 40.000000 135 202 0.668317 0.602054 0.731423 0.066263 0.063106
25 0.159880 0.500000 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
26 0.159880 1.495349 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
27 0.159880 4.472136 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
28 0.159880 13.374806 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
29 0.159880 40.000000 193 202 0.955446 0.923085 0.979324 0.032360 0.023878
30 0.367879 0.500000 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
31 0.367879 1.495349 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
32 0.367879 4.472136 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
33 0.367879 13.374806 201 202 0.995050 0.981815 0.999874 0.013235 0.004825
34 0.367879 40.000000 201 202 0.995050 0.981815 0.999874 0.013235 0.004825

Fit and plot a psychometric function to each subject, sf:


In [5]:
g = pu.psydata.plot_psy(dat, 'contrast', 'correct', 
                        function='weibull',
                        hue='sf', 
                        col='subject',
                        log_x=True,
                        col_wrap=3,
                        errors=False,                        
                        fixed={'gam': .5, 'lam':.02}, 
                        inits={'m': 0.01, 'w': 3})
g.add_legend()
g.set(xlabel='Log Contrast', ylabel='Prop correct')
g.fig.subplots_adjust(wspace=.8, hspace=.8);


The fitted parameters are:

           sf subject  gam   lam         m         w
0    0.500000      S1  0.5  0.02 -3.039783  1.553811
1    0.500000      S2  0.5  0.02 -3.569313  1.385677
2    0.500000      S3  0.5  0.02 -3.429419  1.171425
3    0.500000      S4  0.5  0.02 -3.528454  0.333372
4    0.500000      S5  0.5  0.02 -4.265210  1.954781
5    1.495349      S1  0.5  0.02 -3.927007  0.927928
6    1.495349      S2  0.5  0.02 -5.155828  0.175250
7    1.495349      S3  0.5  0.02 -4.350894  1.168227
8    1.495349      S4  0.5  0.02 -4.474785  1.827611
9    1.495349      S5  0.5  0.02 -5.299547  1.566281
10   4.472136      S1  0.5  0.02 -3.697220  1.937106
11   4.472136      S2  0.5  0.02 -4.690916  1.049057
12   4.472136      S3  0.5  0.02 -4.092843  0.913296
13   4.472136      S4  0.5  0.02 -4.281961  0.192128
14   4.472136      S5  0.5  0.02 -4.933101  2.535801
15  13.374806      S1  0.5  0.02 -2.943758  1.837344
16  13.374806      S2  0.5  0.02 -3.775010  2.183722
17  13.374806      S3  0.5  0.02 -3.479685  1.391155
18  13.374806      S4  0.5  0.02 -3.650320  1.907574
19  13.374806      S5  0.5  0.02 -3.873398  1.099602
20  40.000000      S1  0.5  0.02 -2.266632  1.280605
21  40.000000      S2  0.5  0.02 -2.628770  0.185276
22  40.000000      S3  0.5  0.02 -2.109918  1.421719
23  40.000000      S4  0.5  0.02 -2.621802  1.634402
24  40.000000      S5  0.5  0.02 -2.925570  1.664404

Run pu.psydata.psy_params to get this data

Some kind of wonky fits (unrealistic slopes), but hey, that's what you get with a simple ML fit with no pooling / shrinkage / priors.


In [6]:
g = pu.psydata.plot_psy_params(dat, 'contrast', 'correct', 
                               x="sf", y="m",
                               function='weibull',
                               hue='subject', 
                               fixed={'gam': .5, 'lam':.02})
g.set(xlabel='Spatial Frequency', ylabel='Contrast threshold');


Reasonable (imposed by simulation) CSF shape recovered.