我来做数据--如何对数据进行处理以满足机器学习技术(一):MovieLens数据

标签(空格分隔): 数据分析 python 数据挖掘


MovieLens 1M数据集

一组从20世纪90年末到21世纪初由MovieLens用户提供的电影评分数据。这些数据中包括电影评分、电影元数据(风格类型和年代)以及关于用户的人口统计学数据(年龄、邮编、性别和职业等)。

MovieLens 1M数据集含有来自6000名用户对4000部电影的100万条评分数据。分为三个表:评分、用户信息和电影信息。
以下代码,通过pandas.read_table将各个表分别读到一个pandas DataFrame对象中:

import pandas as pd

unames = ['user_id', 'gender', 'age', 'occupation', 'zip']
users = pd.read_table('G:\\lcw\\movielens\\users.dat', sep='::', header=None, names=unames)

rnames = ['user_id', 'movie_id', 'rating', 'timestamp']
ratings = pd.read_table('G:\\lcw\\movielens\\ratings.dat', sep='::', header=None, names=rnames)

mnames = ['movie_id', 'title', 'genres']
movies = pd.read_table('G:\\lcw\\movielens\\movies.dat', sep='::', header=None, names=mnames)

# 如果是读取CSV的数据格式(说明):
import pandas as pd
  
# Reading data locally
df = pd.read_csv('/Users/al-ahmadgaidasaad/Documents/d.csv')
  
# Reading data from web
data_url = "https://raw.githubusercontent.com/alstat/Analysis-with-Programming/master/2014/Python/Numerical-Descriptions-of-the-Data/data.csv"
df = pd.read_csv(data_url)

问题:对分布在三个表的数据进行分析同时进行分析很难,那必须将所有的数据都合并到一个表中进行分析,下面,用pandas的merge函数将ratings跟users合并到一起,然后再将movies也合并进去。pandas会根据列名的重叠情况推断出哪些列是合并(或连接)键:

>>> data = pd.merge(pd.merge(ratings,users),movies)
>>> data
         user_id  movie_id  rating   timestamp gender  age  occupation    zip  \
0              1      1193       5   978300760      F    1          10  48067   
1              2      1193       5   978298413      M   56          16  70072   
2             12      1193       4   978220179      M   25          12  32793   
3             15      1193       4   978199279      M   25           7  22903   
4             17      1193       5   978158471      M   50           1  95350   
5             18      1193       4   978156168      F   18           3  95825   
6             19      1193       5   982730936      M    1          10  48073   
7             24      1193       5   978136709      F   25           7  10023   
8             28      1193       3   978125194      F   25           1  14607   
9             33      1193       5   978557765      M   45           3  55421   
10            39      1193       5   978043535      M   18           4  61820   
11            42      1193       3   978038981      M   25           8  24502   

下面对pandas进行聚类操作:
1、按性别计算每部电影的平均得分,用Pivot_table方法:

DataFrame 对象有一个 .pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean', fill_value=None, margins=False, dropna=True) 方法可以用来制作透视表,同时 pd.pivot_table() 也是一个顶层函数。

    • data 参数相当于 self,这里将其命名为 data 也许是为了与顶级函数版本的 pivot_table 保持一致。
    • values 参数可以是一个以列名为元素的列表,用于指定想要聚合的数据,不给出的话默认使用全部数据。
    • rows 参数用于指定行分组键
    • cols 参数用于指定列分组键
    • aggfunc 参数用于指定聚合函数,默认为均值(mean),也可以是np.sum
    • margins 参数是小计(Total)功能的开关,设为 True 后结果集中会出现名为 “ALL” 的行和列
>>> df
   A   B   C      D
0  foo one small  1
1  foo one large  2
2  foo one large  2
3  foo two small  3
4  foo two small  3
5  bar one large  4
6  bar one small  5
7  bar two small  6
8  bar two large  7
>>> table = pivot_table(df, values='D', rows=['A', 'B'], cols=['C'], aggfunc=np.sum)
>>> table
          small  large
foo  one  1      4
     two  6      NaN
bar  one  5      4
     two  6      7

具体实例:

>>> mean_ratings = data.pivot_table('rating', rows='title',cols='gender',aggfunc='mean')
>>> mean_ratings[:5]
gender                                F         M
title                                            
$1,000,000 Duck (1971)         3.375000  2.761905
'Night Mother (1986)           3.388889  3.352941
'Til There Was You (1997)      2.675676  2.733333
'burbs, The (1989)             2.793478  2.962085
...And Justice for All (1979)  3.828571  3.689024
  • ps 该操作产生了另一个DataFrame,其内容为电影平均得分,行标为电影名称,列表为性别。

2、过滤掉评分数据不够250条的电影,为了达到这个目的,先对title进行分组,然后利用size() 得到一个含有各电影分组大小的Series对象:

