Election Mining

Campaigns are moving away from the meaningless labels of pollsters and newsweeklies — “Nascar dads” and “waitress moms” — and moving toward treating each voter as a separate person. In 2012 you didn’t just have to be an African-American from Akron or a suburban married female age 45 to 54. More and more, the information age allows people to be complicated, contradictory and unique. New technologies and an abundance of data may rattle the senses, but they are also bringing a fresh appreciation of the value of the individual to American politics.

- Ethan Roeder, “I Am Not Big Brother” http://www.nytimes.com/2012/12/06/opinion/i-am-not-big-brother.html?_r=0.
In [5]:
%matplotlib inline

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

We'll be using the MovieLens data set with 100K ratings from http://grouplens.org/datasets/movielens/. There you can find much bigger sets.

In the midst of writing this, I discovered a great blog post using pandas on the same data: http://www.gregreda.com/2013/10/26/using-pandas-on-the-movielens-dataset/. The approach and tools are slightly different. Worth checking out!

In [7]:
#First, let's look at what the files are.
!ls ml-100k
allbut.pl	u1.base  u3.base  u5.base  ub.base  u.info
mku.sh		u1.test  u3.test  u5.test  ub.test  u.item
ml-100k.tar.gz	u2.base  u4.base  ua.base  u.data   u.occupation
README		u2.test  u4.test  ua.test  u.genre  u.user
In [8]:
!cat ml-100k/README
SUMMARY & USAGE LICENSE
=============================================

MovieLens data sets were collected by the GroupLens Research Project
at the University of Minnesota.
 
This data set consists of:
	* 100,000 ratings (1-5) from 943 users on 1682 movies. 
	* Each user has rated at least 20 movies. 
        * Simple demographic info for the users (age, gender, occupation, zip)

The data was collected through the MovieLens web site
(movielens.umn.edu) during the seven-month period from September 19th, 
1997 through April 22nd, 1998. This data has been cleaned up - users
who had less than 20 ratings or did not have complete demographic
information were removed from this data set. Detailed descriptions of
the data file can be found at the end of this file.

Neither the University of Minnesota nor any of the researchers
involved can guarantee the correctness of the data, its suitability
for any particular purpose, or the validity of results based on the
use of the data set.  The data set may be used for any research
purposes under the following conditions:

     * The user may not state or imply any endorsement from the
       University of Minnesota or the GroupLens Research Group.

     * The user must acknowledge the use of the data set in
       publications resulting from the use of the data set, and must
       send us an electronic or paper copy of those publications.

     * The user may not redistribute the data without separate
       permission.

     * The user may not use this information for any commercial or
       revenue-bearing purposes without first obtaining permission
       from a faculty member of the GroupLens Research Project at the
       University of Minnesota.

If you have any further questions or comments, please contact Jon Herlocker
<[email protected]>. 

ACKNOWLEDGEMENTS
==============================================

Thanks to Al Borchers for cleaning up this data and writing the
accompanying scripts.

PUBLISHED WORK THAT HAS USED THIS DATASET
==============================================

Herlocker, J., Konstan, J., Borchers, A., Riedl, J.. An Algorithmic
Framework for Performing Collaborative Filtering. Proceedings of the
1999 Conference on Research and Development in Information
Retrieval. Aug. 1999.

FURTHER INFORMATION ABOUT THE GROUPLENS RESEARCH PROJECT
==============================================

The GroupLens Research Project is a research group in the Department
of Computer Science and Engineering at the University of Minnesota.
Members of the GroupLens Research Project are involved in many
research projects related to the fields of information filtering,
collaborative filtering, and recommender systems. The project is lead
by professors John Riedl and Joseph Konstan. The project began to
explore automated collaborative filtering in 1992, but is most well
known for its world wide trial of an automated collaborative filtering
system for Usenet news in 1996.  The technology developed in the
Usenet trial formed the base for the formation of Net Perceptions,
Inc., which was founded by members of GroupLens Research. Since then
the project has expanded its scope to research overall information
filtering solutions, integrating in content-based methods as well as
improving current collaborative filtering technology.

Further information on the GroupLens Research project, including
research publications, can be found at the following web site:
        
        http://www.grouplens.org/

GroupLens Research currently operates a movie recommender based on
collaborative filtering:

        http://www.movielens.org/

DETAILED DESCRIPTIONS OF DATA FILES
==============================================

Here are brief descriptions of the data.

ml-data.tar.gz   -- Compressed tar file.  To rebuild the u data files do this:
                gunzip ml-data.tar.gz
                tar xvf ml-data.tar
                mku.sh

u.data     -- The full u data set, 100000 ratings by 943 users on 1682 items.
              Each user has rated at least 20 movies.  Users and items are
              numbered consecutively from 1.  The data is randomly
              ordered. This is a tab separated list of 
	         user id | item id | rating | timestamp. 
              The time stamps are unix seconds since 1/1/1970 UTC   

u.info     -- The number of users, items, and ratings in the u data set.

u.item     -- Information about the items (movies); this is a tab separated
              list of
              movie id | movie title | release date | video release date |
              IMDb URL | unknown | Action | Adventure | Animation |
              Children's | Comedy | Crime | Documentary | Drama | Fantasy |
              Film-Noir | Horror | Musical | Mystery | Romance | Sci-Fi |
              Thriller | War | Western |
              The last 19 fields are the genres, a 1 indicates the movie
              is of that genre, a 0 indicates it is not; movies can be in
              several genres at once.
              The movie ids are the ones used in the u.data data set.

u.genre    -- A list of the genres.

u.user     -- Demographic information about the users; this is a tab
              separated list of
              user id | age | gender | occupation | zip code
              The user ids are the ones used in the u.data data set.

u.occupation -- A list of the occupations.

u1.base    -- The data sets u1.base and u1.test through u5.base and u5.test
u1.test       are 80%/20% splits of the u data into training and test data.
u2.base       Each of u1, ..., u5 have disjoint test sets; this if for
u2.test       5 fold cross validation (where you repeat your experiment
u3.base       with each training and test set and average the results).
u3.test       These data sets can be generated from u.data by mku.sh.
u4.base
u4.test
u5.base
u5.test

ua.base    -- The data sets ua.base, ua.test, ub.base, and ub.test
ua.test       split the u data into a training set and a test set with
ub.base       exactly 10 ratings per user in the test set.  The sets
ub.test       ua.test and ub.test are disjoint.  These data sets can
              be generated from u.data by mku.sh.

allbut.pl  -- The script that generates training and test sets where
              all but n of a users ratings are in the training data.

mku.sh     -- A shell script to generate all the u data sets from u.data.

Take a close look at u.data, u.item, u.users. How would you glance at the format in the Unix shell?

