pandas笔记-ch07:数据规整化:清理、转换、合并、重塑
ch07
第七章:数据规整化:清理、转换、合并、重塑¶
In [1]:
from __future__ import division
from numpy.random import randn
import numpy as np
import os
import matplotlib.pyplot as plt
np.random.seed(12345)
plt.rc('figure', figsize=(10, 6))
from pandas import Series, DataFrame
import pandas
import pandas as pd
np.set_printoptions(precision=4, threshold=500)
pd.options.display.max_rows = 100
In [2]:
%matplotlib inline
合并数据集¶
数据库风格的 DataFrame 合并¶
In [16]:
df1 = DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
df2 = DataFrame({'key': ['a', 'b', 'd'],
'data2': range(3)})
df1
Out[16]:
In [4]:
df2
Out[4]:
In [7]:
'默认以重叠的列名进行合并'
pd.merge(df1, df2)
Out[7]:
In [6]:
'on= 最好显式的指定一下要合并的列名:'
pd.merge(df1, df2, on='key')
Out[6]:
In [8]:
'left_on=,right_on= :要合并的列有不同的名称 可以用来分开指定'
df3 = DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
df4 = DataFrame({'rkey': ['a', 'b', 'd'],
'data2': range(3)})
pd.merge(df3, df4, left_on='lkey', right_on='rkey')
Out[8]:
In [11]:
'how= 默认inner,即交集合并,其他还有 left right outer(=left + right)'
pd.merge(df1, df2, how='outer')
Out[11]:
In [17]:
pd.merge(df1, df2, on='key', how='left')
Out[17]:
In [18]:
'多对多的合并:产生的是行的笛卡尔积。例:df1: b*3, df2: b*2, 则 pd.merge(df1,df2): b*3*2'
df1 = DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],
'data1': range(6)})
df2 = DataFrame({'key': ['a', 'b', 'a', 'b', 'd'],
'data2': range(5)})
In [19]:
df1
Out[19]:
In [20]:
df2
Out[20]:
In [22]:
pd.merge(df1, df2, how='inner')
Out[22]:
In [21]:
'连接方式只影响出现在结果中的键'
pd.merge(df1, df2, on='key', how='left')
Out[21]:
In [23]:
'多个键进行合并:传入要合并的列名组成的列表'
left = DataFrame({'key1': ['foo', 'foo', 'bar'],
'key2': ['one', 'two', 'one'],
'lval': [1, 2, 3]})
right = DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'],
'key2': ['one', 'one', 'one', 'two'],
'rval': [4, 5, 6, 7]})
pd.merge(left, right, on=['key1', 'key2'], how='outer')
Out[23]:
In [24]:
pd.merge(left, right, on='key1')
Out[24]:
In [25]:
'suffixes= 对 非合并的列 含有重复列名的处理'
pd.merge(left, right, on='key1', suffixes=('_left', '_right'))
Out[25]:
表7-1:merge函数的参数¶
left 参与合并的左侧DataFrame right 参与合并的右侧DataFrame how 'inner','outer','left','right'其中之一。默认为'inner' on 用于连接的列名。必须存在于左右两个DataFrame对象中。如果未指定,其他连接键也未指定,则以left和right列名的交集作为连接键 left_on 左侧DataFrame中用作连接键的列 right_on 右侧DataFrame中用作连接键的列 left_index 将左侧的行索引用作其连接键 right_index 类似于left_index sort 根据连接键对合并后的数据进行排序,默认为True。有时在处理大数据集时,禁用该选项可获得更好的性能 suffixes 字符串值元组,用于追加到重叠列名的末尾,默认为('_x','_y')。例如,如果左右两个DataFrame对象都有‘data’,则结果中就会出 现‘data_x’和‘data_y’ copy 设置为False,可以在某些特殊情况下避免将数据复制到结果数据结构中。默认总是复制
这部分是测试的内容,可以忽略
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
索引上的合并¶
传入left_index= 或者 right_index= 可以指定一方或者两方使用索引作为合并键
In [26]:
left1 = DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'],
'value': range(6)})
right1 = DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
In [27]:
left1
Out[27]:
In [28]:
right1
Out[28]:
In [31]:
'指定右侧用索引作为合并键'
pd.merge(left1, right1, left_on='key', right_index=True)
Out[31]:
In [30]:
pd.merge(left1, right1, left_on='key', right_index=True, how='outer')
Out[30]:
In [33]:
'层次化的索引的数据合并'
lefth = DataFrame({'key1': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'key2': [2000, 2001, 2002, 2001, 2002],
'data': np.arange(5.)})
righth = DataFrame(np.arange(12).reshape((6, 2)),
index=[['Nevada', 'Nevada', 'Ohio', 'Ohio', 'Ohio', 'Ohio'],
[2001, 2000, 2000, 2000, 2001, 2002]],
columns=['event1', 'event2'])
lefth
Out[33]:
In [34]:
righth
Out[34]:
In [35]:
'解决方法:把要合并的多个列组成列表传递给对应参数'
pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True)
Out[35]:
In [36]:
pd.merge(lefth, righth, left_on=['key1', 'key2'],
right_index=True, how='outer')
Out[36]:
In [37]:
left2 = DataFrame([[1., 2.], [3., 4.], [5., 6.]], index=['a', 'c', 'e'],
columns=['Ohio', 'Nevada'])
right2 = DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]],
index=['b', 'c', 'd', 'e'], columns=['Missouri', 'Alabama'])
In [38]:
left2
Out[38]:
In [39]:
right2
Out[39]:
In [40]:
'同时使用双方的索引作为合并依据'
pd.merge(left2, right2, how='outer', left_index=True, right_index=True)
Out[40]:
In [43]:
'join实例化方法:合并多个带有相同或者相似索引的DataFrame对象,而不管他们之间有没有重叠的列'
'DataFrame的 join 方法在连接键上做左连接'
left2.join(right2, how='outer')
Out[43]:
In [42]:
'left1 的 "key" 列 与 right1的索引作为合并键'
left1.join(right1, on='key')
Out[42]:
In [44]:
another = DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]],
index=['a', 'c', 'e', 'f'], columns=['New York', 'Oregon'])
In [45]:
'多组DataFrame的索引合并:(后面会介绍通用的concat函数,它也可以实现这样的功能)'
left2.join([right2, another])
Out[45]:
In [46]:
left2.join([right2, another], how='outer')
Out[46]:
轴向连接¶
In [47]:
arr = np.arange(12).reshape((3, 4))
In [48]:
arr
Out[48]:
In [49]:
np.concatenate([arr, arr], axis=1)
Out[49]:
In [50]:
s1 = Series([0, 1], index=['a', 'b'])
s2 = Series([2, 3, 4], index=['c', 'd', 'e'])
s3 = Series([5, 6], index=['f', 'g'])
In [51]:
'默认情况下,concat是在axis=0上工作的。'
pd.concat([s1, s2, s3])
Out[51]:
In [52]:
'如果传入axis=1,则会生成一个DataFrame'
'这种情况下,axis=1轴没有重叠'
pd.concat([s1, s2, s3], axis=1)
Out[52]:
In [53]:
s4 = pd.concat([s1 * 5, s3])
In [54]:
pd.concat([s1, s4], axis=1)
Out[54]:
In [55]:
'join=: 指定连接方式是inner,left,right,还是outer'
pd.concat([s1, s4], axis=1, join='inner')
Out[55]:
In [56]:
'join_axes=: 指定索引作为合并键'
pd.concat([s1, s4], axis=1, join_axes=[['a', 'c', 'b', 'e']])
Out[56]:
In [58]:
'keys=: 在连接轴上创建层次化索引:'
result = pd.concat([s1, s1, s3], keys=['one', 'two', 'three'])
In [59]:
result
Out[59]:
In [60]:
#稍后将详细介绍unstack函数
result.unstack()
Out[60]:
In [61]:
'沿着axis=1方向对Series进行合并,keys就会成为DataFrame的列头'
pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three'])
Out[61]:
In [62]:
'axis=1 对DataFrame也是用。 注意:与处理Series的情况不同,此时的 keys= 参数会在连接轴上创建层次化索引'
df1 = DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'],
columns=['one', 'two'])
df2 = DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'],
columns=['three', 'four'])
pd.concat([df1, df2], axis=1, keys=['level1', 'level2'])
Out[62]:
In [63]:
'如果传入字典而非列表,则字典的 keys 键就会被当成 keys 选项'
pd.concat({'level1': df1, 'level2': df2}, axis=1)
Out[63]:
In [64]:
'names=:对层次化的索引命名'
pd.concat([df1, df2], axis=1, keys=['level1', 'level2'],
names=['upper', 'lower'])
Out[64]:
In [3]:
df1 = DataFrame(np.random.randn(3, 4), columns=['a', 'b', 'c', 'd'])
df2 = DataFrame(np.random.randn(2, 3), columns=['b', 'd', 'a'])
In [66]:
df1
Out[66]:
In [67]:
df2
Out[67]:
In [68]:
'ignore_index=: 不保留连接轴上的索引,产生一组新索引range(total_length)'
pd.concat([df1, df2], ignore_index=True)
Out[68]:
In [7]:
'对比索引值的情况:'
pd.concat([df1, df2])
Out[7]:
表7-2:函数的参数¶
objs 参与连接的pandas对象的列表或字典。唯一必需的参数 axis 指明连接的轴向,默认为0 join 'inner','outer'其中之一,默认为‘outer’。指明其他轴向上的索引是按交集(inner)还是并集(outer)进行合并 join_axes 指明用于其他n-1条轴的索引,不执行并集/交集运算 keys 与连接对象有关的值,用于形成连接轴向上的层次化索引。可以是任意值的列表或数组、元组数组、数组列表(如果将levels设置成多级数组的话) levels 指定用作层次化索引各级别上的索引,如果设置了keys的话 names 用于创建分层级别的名称,如果设置了keys和(或)levels的话 verify_integrity 检查结果对象新轴上的重复情况,如果发现则引发异常。默认(False)允许重复。 ignore_index 不保留连接轴上的索引,产生一组新索引range(total_length)
合并重叠数据¶
In [69]:
a = Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],
index=['f', 'e', 'd', 'c', 'b', 'a'])
b = Series(np.arange(len(a), dtype=np.float64),
index=['f', 'e', 'd', 'c', 'b', 'a'])
b[-1] = np.nan
In [70]:
a
Out[70]:
In [71]:
b
Out[71]:
In [72]:
'Numpy的where函数:用于表达一种矢量化的if-else:'
np.where(pd.isnull(a), b, a)
Out[72]:
In [73]:
'Series中有一个combine_first方法,实现一样的功能,而且会对数据对齐'
b[:-2].combine_first(a[2:])
Out[73]:
In [74]:
'对于DataFrame,combine_first也是一样的,可以这么理解:用参数对象中的数据为调用者对象的缺失数据"打补丁"'
df1 = DataFrame({'a': [1., np.nan, 5., np.nan],
'b': [np.nan, 2., np.nan, 6.],
'c': range(2, 18, 4)})
df2 = DataFrame({'a': [5., 4., np.nan, 3., 7.],
'b': [np.nan, 3., 4., 6., 8.]})
df1.combine_first(df2)
Out[74]:
重塑(reshape)与轴向旋转(pivot)¶
重塑层次化索引¶
stack:将数据的列‘旋转’为行
unstack:将数据的行‘旋转’为列
In [75]:
data = DataFrame(np.arange(6).reshape((2, 3)),
index=pd.Index(['Ohio', 'Colorado'], name='state'),
columns=pd.Index(['one', 'two', 'three'], name='number'))
data
Out[75]:
In [76]:
'stack举例:默认对最内层进行操作'
result = data.stack()
result
Out[76]:
In [77]:
'unstack举例:默认对最内层进行操作'
result.unstack()
Out[77]:
In [78]:
'传入分层级别的编号或者名称即可对其他级别进行unstack(stack)操作:'
result.unstack(0)
Out[78]:
In [79]:
result.unstack('state')
Out[79]:
In [80]:
s1 = Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd'])
s2 = Series([4, 5, 6], index=['c', 'd', 'e'])
data2 = pd.concat([s1, s2], keys=['one', 'two'])
data2
Out[80]:
In [82]:
'unstack 会引入缺失值'
data2.unstack()
Out[82]:
In [83]:
'stack 会过滤缺失数据,因此unstack,unstack运算可逆'
data2.unstack().stack()
Out[83]:
In [84]:
'也可以保留缺失值:传入dropna=False参数'
data2.unstack().stack(dropna=False)
Out[84]:
In [85]:
'在对DataFrame进行unstack操作时,作为旋转轴的级别将会成为结果中的最低级别'
df = DataFrame({'left': result, 'right': result + 5},
columns=pd.Index(['left', 'right'], name='side'))
df
Out[85]:
In [86]:
df.unstack('state')
Out[86]:
In [87]:
df.unstack('state').stack('side')
Out[87]:
将‘长格式’旋转为‘宽格式’¶
时间序列数据通常是以所谓的‘长格式’(long)或者‘堆叠格式’(stacked)存在数据库和csv中的:
In [88]:
data = pd.read_csv('ch07/macrodata.csv')
periods = pd.PeriodIndex(year=data.year, quarter=data.quarter, name='date')
data = DataFrame(data.to_records(),
columns=pd.Index(['realgdp', 'infl', 'unemp'], name='item'),
index=periods.to_timestamp('D', 'end'))
ldata = data.stack().reset_index().rename(columns={0: 'value'})
wdata = ldata.pivot('date', 'item', 'value')
In [89]:
ldata[:10]
Out[89]:
In [90]:
'pivot:前两个参数的参数名作为行列索引的name,参数名对应值作为行列索引的值,第三个参数的值用来填充DataFrame的数值主体'
pivoted = ldata.pivot('date', 'item', 'value')
pivoted.head()
Out[90]:
In [91]:
ldata['value2'] = np.random.randn(len(ldata))
ldata[:10]
Out[91]:
In [92]:
'pivot: 忽略最后一个参数,得到的DataFrame就会带有层次化的列'
pivoted = ldata.pivot('date', 'item')
pivoted[:5]
Out[92]:
In [93]:
pivoted['value'][:5]
Out[93]:
In [94]:
'注意:pivot其实只是一个快捷方式而已,:用set_index创建层次化索引,再用unstack重塑'
unstacked = ldata.set_index(['date', 'item']).unstack('item')
unstacked[:7]
Out[94]:
数据转换¶
移除重复数据¶
In [95]:
data = DataFrame({'k1': ['one'] * 3 + ['two'] * 4,
'k2': [1, 1, 2, 3, 3, 4, 4]})
data
Out[95]:
In [96]:
'duplicated:判断各行是否是重复行,返回布尔型Series'
data.duplicated()
Out[96]:
In [97]:
'drop_duplicates:返回去除重复行后的数据'
data.drop_duplicates()
Out[97]:
In [102]:
'两种方法默认都会判断全部列,也可以指定个别的列:传入含有指定列的列表'
data['v1'] = range(7)
data.drop_duplicates(['k1'])
Out[102]:
In [105]:
'(keep="last"): duplicated和drop_duplicates默认保留的是第一个出现的值的组合,传入keep="last",则保留最后一个'
data.drop_duplicates(['k1', 'k2'], keep='last')
Out[105]:
利用函数或者映射进行数据转换¶
In [108]:
data = DataFrame({'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami',
'corned beef', 'Bacon', 'pastrami', 'honey ham',
'nova lox'],
'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]})
data
Out[108]:
In [109]:
'肉类与动物名字的字典映射'
meat_to_animal = {
'bacon': 'pig',
'pulled pork': 'pig',
'pastrami': 'cow',
'corned beef': 'cow',
'honey ham': 'pig',
'nova lox': 'salmon'
}
In [110]:
'Series的map方法可以接受一个函数或含有映射关系的字典型对象,但是这里有一个转换大写到小写的问题:'
data['animal'] = data['food'].map(str.lower).map(meat_to_animal)
data
Out[110]:
In [111]:
'也可以传入能够完成全部这些工作的函数'
data['food'].map(lambda x: meat_to_animal[x.lower()])
Out[111]:
替换值¶
利用fillna方法填充缺失数据可以看做值替代的一种特殊情况。
map也可以用来修改对象的数据子集
replace则提供了一种实现该功能的更简单、灵活的方法。
In [112]:
data = Series([1., -999., 2., -999., -1000., 3.])
data
Out[112]:
In [113]:
'-999可能是一个缺失值数据的标记值,我们把它替换成pandas能够理解的NA值'
data.replace(-999, np.nan)
Out[113]:
In [114]:
'传入列表:一次替换多个值'
data.replace([-999, -1000], np.nan)
Out[114]:
In [115]:
'对不同的值进行不同的替换'
data.replace([-999, -1000], [np.nan, 0])
Out[115]:
In [116]:
'也可以传入字典参数'
data.replace({-999: np.nan, -1000: 0})
Out[116]:
重命名轴索引¶
In [8]:
data = DataFrame(np.arange(12).reshape((3, 4)),
index=['Ohio', 'Colorado', 'New York'],
columns=['one', 'two', 'three', 'four'])
data
Out[8]:
In [9]:
'和Series一样,轴标签也有一个map方法:'
data.index.map(str.upper)
Out[9]:
In [10]:
'对DataFrame进行修改:将其赋值给index即可:'
data.index = data.index.map(str.upper)
data
Out[10]:
In [11]:
'rename:默认先复制DataFrame,后对索引和列标签赋值'
data.rename(index=str.title, columns=str.upper)
Out[11]:
In [12]:
'传递字典:实现部分轴标签的更新'
data.rename(index={'OHIO': 'INDIANA'},
columns={'three': 'peekaboo'})
Out[12]:
In [13]:
'传入inplace=True,原地修改某个数据集'
# 总是返回DataFrame的引用
_ = data.rename(index={'OHIO': 'INDIANA'}, inplace=True)
data
Out[13]:
In [14]:
_
Out[14]:
离散化和面元划分¶
In [122]:
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
In [130]:
'cut: 将数据拆分为‘面元’'
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
cats
Out[130]:
In [127]:
'codes: 数据在categories中的位置'
cats.codes #原书:cats.labels
Out[127]:
In [128]:
'categories: 分类名称'
cats.categories #原书: cats.levels
Out[128]:
In [129]:
pd.value_counts(cats)
Out[129]:
In [131]:
'right=False: 设置左边为闭端(默认右侧为闭端)'
pd.cut(ages, [18, 26, 36, 61, 100], right=False)
Out[131]:
In [132]:
'自定义面元(分类)名称'
group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']
pd.cut(ages, bins, labels=group_names)
Out[132]:
In [133]:
'等长面元:传入面元数量: 会根据数据的max和min计算等长面元:'
data = np.random.rand(20)
pd.cut(data, 4, precision=2)
Out[133]:
In [134]:
'qcut: 类似于cut,按照样本分位数对数据进行面元划分:(可以得到数量相同的面元分类)'
data = np.random.randn(1000) # 正态分布
cats = pd.qcut(data, 4) # 按4分位数进行切割
cats
Out[134]:
In [135]:
pd.value_counts(cats)
Out[135]:
In [136]:
'qcut: 也可以设置自定义分位数:'
pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.])
Out[136]:
检测和过滤异常值¶
异常值的过滤和运算很大程度上就是数组的运算
In [15]:
np.random.seed(12345)
data = DataFrame(np.random.randn(1000, 4))
data.describe()
Out[15]:
In [16]:
'找出某列中绝对值超过3的值'
col = data[3]
col[np.abs(col) > 3]
Out[16]:
In [23]:
(np.abs(data)>3).head(10)
Out[23]:
In [22]:
'找出全部含有‘超过3或-3的值’的行,你可以利用布尔型DataFrame以及any方法:'
(np.abs(data) > 3).any(1).head(10) # any(axis=1)
Out[22]:
In [140]:
data[(np.abs(data) > 3).any(1)]
Out[140]:
In [26]:
'对特定区域的值赋值'
data[np.abs(data) > 3] = np.sign(data) * 3 # the `sign` function returns ``-1 if x < 0, 0 if x==0, 1 if x > 0``
data.describe() # 注意最大值的变化
Out[26]:
排列和随机采样¶
利用np.random.permutation函数可以轻松实现对Series或DataFrame的列的排序工作(permuting,随机重排序)
In [144]:
df = DataFrame(np.arange(5 * 4).reshape((5, 4)))
sampler = np.random.permutation(5) #permutation 变更,彻底变化 的意思
sampler
Out[144]:
In [145]:
df
Out[145]:
In [146]:
'df.take(indices): 模拟np.take(df,indices),在指定轴上通过数组获取元素,做法类似 reindex'
df.take(sampler)
Out[146]:
In [148]:
df
Out[148]:
In [147]:
'如果不想用重复的方式选取随机子集,可以使用permutation:从permutation返回的数组中切下K个元素,(K为期望的子集的大小)'
df.take(np.random.permutation(len(df))[:3])
Out[147]:
In [149]:
'要通过重复的方式产生样本,最快的方式是通过np.random.randint得到一组随机整数'
'个人理解:应该是这种方式可以产生重复的索引,而上一种则不重复'
bag = np.array([5, 7, -1, 6, 4])
sampler = np.random.randint(0, len(bag), size=10)
In [150]:
sampler
Out[150]:
In [151]:
draws = bag.take(sampler)
draws
Out[151]:
In [152]:
bag
Out[152]:
计算指标/哑变量¶
另一种常用于统计建模或机器学习的转换方式是:将分类标量(categorical variable)转换为
‘哑变量矩阵’(dummy matrix)或‘指标矩阵’(indicator matrix)。
如果某一列中含有K个不同的值,则可以派生出一个K列矩阵或DataFrame(其值全为1或0)。
pandas有一个get_dummies函数可以实现该功能(其实自己动手做一个也不难)。
In [153]:
df = DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],
'data1': range(6)})
pd.get_dummies(df['key'])
Out[153]:
In [157]:
'(prefix=): 有时候,你可能想给指标DataFrame的列加上一个前缀,一遍能够跟其他数据进行合并'
dummies = pd.get_dummies(df['key'], prefix='key')
dummies
Out[157]:
In [154]:
df_with_dummy = df[['data1']].join(dummies)
df_with_dummy
Out[154]:
In [29]:
'如果DataFrame的某行同属于多个分类,则事情就会有点复杂。'
'engine="python",因为c engine 不支持正则表达式(regex)分隔符 sep="::",所以默认会有警告,加上这个参数就好了'
mnames = ['movie_id', 'title', 'genres']
movies = pd.read_table('ch02/movielens/movies.dat', sep='::', header=None,names=mnames,engine='python')
movies[:10]
Out[29]:
In [30]:
'要为每个genre添加指标变量就需要做一些数据规整操作。'
'从数据集中抽取不同的genre值'
genre_iter = (set(x.split('|')) for x in movies.genres)
genres = sorted(set.union(*genre_iter))
In [31]:
'构建指标DataFrame:从全零DataFrame开始'
dummies = DataFrame(np.zeros((len(movies), len(genres))), columns=genres)
In [32]:
'迭代分行赋值为1'
for i, gen in enumerate(movies.genres):
dummies.ix[i, gen.split('|')] = 1
In [36]:
dummies.add_prefix('Genre_').ix[:10,:6]
Out[36]:
In [37]:
'与movies合并:'
movies_windic = movies.join(dummies.add_prefix('Genre_'))
movies_windic.ix[:10,:6]
Out[37]:
In [38]:
movies_windic.ix[0]
#注:对于很大的数据,用这种方式构建多成员值表变量就会变得非常慢。肯定需要编写一个能够利用DataFrame内部机制的更低级的函数才行。
Out[38]:
In [167]:
'一个对统计应用有用的秘诀是:结合get_dummies和诸如cut之类的离散化函数'
np.random.seed(12345)
values = np.random.rand(10)
values
Out[167]:
In [168]:
bins = [0, 0.2, 0.4, 0.6, 0.8, 1]
pd.get_dummies(pd.cut(values, bins))
Out[168]:
字符串操作¶
字符串对象方法(可以略,Python基础中已经学会)¶
In [169]:
val = 'a,b, guido'
val.split(',')
Out[169]:
In [170]:
'split常常与strip结合使用:用于修剪空白符(包括换行符)'
pieces = [x.strip() for x in val.split(',')]
pieces
Out[170]:
In [171]:
first, second, third = pieces
first + '::' + second + '::' + third
Out[171]:
In [172]:
'比上面更快的方法'
'::'.join(pieces)
Out[172]:
In [ ]:
'guido' in val
In [ ]:
val.index(',')
In [ ]:
val.find(':')
In [ ]:
val.index(':')
In [ ]:
val.count(',')
In [ ]:
val.replace(',', '::')
In [ ]:
val.replace(',', '')
正则表达式(还没有开始学习,先跳过)¶
In [ ]:
import re
text = "foo bar\t baz \tqux"
re.split('\s+', text)
In [ ]:
regex = re.compile('\s+')
regex.split(text)
In [ ]:
regex.findall(text)
In [ ]:
text = """Dave dave@google.com
Steve steve@gmail.com
Rob rob@gmail.com
Ryan ryan@yahoo.com
"""
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
# re.IGNORECASE makes the regex case-insensitive
regex = re.compile(pattern, flags=re.IGNORECASE)
In [ ]:
regex.findall(text)
In [ ]:
m = regex.search(text)
m
In [ ]:
text[m.start():m.end()]
In [ ]:
print(regex.match(text))
In [ ]:
print(regex.sub('REDACTED', text))
In [ ]:
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
regex = re.compile(pattern, flags=re.IGNORECASE)
In [ ]:
m = regex.match('wesm@bright.net')
m.groups()
In [ ]:
regex.findall(text)
In [ ]:
print(regex.sub(r'Username: \1, Domain: \2, Suffix: \3', text))
In [ ]:
regex = re.compile(r"""
(?P<username>[A-Z0-9._%+-]+)
@
(?P<domain>[A-Z0-9.-]+)
\.
(?P<suffix>[A-Z]{2,4})""", flags=re.IGNORECASE|re.VERBOSE)
In [ ]:
m = regex.match('wesm@bright.net')
m.groupdict()
pandas中矢量化的字符串函数(先跳过,学完正则表达式之后再来学习)¶
In [ ]:
data = {'Dave': 'dave@google.com', 'Steve': 'steve@gmail.com',
'Rob': 'rob@gmail.com', 'Wes': np.nan}
data = Series(data)
In [ ]:
data
In [ ]:
data.isnull()
In [ ]:
data.str.contains('gmail')
In [ ]:
pattern
In [ ]:
data.str.findall(pattern, flags=re.IGNORECASE)
In [ ]:
matches = data.str.match(pattern, flags=re.IGNORECASE)
matches
In [ ]:
matches.str.get(1)
In [ ]:
matches.str[0]
In [ ]:
data.str[:5]
示例: USDA 食品数据库(先跳过)¶
In [ ]:
import json
db = json.load(open('ch07/foods-2011-10-03.json'))
len(db)
In [ ]:
db[0].keys()
In [ ]:
db[0]['nutrients'][0]
In [ ]:
nutrients = DataFrame(db[0]['nutrients'])
nutrients[:7]
In [ ]:
info_keys = ['description', 'group', 'id', 'manufacturer']
info = DataFrame(db, columns=info_keys)
In [ ]:
info[:5]
In [ ]:
info
In [ ]:
pd.value_counts(info.group)[:10]
In [ ]:
nutrients = []
for rec in db:
fnuts = DataFrame(rec['nutrients'])
fnuts['id'] = rec['id']
nutrients.append(fnuts)
nutrients = pd.concat(nutrients, ignore_index=True)
In [ ]:
nutrients
In [ ]:
nutrients.duplicated().sum()
In [ ]:
nutrients = nutrients.drop_duplicates()
In [ ]:
col_mapping = {'description' : 'food',
'group' : 'fgroup'}
info = info.rename(columns=col_mapping, copy=False)
info
In [ ]:
col_mapping = {'description' : 'nutrient',
'group' : 'nutgroup'}
nutrients = nutrients.rename(columns=col_mapping, copy=False)
nutrients
In [ ]:
ndata = pd.merge(nutrients, info, on='id', how='outer')
In [ ]:
ndata
In [ ]:
ndata.ix[30000]
In [ ]:
result = ndata.groupby(['nutrient', 'fgroup'])['value'].quantile(0.5)
result['Zinc, Zn'].order().plot(kind='barh')
In [ ]:
by_nutrient = ndata.groupby(['nutgroup', 'nutrient'])
get_maximum = lambda x: x.xs(x.value.idxmax())
get_minimum = lambda x: x.xs(x.value.idxmin())
max_foods = by_nutrient.apply(get_maximum)[['value', 'food']]
# make the food a little smaller
max_foods.food = max_foods.food.str[:50]
In [ ]:
max_foods.ix['Amino Acids']['food']

浙公网安备 33010602011771号