>>> ratings_by_titlr = data.groupby('title').size()
>>> ratings_by_titlr[:10]
title
$1,000,000 Duck (1971)                37
'Night Mother (1986)                  70
'Til There Was You (1997)             52
'burbs, The (1989)                   303
...And Justice for All (1979)        199
1-900 (1994)                           2
10 Things I Hate About You (1999)    700
101 Dalmatians (1961)                565
101 Dalmatians (1996)                364
12 Angry Men (1957)                  616
dtype: int64
>>> active_titles = ratings_by_titlr.index[ratings_by_titlr >250]
>>> active_titles

  • ps 这个地方得到的其实是满足条件的title的Index索引值,然后在下面用索引字段ix中直接获取
    然后从1中切出评论大于250条的电影了:
>>> mean_ratings = mean_ratings.ix[active_titles]
>>> active_titles
Index([u''burbs, The (1989)', u'10 Things I Hate About You (1999)', u'101 Dalmatians (1961)', ...], dtype='object')
  • ps :这个地方用ix[active_titles] 直接获取对应的数据
  • 我们做了个试验:
>>> data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],'year': [2000, 2001, 2002, 2001, 2002],'pop':[1.5, 1.7, 3.6, 2.4, 2.9]}
>>> frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],index=['one', 'two', 'three', 'four', 'five'])
>>> frame2.columns
Index([u'year', u'state', u'pop', u'debt'], dtype='object')
>>> frame2.ix['three']
year     2002
state    Ohio
pop       3.6
debt      NaN
Name: three, dtype: object
>>> obj = frame2.index
>>> frame2.ix[obj]
       year   state  pop debt
one    2000    Ohio  1.5  NaN
two    2001    Ohio  1.7  NaN
three  2002    Ohio  3.6  NaN
four   2001  Nevada  2.4  NaN
five   2002  Nevada  2.9  NaN

这里涉及到切片,DataFrame对象的标准切片语法为:.ix[::,::].ix对象可以接受两套切片,分别为行(axis =0)和列(axis =1)的方向:

>>> df
   Ohio  Texas  California
a     0      1           2
c     3      4           5
d     6      7           8

[3 rows x 3 columns]

>>> df.ix[:2,:2]
   Ohio  Texas
a     0      1
c     3      4

[2 rows x 2 columns]

>>> df.ix['a','Ohio']
0

而不使用 ix,直接切的情况就特殊了:索引时,选取的是列,切片时,选取的是行

>>> df['Ohio']
a    0
c    3
d    6
Name: Ohio, dtype: int32
>>> df[:'c']
   Ohio  Texas  California
a     0      1           2
c     3      4           5

[2 rows x 3 columns]
>>> df[:2]
   Ohio  Texas  California
a     0      1           2
c     3      4           5

[2 rows x 3 columns]

使用布尔型数组的情况,注意行与列的不同切法(列切法的“:”不能省)

>>> df['Texas']>=4
a    False
c     True
d     True
Name: Texas, dtype: bool
>>> df[df['Texas']>=4]
   Ohio  Texas  California
c     3      4           5
d     6      7           8

[2 rows x 3 columns]
>>> df.ix[:,df.ix['c']>=4]
   Texas  California
a      1           2
c      4           5
d      7           8

[3 rows x 2 columns]
  • 我只是不知道为什么不能显示摘要模式
    接下来就是对某一行的数据进行排列,主要用到的是sort_index
>>> top_female_ratings = mean_ratings.sort_index(by = 'F', ascending = False)
>>> top_female_ratings
  • Series 的sort_index(ascending=True) 方法可以对index进行排序操作,ascdending 参数用于控制升序或者降序,默认是升序 DataFrame 上,.sort_index(axis=0, by=None, ascending=True) 方法多了一个轴向的选择参数与一个 by 参数,by 参数的作用是针对某一(些)列进行排序(不能对行使用 by 参数):。

3、计算评分分歧,找出男性和女性观众分歧最大的电影。在mean_ratings 加上一个用于存放平均得分之差的列,并对其进行排序:

mean_ratings['diff'] = mean_ratings['M'] - mean_ratings['F']
>>> sort_by_diff = mean_ratings.sort_index(by='diff')
>>> sort_by_diff[:15]
gender                                        F         M      diff
title                                                              
Dirty Dancing (1987)                   3.790378  2.959596 -0.830782
Jumpin' Jack Flash (1986)              3.254717  2.578358 -0.676359
Grease (1978)                          3.975265  3.367041 -0.608224
Little Women (1994)                    3.870588  3.321739 -0.548849
Steel Magnolias (1989)                 3.901734  3.365957 -0.535777
Anastasia (1997)                       3.800000  3.281609 -0.518391
Rocky Horror Picture Show, The (1975)  3.673016  3.160131 -0.512885
Color Purple, The (1985)               4.158192  3.659341 -0.498851
Age of Innocence, The (1993)           3.827068  3.339506 -0.487561
Free Willy (1993)                      2.921348  2.438776 -0.482573
French Kiss (1995)                     3.535714  3.056962 -0.478752
Little Shop of Horrors, The (1960)     3.650000  3.179688 -0.470312
Guys and Dolls (1955)                  4.051724  3.583333 -0.468391
Mary Poppins (1964)                    4.197740  3.730594 -0.467147
Patch Adams (1998)                     3.473282  3.008746 -0.464536