In [9]:
!head ml-100k/u.data
196	242	3	881250949
186	302	3	891717742
22	377	1	878887116
244	51	2	880606923
166	346	1	886397596
298	474	4	884182806
115	265	2	881171488
253	465	5	891628467
305	451	3	886324817
6	86	3	883603013
In [11]:
!head ml-100k/u.user
1|24|M|technician|85711
2|53|F|other|94043
3|23|M|writer|32067
4|24|M|technician|43537
5|33|F|other|15213
6|42|M|executive|98101
7|57|M|administrator|91344
8|36|M|administrator|05201
9|29|M|student|01002
10|53|M|lawyer|90703
In [12]:
!head ml-100k/u.item
1|Toy Story (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)|0|0|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0
2|GoldenEye (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?GoldenEye%20(1995)|0|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0
3|Four Rooms (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Four%20Rooms%20(1995)|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0
4|Get Shorty (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Get%20Shorty%20(1995)|0|1|0|0|0|1|0|0|1|0|0|0|0|0|0|0|0|0|0
5|Copycat (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Copycat%20(1995)|0|0|0|0|0|0|1|0|1|0|0|0|0|0|0|0|1|0|0
6|Shanghai Triad (Yao a yao yao dao waipo qiao) (1995)|01-Jan-1995||http://us.imdb.com/Title?Yao+a+yao+yao+dao+waipo+qiao+(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0
7|Twelve Monkeys (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Twelve%20Monkeys%20(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0
8|Babe (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Babe%20(1995)|0|0|0|0|1|1|0|0|1|0|0|0|0|0|0|0|0|0|0
9|Dead Man Walking (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Dead%20Man%20Walking%20(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0
10|Richard III (1995)|22-Jan-1996||http://us.imdb.com/M/title-exact?Richard%20III%20(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|1|0

How do these data files relate to one another?

In [2]:
from IPython.display import Image
Image("http://imgur.com/ZhpRFTj.png")
Out[2]:

What's missing? Duh, the labels!

Pandas is clever, but not so clever as to infer labels not included in the file. It's not the google(tm).

README gives us them. Let's copy them over by putting them into list of strings.

Exercise for the reader: Could you use `re.sub` to make this list of strings? Oh, you will, you will. (On the homework).
In [16]:
labels=["user_id","item_id","rating","timestamp"]
#arduously hand entered when should have spent 2 hours coding a way to do it automatically
In [17]:
individual_ratings=pd.read_csv( './ml-100k/u.data', sep="\t", names=labels) #\t because TAB separated
In [18]:
individual_ratings
Out[18]:
user_id item_id rating timestamp
0 196 242 3 881250949
1 186 302 3 891717742
2 22 377 1 878887116
3 244 51 2 880606923
4 166 346 1 886397596
5 298 474 4 884182806
6 115 265 2 881171488
7 253 465 5 891628467
8 305 451 3 886324817
9 6 86 3 883603013
10 62 257 2 879372434
11 286 1014 5 879781125
12 200 222 5 876042340
13 210 40 3 891035994
14 224 29 3 888104457
15 303 785 3 879485318
16 122 387 5 879270459
17 194 274 2 879539794
18 291 1042 4 874834944
19 234 1184 2 892079237
20 119 392 4 886176814
21 167 486 4 892738452
22 299 144 4 877881320
23 291 118 2 874833878
24 308 1 4 887736532
25 95 546 2 879196566
26 38 95 5 892430094
27 102 768 2 883748450
28 63 277 4 875747401
29 160 234 5 876861185
... ... ... ... ...
99970 449 120 1 879959573
99971 661 762 2 876037121
99972 721 874 3 877137447
99973 821 151 4 874792889
99974 764 596 3 876243046
99975 537 443 3 886031752
99976 618 628 2 891308019
99977 487 291 3 883445079
99978 113 975 5 875936424
99979 943 391 2 888640291
99980 864 685 4 888891900
99981 750 323 3 879445877
99982 279 64 1 875308510
99983 646 750 3 888528902
99984 654 370 2 887863914
99985 617 582 4 883789294
99986 913 690 3 880824288
99987 660 229 2 891406212
99988 421 498 4 892241344
99989 495 1091 4 888637503
99990 806 421 4 882388897
99991 676 538 4 892685437
99992 721 262 3 877137285
99993 913 209 2 881367150
99994 378 78 3 880056976
99995 880 476 3 880175444
99996 716 204 5 879795543
99997 276 1090 1 874795795
99998 13 225 2 882399156
99999 12 203 3 879959583

100000 rows × 4 columns

What's with that crazy number? According to the README, it's "unix seconds." A quick google search explains how to convert using the pd.to.datetime command. I will remember this just long enough to type the next few lines.

In [19]:
pd.to_datetime(individual_ratings["timestamp"], unit='s')
Out[19]:
0    1997-12-04 15:55:49
1    1998-04-04 19:22:22
2    1997-11-07 07:18:36
3    1997-11-27 05:02:03
4    1998-02-02 05:33:16
5    1998-01-07 14:20:06
6    1997-12-03 17:51:28
7    1998-04-03 18:34:27
8    1998-02-01 09:20:17
9    1997-12-31 21:16:53
10   1997-11-12 22:07:14
11   1997-11-17 15:38:45
12   1997-10-05 09:05:40
13   1998-03-27 21:59:54
14   1998-02-21 23:40:57
...
99985   1998-01-03 01:01:34
99986   1997-11-29 17:24:48
99987   1998-04-01 04:50:12
99988   1998-04-10 20:49:04
99989   1998-02-28 03:45:03
99990   1997-12-17 20:01:37
99991   1998-04-16 00:10:37
99992   1997-10-18 01:14:45
99993   1997-12-06 00:12:30
99994   1997-11-20 20:16:16
99995   1997-11-22 05:10:44
99996   1997-11-17 19:39:03
99997   1997-09-20 22:49:55
99998   1997-12-17 22:52:36
99999   1997-11-19 17:13:03
Name: timestamp, Length: 100000, dtype: datetime64[ns]
In [20]:
replacement_timestamps=pd.to_datetime(individual_ratings["timestamp"], unit='s')

Note that pd.to_datetime converted each of the timestamps individual without us telling it manually to loop through them. Hooray vectorized functions!

In [21]:
individual_ratings["timestamp"]=replacement_timestamps  

One = sign not two ( ==). Why?

In [22]:
individual_ratings
Out[22]:
user_id item_id rating timestamp
0 196 242 3 1997-12-04 15:55:49
1 186 302 3 1998-04-04 19:22:22
2 22 377 1 1997-11-07 07:18:36
3 244 51 2 1997-11-27 05:02:03
4 166 346 1 1998-02-02 05:33:16
5 298 474 4 1998-01-07 14:20:06
6 115 265 2 1997-12-03 17:51:28
7 253 465 5 1998-04-03 18:34:27
8 305 451 3 1998-02-01 09:20:17
9 6 86 3 1997-12-31 21:16:53
10 62 257 2 1997-11-12 22:07:14
11 286 1014 5 1997-11-17 15:38:45
12 200 222 5 1997-10-05 09:05:40
13 210 40 3 1998-03-27 21:59:54
14 224 29 3 1998-02-21 23:40:57
15 303 785 3 1997-11-14 05:28:38
16 122 387 5 1997-11-11 17:47:39
17 194 274 2 1997-11-14 20:36:34
18 291 1042 4 1997-09-21 09:42:24
19 234 1184 2 1998-04-08 23:47:17
20 119 392 4 1998-01-30 16:13:34
21 167 486 4 1998-04-16 14:54:12
22 299 144 4 1997-10-26 15:55:20
23 291 118 2 1997-09-21 09:24:38
24 308 1 4 1998-02-17 17:28:52
25 95 546 2 1997-11-10 21:16:06
26 38 95 5 1998-04-13 01:14:54
27 102 768 2 1998-01-02 13:40:50
28 63 277 4 1997-10-01 23:10:01
29 160 234 5 1997-10-14 20:33:05
... ... ... ... ...
99970 449 120 1 1997-11-19 17:12:53
99971 661 762 2 1997-10-05 07:38:41
99972 721 874 3 1997-10-18 01:17:27
99973 821 151 4 1997-09-20 22:01:29
99974 764 596 3 1997-10-07 16:50:46
99975 537 443 3 1998-01-28 23:55:52
99976 618 628 2 1998-03-31 01:33:39
99977 487 291 3 1997-12-30 01:24:39
99978 113 975 5 1997-10-04 03:40:24
99979 943 391 2 1998-02-28 04:31:31
99980 864 685 4 1998-03-03 02:25:00
99981 750 323 3 1997-11-13 18:31:17
99982 279 64 1 1997-09-26 21:15:10
99983 646 750 3 1998-02-26 21:35:02
99984 654 370 2 1998-02-19 04:51:54
99985 617 582 4 1998-01-03 01:01:34
99986 913 690 3 1997-11-29 17:24:48
99987 660 229 2 1998-04-01 04:50:12
99988 421 498 4 1998-04-10 20:49:04
99989 495 1091 4 1998-02-28 03:45:03
99990 806 421 4 1997-12-17 20:01:37
99991 676 538 4 1998-04-16 00:10:37
99992 721 262 3 1997-10-18 01:14:45
99993 913 209 2 1997-12-06 00:12:30
99994 378 78 3 1997-11-20 20:16:16
99995 880 476 3 1997-11-22 05:10:44
99996 716 204 5 1997-11-17 19:39:03
99997 276 1090 1 1997-09-20 22:49:55
99998 13 225 2 1997-12-17 22:52:36
99999 12 203 3 1997-11-19 17:13:03

100000 rows × 4 columns

Now, this is nice.

What if we wanted to get all the items that one user ranked?

Our new BFF boolean indexing comes to the rescue.

In [26]:
individual_ratings["user_id"]==42
Out[26]:
0     False
1     False
2     False
3     False
4     False
5     False
6     False
7     False
8     False
9     False
10    False
11    False
12    False
13    False
14    False
...
99985    False
99986    False
99987    False
99988    False
99989    False
99990    False
99991    False
99992    False
99993    False
99994    False
99995    False
99996    False
99997    False
99998    False
99999    False
Name: user_id, Length: 100000, dtype: bool
In [29]:
user_42_ratings_boolean=individual_ratings["user_id"]==42
In [30]:
individual_ratings[user_42_ratings_boolean]
Out[30]:
user_id item_id rating timestamp
58 42 423 5 1997-12-03 00:08:07
87 42 403 3 1997-12-03 00:24:44
111 42 96 5 1997-12-02 23:59:38
166 42 794 3 1997-12-03 00:20:25
310 42 546 3 1997-12-02 23:36:57
638 42 274 5 1997-12-02 23:36:57
659 42 588 5 1997-12-03 00:15:47
754 42 44 3 1997-12-03 00:22:28
778 42 1028 4 1997-12-02 23:41:12
871 42 625 3 1997-12-03 00:27:53
1119 42 98 4 1997-12-02 23:51:51
1245 42 953 2 1997-12-03 00:26:55
1656 42 685 4 1997-12-02 23:39:32
1761 42 176 3 1997-12-02 23:59:38
1864 42 195 5 1997-12-03 00:12:29
2179 42 185 4 1997-12-03 00:04:09
2290 42 69 4 1997-12-03 00:02:55
2394 42 684 4 1997-12-03 00:14:53
2431 42 603 4 1997-12-03 00:05:02
2613 42 1041 4 1997-12-03 00:31:00
2809 42 121 4 1997-12-03 00:56:18
2833 42 606 3 1997-12-03 00:05:38
2863 42 456 3 1997-12-02 23:41:53
2979 42 506 3 1997-12-03 00:26:00
3060 42 143 4 1997-12-03 00:17:09
3162 42 746 3 1997-12-03 00:17:59
3480 42 48 5 1997-12-03 00:10:21
3542 42 999 4 1997-12-03 00:29:42
3601 42 102 5 1997-12-03 00:27:53
3824 42 210 5 1997-12-03 00:23:53
... ... ... ... ...
59045 42 1046 3 1997-12-03 00:26:00
60647 42 97 3 1997-12-03 00:05:02
61040 42 559 2 1997-12-03 00:34:31
61695 42 86 3 1997-12-03 00:11:20
62662 42 71 4 1997-12-03 00:17:09
63521 42 941 4 1997-12-03 00:31:00
67740 42 655 3 1997-12-03 00:07:22
68778 42 969 5 1997-12-03 00:08:07
69604 42 132 5 1997-12-03 00:05:02
70257 42 595 1 1997-12-02 23:49:42
70653 42 1048 1 1997-12-02 23:43:40
71380 42 826 3 1997-12-02 23:46:59
73843 42 111 1 1997-12-02 23:38:51
74673 42 1050 3 1997-12-03 00:05:38
76940 42 141 3 1997-12-03 00:30:59
77201 42 181 5 1997-12-03 00:01:31
79562 42 174 5 1997-12-02 23:51:51
79923 42 73 4 1997-12-03 00:21:24
82241 42 168 3 1997-12-03 00:09:33
84817 42 2 5 1997-12-03 00:34:31
85776 42 658 2 1997-12-03 00:05:02
86538 42 755 4 1997-12-03 00:20:25
86768 42 282 4 1997-12-02 23:34:37
87394 42 136 4 1997-12-03 00:02:09
88397 42 735 4 1997-12-03 00:22:28
89527 42 411 4 1997-12-02 23:45:17
93817 42 433 2 1997-12-03 00:26:00
94791 42 87 4 1997-12-03 00:06:16
97557 42 591 4 1997-12-03 00:48:58
98433 42 103 3 1997-12-02 23:42:42

183 rows × 4 columns

Once we're in the confort zone with boolean indexing, we'd probably condense all that into one line:

In [31]:
individual_ratings[individual_ratings["user_id"]==42]
Out[31]:
user_id item_id rating timestamp
58 42 423 5 1997-12-03 00:08:07
87 42 403 3 1997-12-03 00:24:44
111 42 96 5 1997-12-02 23:59:38
166 42 794 3 1997-12-03 00:20:25
310 42 546 3 1997-12-02 23:36:57
638 42 274 5 1997-12-02 23:36:57
659 42 588 5 1997-12-03 00:15:47
754 42 44 3 1997-12-03 00:22:28
778 42 1028 4 1997-12-02 23:41:12
871 42 625 3 1997-12-03 00:27:53
1119 42 98 4 1997-12-02 23:51:51
1245 42 953 2 1997-12-03 00:26:55
1656 42 685 4 1997-12-02 23:39:32
1761 42 176 3 1997-12-02 23:59:38
1864 42 195 5 1997-12-03 00:12:29
2179 42 185 4 1997-12-03 00:04:09
2290 42 69 4 1997-12-03 00:02:55
2394 42 684 4 1997-12-03 00:14:53
2431 42 603 4 1997-12-03 00:05:02
2613 42 1041 4 1997-12-03 00:31:00
2809 42 121 4 1997-12-03 00:56:18
2833 42 606 3 1997-12-03 00:05:38
2863 42 456 3 1997-12-02 23:41:53
2979 42 506 3 1997-12-03 00:26:00
3060 42 143 4 1997-12-03 00:17:09
3162 42 746 3 1997-12-03 00:17:59
3480 42 48 5 1997-12-03 00:10:21
3542 42 999 4 1997-12-03 00:29:42
3601 42 102 5 1997-12-03 00:27:53
3824 42 210 5 1997-12-03 00:23:53
... ... ... ... ...
59045 42 1046 3 1997-12-03 00:26:00
60647 42 97 3 1997-12-03 00:05:02
61040 42 559 2 1997-12-03 00:34:31
61695 42 86 3 1997-12-03 00:11:20
62662 42 71 4 1997-12-03 00:17:09
63521 42 941 4 1997-12-03 00:31:00
67740 42 655 3 1997-12-03 00:07:22
68778 42 969 5 1997-12-03 00:08:07
69604 42 132 5 1997-12-03 00:05:02
70257 42 595 1 1997-12-02 23:49:42
70653 42 1048 1 1997-12-02 23:43:40
71380 42 826 3 1997-12-02 23:46:59
73843 42 111 1 1997-12-02 23:38:51
74673 42 1050 3 1997-12-03 00:05:38
76940 42 141 3 1997-12-03 00:30:59
77201 42 181 5 1997-12-03 00:01:31
79562 42 174 5 1997-12-02 23:51:51
79923 42 73 4 1997-12-03 00:21:24
82241 42 168 3 1997-12-03 00:09:33
84817 42 2 5 1997-12-03 00:34:31
85776 42 658 2 1997-12-03 00:05:02
86538 42 755 4 1997-12-03 00:20:25
86768 42 282 4 1997-12-02 23:34:37
87394 42 136 4 1997-12-03 00:02:09
88397 42 735 4 1997-12-03 00:22:28
89527 42 411 4 1997-12-02 23:45:17
93817 42 433 2 1997-12-03 00:26:00
94791 42 87 4 1997-12-03 00:06:16
97557 42 591 4 1997-12-03 00:48:58
98433 42 103 3 1997-12-02 23:42:42

183 rows × 4 columns

Now, if just wanted the series of ratings of user 42, we could add an index ['rating'].

In [34]:
individual_ratings[user_42_ratings_boolean]['rating']
Out[34]:
58      5
87      3
111     5
166     3
310     3
638     5
659     5
754     3
778     4
871     3
1119    4
1245    2
1656    4
1761    3
1864    5
...
77201    5
79562    5
79923    4
82241    3
84817    5
85776    2
86538    4
86768    4
87394    4
88397    4
89527    4
93817    2
94791    4
97557    4
98433    3
Name: rating, Length: 183, dtype: int64
In [41]:
#or in a one line formulation:
individual_ratings[individual_ratings["user_id"]==42]['rating']
Out[41]:
58      5
87      3
111     5
166     3
310     3
638     5
659     5
754     3
778     4
871     3
1119    4
1245    2
1656    4
1761    3
1864    5
...
77201    5
79562    5
79923    4
82241    3
84817    5
85776    2
86538    4
86768    4
87394    4
88397    4
89527    4
93817    2
94791    4
97557    4
98433    3
Name: rating, Length: 183, dtype: int64

pandas lets us do all sorts of simple statistics, like finding the mean. just tack on the method mean.

In [42]:
individual_ratings[individual_ratings["user_id"]==42]['rating'].mean()
Out[42]:
3.7267759562841531

How about all the ratings for a given film, say no. 65? How would we get that?

In [43]:
individual_ratings[individual_ratings["item_id"]==65]
Out[43]:
user_id item_id rating timestamp
247 62 65 4 1997-11-12 22:44:46
1042 271 65 3 1998-01-26 21:16:59
1152 207 65 3 1997-10-29 05:56:34
2321 303 65 4 1997-11-14 00:30:36
2608 279 65 1 1997-09-26 20:46:07
3111 313 65 2 1998-03-27 16:42:42
7149 59 65 4 1998-02-23 03:41:05
9097 378 65 3 1997-11-20 17:15:32
9178 151 65 4 1997-11-14 17:32:09
10285 128 65 4 1997-11-19 19:41:52
11112 210 65 4 1998-02-17 16:01:45
11591 347 65 2 1997-12-09 08:04:39
11779 339 65 4 1998-03-27 21:17:32
13254 409 65 4 1997-12-03 00:26:17
13860 116 65 2 1997-10-10 03:27:32
14614 144 65 4 1998-02-22 00:09:42
16207 235 65 2 1998-03-11 22:35:23
16330 198 65 2 1998-01-07 21:24:01
16707 71 65 5 1998-01-17 06:02:41
17220 1 65 4 1997-09-24 03:35:25
19110 401 65 4 1998-03-27 21:14:10
19153 398 65 3 1997-10-01 22:08:59
20515 437 65 4 1997-11-21 19:33:07
20831 65 65 3 1997-11-11 02:51:12
21607 18 65 5 1997-11-21 16:38:53
21786 267 65 4 1997-11-08 06:54:31
23247 450 65 3 1997-12-17 16:41:25
26808 239 65 5 1998-03-06 10:27:21
29009 187 65 5 1997-11-13 23:58:27
30379 417 65 4 1997-11-16 02:23:31
... ... ... ... ...
68157 621 65 3 1998-01-23 23:09:04
69155 790 65 4 1998-01-18 20:37:26
69366 916 65 3 1997-11-29 23:15:27
69838 405 65 1 1998-01-23 09:06:19
71118 276 65 4 1997-09-20 20:31:07
72450 815 65 5 1997-11-05 01:51:04
73577 848 65 2 1998-02-09 15:35:27
73753 883 65 4 1998-04-04 19:15:19
74031 269 65 4 1998-04-01 16:27:52
74869 174 65 5 1998-02-03 13:55:23
77183 354 65 4 1998-03-30 00:34:06
79753 727 65 2 1998-01-02 03:39:03
80688 870 65 3 1997-11-16 20:58:18
80856 216 65 4 1997-11-22 21:25:39
81409 468 65 3 1997-09-26 17:22:29
81865 864 65 3 1998-03-03 02:04:50
82834 244 65 4 1997-11-27 04:42:46
83681 934 65 4 1998-03-29 17:35:14
84507 601 65 4 1997-10-08 22:33:37
86661 846 65 3 1998-01-04 21:27:34
87592 887 65 5 1997-12-06 04:14:39
88365 805 65 3 1997-12-09 20:21:01
88946 766 65 4 1998-03-31 02:03:30
89960 897 65 4 1997-11-20 02:26:51
90575 709 65 2 1997-11-18 09:54:28
93337 788 65 4 1997-11-30 05:59:44
95905 886 65 3 1997-10-05 06:11:10
96697 682 65 3 1998-02-26 18:23:36
96833 868 65 2 1997-10-17 16:03:32
99541 92 65 4 1997-09-30 21:12:40

115 rows × 4 columns

In [44]:
individual_ratings[individual_ratings["item_id"]==65].mean()
Out[44]:
user_id    457.852174
item_id     65.000000
rating       3.539130
dtype: float64

Hmmm.....why is this output different?

Now, you're probably thinking, "there's just no way pandas can't automate this!"

In [68]:
for i in range(20):
    mean=individual_ratings[individual_ratings["item_id"]==i]['rating'].mean()
    if mean < 3.7:
        comment = "the people have spoken"
    else:
        comment = "a possibility, dear"
    print str(i)+"\t"+str(mean)+"\t\t"+comment
0	nan		a possibility, dear
1	3.87831858407		a possibility, dear
2	3.20610687023		the people have spoken
3	3.03333333333		the people have spoken
4	3.55023923445		the people have spoken
5	3.3023255814		the people have spoken
6	3.57692307692		the people have spoken
7	3.79846938776		a possibility, dear
8	3.99543378995		a possibility, dear
9	3.89632107023		a possibility, dear
10	3.83146067416		a possibility, dear
11	3.84745762712		a possibility, dear
12	4.38576779026		a possibility, dear
13	3.41847826087		the people have spoken
14	3.96721311475		a possibility, dear
15	3.77815699659		a possibility, dear
16	3.20512820513		the people have spoken
17	3.11956521739		the people have spoken
18	2.8		the people have spoken
19	3.95652173913		a possibility, dear

That's what I promised you you wouldn't need to do.

The hard part is to pick among them!

Profoundly badass is the groupby method. As its name suggests, it takes a series or dataframe and groups the data by a column of your choosing. You then perform a function on each group.

In [65]:
individual_ratings.groupby(by="item_id").mean()
Out[65]:
user_id rating
item_id
1 477.011062 3.878319
2 492.007634 3.206107
3 459.133333 3.033333
4 469.497608 3.550239
5 439.372093 3.302326
6 454.576923 3.576923
7 445.369898 3.798469
8 454.675799 3.995434
9 460.321070 3.896321
10 450.213483 3.831461
11 440.762712 3.847458
12 448.382022 4.385768
13 436.668478 3.418478
14 458.836066 3.967213
15 459.525597 3.778157
16 503.692308 3.205128
17 441.489130 3.119565
18 219.200000 2.800000
19 489.376812 3.956522
20 478.916667 3.416667
21 450.821429 2.761905
22 471.000000 4.151515
23 466.203297 4.120879
24 458.477011 3.448276
25 449.901024 3.443686
26 472.945205 3.452055
27 467.508772 3.105263
28 465.710145 3.931159
29 466.859649 2.666667
30 483.945946 3.945946
... ... ...
1653 675.000000 5.000000
1654 676.000000 1.000000
1655 682.000000 2.000000
1656 798.000000 3.500000
1657 727.000000 3.000000
1658 803.000000 3.000000
1659 747.000000 1.000000
1660 747.000000 2.000000
1661 751.000000 1.000000
1662 772.000000 2.500000
1663 782.000000 2.000000
1664 842.750000 3.250000
1665 782.000000 2.000000
1666 782.000000 2.000000
1667 782.000000 3.000000
1668 782.000000 3.000000
1669 782.000000 2.000000
1670 782.000000 3.000000
1671 787.000000 1.000000
1672 862.000000 2.000000
1673 835.000000 3.000000
1674 840.000000 4.000000
1675 851.000000 3.000000
1676 851.000000 2.000000
1677 854.000000 3.000000
1678 863.000000 1.000000
1679 863.000000 3.000000
1680 863.000000 2.000000
1681 896.000000 3.000000
1682 916.000000 3.000000

1682 rows × 2 columns

Pivot

What if we wanted to have a big table where each row is the user followed by all her ratings? We could write a few lines of code to produce this.

What would such code look like?

Fortunately, Pandas will do this heavy lifting for us using the pivot method.

In [35]:
ratings=individual_ratings.pivot(index="user_id", columns="item_id", values="rating")

Basically: rework our data using user_id as row names; item_id as column names and all the ratings as the values

In [36]:
ratings[100:115]
Out[36]:
item_id 1 2 3 4 5 6 7 8 9 10 ... 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
user_id
101 3 NaN NaN NaN NaN NaN 3 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
102 3 2 NaN 2 3 NaN 2 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
103 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
104 NaN NaN 3 NaN NaN NaN 3 NaN 2 2 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
105 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
106 4 NaN NaN NaN NaN NaN NaN 4 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
107 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
108 4 NaN NaN NaN NaN NaN 5 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
109 4 NaN NaN 2 3 NaN 4 3 3 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
110 NaN 3 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
111 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
112 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
113 NaN NaN NaN NaN NaN NaN 3 NaN 3 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
114 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
115 NaN NaN NaN 4 NaN NaN 5 5 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

15 rows × 1682 columns

Question to the user: Why all the NaNs?

Another question to the user: Why not switch all the NaNs to zeros?

Question: What did we lose from our original dataframe?

Question: What questions could no longer ask?

- say we wanted to know whether people rate movies differently at different times of the day? or differently during different seasons?.

In the biz, this is called a sparse matrix. Sparse matrixes are the heart of all data mining of consumers--Amazon ranking, Netflix recommendations--and lots of search technologies--Google, etc.

Simple statistical operations

Pandas lets us easily compute standard statistics across columns, rows and so forth.

The commands require us to refer to the columns and rows by their respective 'axis' number:

0 for going DOWN a column--so the ratings given by ALL users to a ONE film

1 for going ACROSS a row--so the ratings given by ONE user to ALL the films

(There is only Axis, no Allies).

Let's start looking into the ratings. We can use the mean method on a dataframe type. We need to say which direction we mean to mean.

In [71]:
ratings.mean(axis=0) #average rating per film (axis 0)
Out[71]:
item_id
1          3.878319
2          3.206107
3          3.033333
4          3.550239
5          3.302326
6          3.576923
7          3.798469
8          3.995434
9          3.896321
10         3.831461
11         3.847458
12         4.385768
13         3.418478
14         3.967213
15         3.778157
...
1668       3
1669       2
1670       3
1671       1
1672       2
1673       3
1674       4
1675       3
1676       2
1677       3
1678       1
1679       3
1680       2
1681       3
1682       3
Length: 1682, dtype: float64
In [70]:
ratings.mean(1) #we can drop the axis= bit if we want
Out[70]:
user_id
1          3.610294
2          3.709677
3          2.796296
4          4.333333
5          2.874286
6          3.635071
7          3.965261
8          3.796610
9          4.272727
10         4.206522
11         3.464088
12         4.392157
13         3.097484
14         4.091837
15         2.875000
...
929        3.693878
930        2.968254
931        3.721311
932        3.966805
933        2.646739
934        3.701149
935        3.923077
936        3.746479
937        3.375000
938        3.268519
939        4.265306
940        3.457944
941        4.045455
942        4.265823
943        3.410714
Length: 943, dtype: float64

What are the top ranked films? The .order() method will order our series by values.

In [172]:
ratings.mean(0).order()
Out[172]:
item_id
1659       0.75
1564       1.00
1364       1.00
1587       1.00
439        1.00
1586       1.00
858        1.00
1366       1.00
437        1.00
852        1.00
1584       1.00
1373       1.00
1349       1.00
1583       1.00
1348       1.00
...
64         4.282686
169        4.290254
408        4.354911
119        4.500000
1398       4.500000
1642       4.500000
1293       4.583333
1189       4.583333
1449       4.625000
1599       5.000000
1536       5.000000
814        5.000000
1500       5.000000
1467       5.000000
1653       5.000000
Length: 1682, dtype: float64

We might want to disregard movies with a low number of ratings. We need to know how many each film got.

The count method will tell us how many non NaN values there are, so we can know if there are lots of ratings, or only a few.

How many users have rated each film:

In [72]:
ratings.count(0)
Out[72]:
item_id
1          452
2          131
3           90
4          209
5           86
6           26
7          392
8          219
9          299
10          89
11         236
12         267
13         184
14         183
15         293
...
1668       1
1669       1
1670       1
1671       1
1672       2
1673       1
1674       1
1675       1
1676       1
1677       1
1678       1
1679       1
1680       1
1681       1
1682       1
Length: 1682, dtype: int64

How many films every user has rated:

In [73]:
ratings.count(1)
Out[73]:
user_id
1          272
2           62
3           54
4           24
5          175
6          211
7          403
8           59
9           22
10         184
11         181
12          51
13         636
14          98
15         104
...
929         49
930         63
931         61
932        241
933        184
934        174
935         39
936        142
937         40
938        108
939         49
940        107
941         22
942         79
943        168
Length: 943, dtype: int64

The method describe computes a variety of standard statistics for the items.

In [74]:
ratings.describe()
/usr/local/lib/python2.7/dist-packages/pandas/core/generic.py:3549: FutureWarning: The `percentile_width` keyword is deprecated. Use percentiles=[0.25, 0.5, 0.75] instead
  warnings.warn(msg, FutureWarning)
Out[74]:
item_id 1 2 3 4 5 6 7 8 9 10 ... 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
count 452.000000 131.000000 90.000000 209.000000 86.000000 26.000000 392.000000 219.000000 299.000000 89.000000 ... 1 1 1 1 1 1 1 1 1 1
mean 3.878319 3.206107 3.033333 3.550239 3.302326 3.576923 3.798469 3.995434 3.896321 3.831461 ... 3 4 3 2 3 1 3 2 3 3
std 0.927897 0.966497 1.212760 0.965069 0.946446 1.301478 0.982037 1.002281 1.042368 1.013948 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
min 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 ... 3 4 3 2 3 1 3 2 3 3
25% 3.000000 3.000000 2.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 ... 3 4 3 2 3 1 3 2 3 3
50% 4.000000 3.000000 3.000000 4.000000 3.000000 4.000000 4.000000 4.000000 4.000000 4.000000 ... 3 4 3 2 3 1 3 2 3 3
75% 5.000000 4.000000 4.000000 4.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 ... 3 4 3 2 3 1 3 2 3 3
max 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 ... 3 4 3 2 3 1 3 2 3 3

8 rows × 1682 columns

Back to the ratings... what doesn't suck?

How can use use boolean indexing to find what doesn't suck according to the masses?

In [76]:
ratings.mean(0)>4.25
Out[76]:
item_id
1          False
2          False
3          False
4          False
5          False
6          False
7          False
8          False
9          False
10         False
11         False
12          True
13         False
14         False
15         False
...
1668       False
1669       False
1670       False
1671       False
1672       False
1673       False
1674       False
1675       False
1676       False
1677       False
1678       False
1679       False
1680       False
1681       False
1682       False
Length: 1682, dtype: bool
In [77]:
the_good_stuff=ratings.mean(0)>4.25

And if we want a dataframe of just the good stuff?

In [86]:
ratings[the_good_stuff]
Out[86]:
item_id 1 2 3 4 5 6 7 8 9 10 ... 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
user_id
12 NaN NaN NaN 5 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
50 NaN NaN NaN NaN NaN NaN NaN NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
64 4 3 NaN 3 NaN NaN 4 4 4 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
98 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
114 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
119 NaN NaN NaN NaN NaN NaN 5 NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
127 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
134 5 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
169 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
174 3 NaN NaN NaN NaN NaN NaN NaN 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
178 4 4 NaN NaN NaN NaN 4 4 2 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
251 4 NaN NaN NaN NaN NaN 3 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
272 NaN NaN NaN NaN NaN NaN NaN 4 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
285 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
318 NaN NaN NaN 2 NaN NaN NaN 4 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
357 5 NaN NaN NaN NaN NaN 3 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
408 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
427 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
474 NaN NaN NaN 5 NaN NaN 5 5 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
479 5 NaN NaN NaN NaN NaN NaN 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
480 NaN NaN NaN NaN NaN NaN NaN 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
483 4 NaN NaN NaN NaN NaN NaN NaN 2 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
513 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
603 NaN NaN NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
657 3 NaN NaN NaN NaN NaN 3 NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
814 NaN NaN NaN NaN 3 NaN 4 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

26 rows × 1682 columns

No, no, no, no!

We want to use boolean indexing across the columns but clever pandas has done it on the rows. Good thing we checked.

We can use a more precise way of indexing a dataframe, the .loc method, which takes .loc[rows,columns].

In [85]:
ratings.loc[:,the_good_stuff]
Out[85]:
item_id 12 50 64 98 114 119 127 134 169 174 ... 1398 1449 1467 1500 1536 1594 1599 1639 1642 1653
user_id
1 5 5 5 4 5 5 5 4 5 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN 5 NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN 5 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN 4 NaN 3 NaN NaN NaN NaN 5 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 4 4 4 5 NaN NaN 5 5 4 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 5 5 5 4 NaN NaN 5 4 NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN 5 NaN NaN NaN NaN 5 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN 5 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
10 5 5 4 4 NaN NaN 5 5 NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
11 2 NaN NaN 2 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
12 NaN 4 NaN 5 NaN NaN 4 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
13 5 5 5 4 NaN NaN 5 NaN NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
14 5 5 NaN 3 NaN NaN 2 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
15 NaN 5 NaN NaN NaN NaN 2 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
16 5 NaN 5 5 NaN NaN 5 4 NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
17 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
18 5 4 5 5 NaN NaN 5 5 5 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
19 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
20 NaN 3 NaN 3 NaN NaN NaN NaN NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
21 NaN 3 NaN 5 NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
22 NaN 5 NaN NaN NaN NaN 5 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
23 NaN 4 NaN 5 NaN NaN NaN 4 NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
24 5 NaN 5 5 NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
25 NaN 5 NaN 5 5 NaN 3 4 5 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
26 NaN 4 NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27 NaN 3 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
28 4 4 NaN 5 NaN NaN NaN NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
29 5 NaN NaN 4 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
30 NaN 3 NaN NaN NaN NaN NaN NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
914 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
915 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
916 4 5 5 5 NaN NaN NaN 5 NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
917 NaN 3 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
918 NaN NaN 4 NaN NaN NaN NaN NaN NaN 3 ... NaN NaN NaN NaN NaN NaN NaN 5 NaN NaN
919 3 3 5 5 NaN NaN NaN NaN NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
920 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
921 NaN 4 NaN NaN NaN NaN NaN NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
922 NaN 5 NaN 5 NaN NaN 3 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
923 NaN 5 NaN NaN NaN NaN NaN NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
924 4 5 4 NaN 3 NaN 3 4 NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
925 NaN NaN NaN 4 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
926 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
927 NaN NaN 5 NaN NaN NaN NaN NaN NaN 3 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
928 NaN NaN NaN 5 5 NaN 5 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
929 4 4 NaN 5 NaN NaN 5 4 NaN 3 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
930 NaN 2 4 NaN NaN NaN NaN NaN NaN 3 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
931 NaN 3 NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
932 NaN NaN 2 5 5 5 NaN 4 5 4 ... NaN 5 NaN NaN NaN NaN NaN NaN NaN NaN
933 4 4 5 5 NaN NaN 5 NaN NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
934 NaN 5 NaN NaN NaN NaN NaN 4 NaN 5 ... NaN 5 NaN NaN NaN NaN NaN NaN NaN NaN
935 NaN NaN NaN NaN NaN NaN 4 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
936 NaN 4 NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
937 NaN 5 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
938 NaN 5 NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
939 NaN NaN NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
940 4 4 NaN 4 NaN NaN NaN NaN NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
941 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
942 NaN 5 NaN NaN NaN NaN NaN NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
943 5 4 5 5 NaN NaN 5 NaN NaN 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

943 rows × 42 columns

Cool! What are the average ratings per user?

We need to use mean across columns.

In [89]:
ratings.mean(1) #average rating per user axis 1 is rows--user ids
Out[89]:
user_id
1          3.610294
2          3.709677
3          2.796296
4          4.333333
5          2.874286
6          3.635071
7          3.965261
8          3.796610
9          4.272727
10         4.206522
11         3.464088
12         4.392157
13         3.097484
14         4.091837
15         2.875000
...
929        3.693878
930        2.968254
931        3.721311
932        3.966805
933        2.646739
934        3.701149
935        3.923077
936        3.746479
937        3.375000
938        3.268519
939        4.265306
940        3.457944
941        4.045455
942        4.265823
943        3.410714
Length: 943, dtype: float64
In [90]:
ratings.mean(1)>4 # axis 1 is rows--user ids
Out[90]:
user_id
1          False
2          False
3          False
4           True
5          False
6          False
7          False
8          False
9           True
10          True
11         False
12          True
13         False
14          True
15         False
...
929        False
930        False
931        False
932        False
933        False
934        False
935        False
936        False
937        False
938        False
939         True
940        False
941         True
942         True
943        False
Length: 943, dtype: bool
In [91]:
those_lacking_discernment=ratings.mean(1)>4
In [92]:
ratings[those_lacking_discernment]
Out[92]:
item_id 1 2 3 4 5 6 7 8 9 10 ... 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
user_id
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN 5 4 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
10 4 NaN NaN 4 NaN NaN 4 NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
12 NaN NaN NaN 5 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
14 NaN NaN NaN NaN NaN NaN 5 NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
16 5 NaN NaN 5 NaN NaN 5 5 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
24 NaN NaN NaN NaN NaN NaN 4 5 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
25 5 NaN NaN NaN NaN NaN 4 4 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
34 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
46 NaN NaN NaN NaN NaN NaN 4 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
52 NaN NaN NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
60 NaN NaN NaN NaN NaN NaN 5 3 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
89 5 NaN NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
90 NaN NaN NaN NaN NaN 4 NaN 5 4 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
96 5 NaN NaN NaN NaN NaN 5 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
97 4 NaN NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
118 NaN NaN NaN NaN 2 NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
127 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
131 4 NaN NaN NaN NaN NaN NaN NaN 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
136 NaN NaN NaN NaN NaN NaN NaN NaN 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
137 3 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
138 4 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
147 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
152 NaN NaN NaN NaN NaN NaN NaN 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
164 NaN NaN NaN NaN NaN NaN NaN NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
173 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
185 NaN NaN NaN NaN NaN NaN NaN NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
187 NaN NaN NaN NaN NaN NaN NaN 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
200 5 4 NaN NaN NaN NaN 4 4 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
210 5 NaN NaN 4 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
770 5 NaN NaN NaN NaN NaN 5 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
777 4 NaN NaN NaN NaN NaN NaN NaN 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
794 4 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
801 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
808 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
810 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
811 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
819 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
821 5 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
823 4 NaN NaN 5 NaN NaN 5 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
835 3 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
838 5 NaN NaN NaN NaN NaN 5 4 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
840 NaN NaN NaN NaN NaN NaN 4 5 NaN NaN ... NaN 4 NaN NaN NaN NaN NaN NaN NaN NaN
848 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
849 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
850 NaN NaN NaN NaN NaN NaN NaN 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
862 NaN NaN NaN NaN NaN NaN 5 NaN NaN 5 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
867 4 NaN NaN NaN NaN NaN 5 NaN 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
875 NaN NaN NaN 3 NaN NaN NaN 3 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
876 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
882 5 NaN NaN 4 NaN NaN 4 5 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
888 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
891 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
907 5 NaN NaN NaN 5 NaN NaN 3 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
909 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
923 3 NaN 4 NaN NaN NaN NaN NaN 4 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
928 NaN NaN NaN NaN NaN NaN NaN 5 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
939 NaN NaN NaN NaN NaN NaN NaN NaN 5 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
941 5 NaN NaN NaN NaN NaN 4 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
942 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

147 rows × 1682 columns

Question for the reader:

Could you create a new ratings dataframe excluding all those lacking discernment, i.e. excluding people who have a mean rating > 4? It's on the home work!

What might we want to do with our new knowledge

Let's discount the less discerning viewers! Let's just lower their rankings by .75. A bit arbitrary, but so are they!

We can multiply every element in a dataframe by a constant like so:

In [105]:
ratings[those_lacking_discernment]*.75
Out[105]:
item_id 1 2 3 4 5 6 7 8 9 10 ... 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
user_id
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN 3.75 3.00 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
10 3.00 NaN NaN 3.00 NaN NaN 3.00 NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
12 NaN NaN NaN 3.75 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
14 NaN NaN NaN NaN NaN NaN 3.75 NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
16 3.75 NaN NaN 3.75 NaN NaN 3.75 3.75 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
24 NaN NaN NaN NaN NaN NaN 3.00 3.75 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
25 3.75 NaN NaN NaN NaN NaN 3.00 3.00 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
34 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
46 NaN NaN NaN NaN NaN NaN 3.00 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
52 NaN NaN NaN NaN NaN NaN 3.75 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
60 NaN NaN NaN NaN NaN NaN 3.75 2.25 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
89 3.75 NaN NaN NaN NaN NaN 3.75 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
90 NaN NaN NaN NaN NaN 3.00 NaN 3.75 3.00 3.75 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
96 3.75 NaN NaN NaN NaN NaN 3.75 3.75 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
97 3.00 NaN NaN NaN NaN NaN 3.75 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
118 NaN NaN NaN NaN 1.50 NaN 3.75 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
127 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
131 3.00 NaN NaN NaN NaN NaN NaN NaN 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
136 NaN NaN NaN NaN NaN NaN NaN NaN 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
137 2.25 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
138 3.00 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
147 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
152 NaN NaN NaN NaN NaN NaN NaN 3.75 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
164 NaN NaN NaN NaN NaN NaN NaN NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
173 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
185 NaN NaN NaN NaN NaN NaN NaN NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
187 NaN NaN NaN NaN NaN NaN NaN 3.75 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
200 3.75 3 NaN NaN NaN NaN 3.00 3.00 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
210 3.75 NaN NaN 3.00 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
770 3.75 NaN NaN NaN NaN NaN 3.75 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
777 3.00 NaN NaN NaN NaN NaN NaN NaN 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
794 3.00 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
801 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
808 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
810 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
811 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
819 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
821 3.75 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
823 3.00 NaN NaN 3.75 NaN NaN 3.75 3.75 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
835 2.25 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 2.25 NaN NaN NaN NaN NaN NaN NaN NaN NaN
838 3.75 NaN NaN NaN NaN NaN 3.75 3.00 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
840 NaN NaN NaN NaN NaN NaN 3.00 3.75 NaN NaN ... NaN 3 NaN NaN NaN NaN NaN NaN NaN NaN
848 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
849 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
850 NaN NaN NaN NaN NaN NaN NaN 3.75 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
862 NaN NaN NaN NaN NaN NaN 3.75 NaN NaN 3.75 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
867 3.00 NaN NaN NaN NaN NaN 3.75 NaN 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
875 NaN NaN NaN 2.25 NaN NaN NaN 2.25 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
876 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
882 3.75 NaN NaN 3.00 NaN NaN 3.00 3.75 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
888 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
891 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
907 3.75 NaN NaN NaN 3.75 NaN NaN 2.25 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
909 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
923 2.25 NaN 3 NaN NaN NaN NaN NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
928 NaN NaN NaN NaN NaN NaN NaN 3.75 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
939 NaN NaN NaN NaN NaN NaN NaN NaN 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
941 3.75 NaN NaN NaN NaN NaN 3.00 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
942 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

147 rows × 1682 columns

In [109]:
adjusted_ratings[those_lacking_discernment]=ratings[those_lacking_discernment]*.75

A lot of the movies lack very many ratings. Let's exclude them for now. We can tell how many ratings each column has with the .count method.

In [146]:
ratings.count()
Out[146]:
item_id
1          452
2          131
3           90
4          209
5           86
6           26
7          392
8          219
9          299
10          89
11         236
12         267
13         184
14         183
15         293
...
1668       1
1669       1
1670       1
1671       1
1672       2
1673       1
1674       1
1675       1
1676       1
1677       1
1678       1
1679       1
1680       1
1681       1
1682       1
Length: 1682, dtype: int64
In [150]:
ratings.count()>10
Out[150]:
item_id
1          True
2          True
3          True
4          True
5          True
6          True
7          True
8          True
9          True
10         True
11         True
12         True
13         True
14         True
15         True
...
1668       False
1669       False
1670       False
1671       False
1672       False
1673       False
1674       False
1675       False
1676       False
1677       False
1678       False
1679       False
1680       False
1681       False
1682       False
Length: 1682, dtype: bool

We can use this index to produce a new dataframe of only the often rated movies.

In [157]:
ratings.loc[:,(ratings.count()>10)] 
Out[157]:
item_id 1 2 3 4 5 6 7 8 9 10 ... 1421 1428 1444 1446 1451 1469 1478 1480 1483 1518
user_id
1 5.00 3 4 3.00 3 5.00 4.00 1.00 5.00 3 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 4.00 NaN NaN NaN NaN NaN NaN NaN NaN 2 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 4.00 3 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 4.00 NaN NaN NaN NaN NaN 2.00 4.00 4.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN 5.00 NaN NaN 5.00 5.00 5.00 4 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN 3.00 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN 3.75 3.00 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
10 3.00 NaN NaN 3.00 NaN NaN 3.00 NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
11 NaN NaN NaN NaN NaN NaN NaN 4.00 5.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
12 NaN NaN NaN 3.75 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
13 3.00 3 NaN 5.00 1 NaN 2.00 4.00 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
14 NaN NaN NaN NaN NaN NaN 3.75 NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
15 1.00 NaN NaN NaN NaN NaN 1.00 NaN 4.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
16 3.75 NaN NaN 3.75 NaN NaN 3.75 3.75 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
17 4.00 NaN NaN NaN NaN NaN 4.00 NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
18 5.00 NaN NaN 3.00 NaN 5.00 NaN 5.00 5.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
19 NaN NaN NaN 4.00 NaN NaN NaN 5.00 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
20 3.00 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
21 5.00 NaN NaN NaN 2 NaN 5.00 NaN 5.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
22 NaN 2 NaN 5.00 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
23 5.00 NaN NaN NaN NaN NaN 4.00 4.00 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
24 NaN NaN NaN NaN NaN NaN 3.00 3.75 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
25 3.75 NaN NaN NaN NaN NaN 3.00 3.00 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
26 3.00 NaN NaN NaN NaN NaN 3.00 NaN 4.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27 NaN NaN NaN NaN NaN NaN NaN NaN 4.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
28 NaN NaN NaN NaN 3 NaN 5.00 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
29 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
30 NaN 3 NaN NaN NaN NaN 4.00 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
914 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
915 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
916 4.00 3 3 4.00 3 NaN 4.00 NaN 5.00 NaN ... NaN 3 NaN NaN NaN NaN NaN NaN NaN NaN
917 3.00 NaN 1 NaN NaN NaN NaN NaN 5.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
918 3.00 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
919 4.00 NaN NaN 1.00 4 NaN 3.00 NaN 5.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
920 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
921 3.00 NaN NaN NaN NaN NaN NaN 3.00 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
922 5.00 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
923 2.25 NaN 3 NaN NaN NaN NaN NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
924 5.00 3 NaN NaN NaN 4.00 4.00 NaN 4.00 NaN ... NaN NaN NaN NaN NaN NaN 4 NaN NaN NaN
925 NaN NaN NaN NaN 4 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
926 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
927 5.00 NaN NaN NaN NaN NaN 3.00 4.00 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
928 NaN NaN NaN NaN NaN NaN NaN 3.75 3.75 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
929 3.00 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
930 3.00 NaN NaN NaN NaN NaN NaN 3.00 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
931 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
932 4.00 NaN NaN NaN NaN NaN 4.00 NaN 5.00 NaN ... NaN NaN NaN NaN 5 NaN NaN NaN NaN NaN
933 3.00 NaN NaN 3.00 NaN NaN 4.00 NaN 3.00 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
934 2.00 4 NaN 5.00 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
935 3.00 NaN NaN NaN NaN NaN NaN NaN 1.00 NaN