对排序结果反序并取出前15行,得到的则是观众更喜欢的电影:[:: -1] 取反

>>> sort_by_diff[:: -1][:15]
gender                                         F         M      diff
title                                                               
Good, The Bad and The Ugly, The (1966)  3.494949  4.221300  0.726351
Kentucky Fried Movie, The (1977)        2.878788  3.555147  0.676359
Dumb & Dumber (1994)                    2.697987  3.336595  0.638608
Longest Day, The (1962)                 3.411765  4.031447  0.619682
Cable Guy, The (1996)                   2.250000  2.863787  0.613787
Evil Dead II (Dead By Dawn) (1987)      3.297297  3.909283  0.611985
Hidden, The (1987)                      3.137931  3.745098  0.607167
Rocky III (1982)                        2.361702  2.943503  0.581801
Caddyshack (1980)                       3.396135  3.969737  0.573602
For a Few Dollars More (1965)           3.409091  3.953795  0.544704
Porky's (1981)                          2.296875  2.836364  0.539489
Animal House (1978)                     3.628906  4.167192  0.538286
Exorcist, The (1973)                    3.537634  4.067239  0.529605
Fright Night (1985)                     2.973684  3.500000  0.526316
Barb Wire (1996)                        1.585366  2.100386  0.515020

但是,只是想要找出分歧最大的电影(不考虑性别因素),则可以计算得分数据的方差或者标准差

>>> rating_std_by_title = data.groupby('title')['rating'].std()
>>> rating_std_by_title
title
$1,000,000 Duck (1971)                 1.092563
'Night Mother (1986)                   1.118636
'Til There Was You (1997)              1.020159
'burbs, The (1989)                     1.107760
...And Justice for All (1979)          0.878110
1-900 (1994)                           0.707107
10 Things I Hate About You (1999)      0.989815
101 Dalmatians (1961)                  0.982103
101 Dalmatians (1996)                  1.098717
12 Angry Men (1957)                    0.812731
13th Warrior, The (1999)               1.140421
187 (1997)                             1.057919
2 Days in the Valley (1996)            0.921592
20 Dates (1998)                        1.151943
20,000 Leagues Under the Sea (1954)    0.869685
...
Name: rating, Length: 3706, dtype: float64
  • 注意,这个地方用了groupby 默认的情况下就是统计这个属性出现的次数,但是,就像我们用mysql一样,用了groupby,肯定也会有很多相关的统计的方法:
    一些numpy常用的统计方法:
  • count 非 NA 值的数量
  • describe 针对 Series 或 DF 的列计算汇总统计
  • min , max 最小值和最大值
  • argmin , argmax 最小值和最大值的索引位置(整数)
  • idxmin , idxmax 最小值和最大值的索引值
  • quantile 样本分位数(0 到 1)
  • sum 求和
  • mean 均值
  • median 中位数
  • mad 根据均值计算平均绝对离差
  • var 方差
  • std 标准差
  • skew 样本值的偏度(三阶矩)
  • kurt 样本值的峰度(四阶矩)
  • cumsum 样本值的累计和
  • cummin , cummax 样本值的累计最大值和累计最小值
  • cumprod 样本值的累计积
  • diff 计算一阶差分(对时间序列很有用)
  • pct_change 计算百分数变化

接下来,过滤掉评论不足250条的记录:

>>> rating_std_by_title = rating_std_by_title.ix[active_titles]
>>> rating_std_by_title .order(ascending = False)[: 10]
title
Dumb & Dumber (1994)                     1.321333
Blair Witch Project, The (1999)          1.316368
Natural Born Killers (1994)              1.307198
Tank Girl (1995)                         1.277695
Rocky Horror Picture Show, The (1975)    1.260177
Eyes Wide Shut (1999)                    1.259624
Evita (1996)                             1.253631
Billy Madison (1995)                     1.249970
Fear and Loathing in Las Vegas (1998)    1.246408
Bicentennial Man (1999)                  1.245533
Name: rating, dtype: float64
  • 若要按值对 Series 进行排序,当使用 .order(na_last=True, ascending=True, kind='mergesort') 方法,任何缺失值默认都会被放到 Series 的末尾。
    扩展: 排名(Series.rank(method='average', ascending=True))的作用与排序的不同之处在于,他会把对象的 values 替换成名次(从 1 到 n)。这时唯一的问题在于如何处理平级项,方法里的 method 参数就是起这个作用的,他有四个值可选:average, min, max, first。
>>> ser=Series([3,2,0,3],index=list('abcd'))
>>> ser
a    3
b    2
c    0
d    3
dtype: int64
>>> ser.rank()
a    3.5
b    2.0
c    1.0
d    3.5
dtype: float64
>>> ser.rank(method='min')
a    3
b    2
c    1
d    3
dtype: float64
>>> ser.rank(method='max')
a    4
b    2
c    1
d    4
dtype: float64
>>> ser.rank(method='first')
a    3
b    2
c    1
d    4
dtype: float64
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容