这一节介绍常用的pandas数据结构内置方法。很重要的一节。
创建本节要用到的数据结构。
In [1]:
import numpy as np
import pandas as pd
In [2]:
index = pd.date_range('1/1/2000', periods=8)
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=['A', 'B', 'C'])
wp = pd.Panel(np.random.randn(2,5,4), items=['Item1', 'Item2'], major_axis=pd.date_range('1/1/2000',periods=5),
minor_axis=['A', 'B', 'C', 'D'])
想要预览Series或DataFrame对象,可以使用head()和tail()方法。默认显示5行数据,你也可以自己设置显示的行数。
In [3]:
long_series = pd.Series(np.random.randn(1000))
In [4]:
long_series.head()
Out[4]:
In [5]:
long_series.tail(3)
Out[5]:
pandas对象有很多属性,你可以通过这些属性访问数据。
可以通过属性进行安全赋值。
In [6]:
df[:2]
Out[6]:
In [7]:
df.columns = [x.lower() for x in df.columns] #将列名重置为小写
In [8]:
df
Out[8]:
只想得到对象中的数据而忽略index和columns,使用values属性就可以
In [9]:
s.values
Out[9]:
In [10]:
df.values
Out[10]:
In [11]:
type(df.values)
Out[11]:
In [12]:
wp.values
Out[12]:
如果DataFrame或Panel对象的数据类型相同(比如都是 int64),修改object.values相当于直接修改原对象的值。如果数据类型不相同,则根本不能对values属性返回值进行赋值。
注意:
如果对象内数据类型不同,values返回的ndarray的dtype将是能够兼容所有数据类型的类型。比如,有的列数据是int,有的列数据是float,.values返回的ndarray的dtype将是float。
pandas从0.11.0版本开始使用numexpr库对二值数值类型操作加速,用bottleneck库对布尔操作加速。
加速效果对大数据尤其明显。
这里有一个速度的简单对比,使用100,000行* 100列的DataFrame:
所以,在安装pandas后也要顺便安装numexpr, bottleneck。
在所有的pandas对象之间的二元运算中,大家最感兴趣的一般是下面两个:
DataFrame对象内置add(),sub(),mul(),div()以及radd(), rsub(),...等方法。
至于广播计算,Series的输入是最有意思的。
In [67]:
df = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
'three' : pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
In [68]:
df
Out[68]:
In [69]:
row = df.ix[1]
row
Out[69]:
In [70]:
column = df['two']
In [71]:
column
Out[71]:
In [72]:
df.sub(row, axis='columns')
Out[72]:
In [73]:
df.sub(row, axis=1)
Out[73]:
In [74]:
df.sub(row, axis='index')
Out[74]:
In [75]:
df.sub(row, axis=0)
Out[75]:
在Series和DataFrame中,算术运算方法(比如add())有一个fill_value参数,含义很明显,计算前用一个值来代替缺失值,然后再参与运算。注意,如果参与运算的两个object同一位置(同行同列)都是NaN,fill_value不起作用,计算结果还是NaN。
看例子:
In [76]:
df
Out[76]:
In [91]:
df2 = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
'three' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd'])})
In [92]:
df2
Out[92]:
In [93]:
df + df2
Out[93]:
In [95]:
df.add(df2, fill_value=0) #注意['a', 'three']不是NaN
Out[95]:
In [ ]:
pandas引入了二元比较运算方法:eq, ne, lt, gt, le。
In [96]:
df.gt(df2)
Out[96]:
In [97]:
df2.ne(df)
Out[97]:
意思操作返回一个和输入对象同类型的对象,值类型为bool,返回结果可以用于检索。
pandas提供了三个方法(any(), all(), bool())和一个empty属性来对布尔结果进行降维。
In [100]:
df>0
Out[100]:
In [101]:
(df>0).all() #与操作
Out[101]:
In [103]:
(df > 0).any()#或操作
Out[103]:
同样可以对降维后的结果再进行降维。
In [104]:
(df > 0).any().any()
Out[104]:
使用empty属性检测一个pandas对象是否为空。
In [105]:
df.empty
Out[105]:
In [106]:
pd.DataFrame(columns=list('ABC')).empty
Out[106]:
对于只含有一个元素的pandas对象,对其进行布尔检测,使用bool():
In [108]:
pd.Series([True]).bool()
Out[108]:
In [109]:
pd.Series([False]).bool()
Out[109]:
In [111]:
pd.DataFrame([[True]]).bool()
Out[111]:
In [112]:
pd.DataFrame([[False]]).bool()
Out[112]:
一个问题通常有多种解法。一个最简单的例子:df+df和df*2。为了检测两个计算结果是否相等,你可能想到:(df+df == df*2).all(),然而,这样计算得到的结果是False:
In [113]:
df + df == df*2
Out[113]:
In [114]:
(df+df == df*2).all()
Out[114]:
为什么df + df == df*2 返回的结果含有False?因为NaN和NaN比较厚结果为False!
In [116]:
np.nan == np.nan
Out[116]:
还好pandas提供了equals()方法解决上面NaN之间不想等的问题。
In [119]:
(df+df).equals(df*2)
Out[119]:
注意:
在使用equals()方法进行比较时,两个对象如果数据不一致必为False。
In [120]:
df1 = pd.DataFrame({'c':['f',0,np.nan]})
df1
Out[120]:
In [121]:
df2 = pd.DataFrame({'c':[np.nan, 0, 'f']}, index=[2,1,0])
df2
Out[121]:
In [122]:
df1.equals(df2)
Out[122]:
In [123]:
df1.equals(df2.sort_index()) #对df2的索引排序,然后再比较
Out[123]:
你可以直接对pandas对象和一个常量值进行逐元素比较:
In [124]:
pd.Series(['foo', 'bar', 'baz']) == 'foo'
Out[124]:
In [125]:
pd.Index(['foo', 'bar', 'baz']) == 'foo'
Out[125]:
不同类型的对象(比如pandas数据结构、numpy数组)之间进行逐元素的比较也是没有问题的,前提是两个对象的shape要相同。
In [128]:
pd.Series(['foo', 'bar', 'baz']) == pd.Index(['foo', 'bar', 'qux'])
Out[128]:
In [129]:
pd.Series(['foo', 'bar', 'baz']) == np.array(['foo', 'bar', 'qux'])
Out[129]:
In [130]:
pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo', 'bar']) #长度不相同
但要知道不同shape的numpy数组之间是可以直接比较的!因为广播!即使无法广播,也不会Error而是返回False。
In [133]:
np.array([1,2,3]) == np.array([2])
Out[133]:
In [134]:
np.array([1, 2, 3]) == np.array([1, 2])
Out[134]:
看一下例子:
In [135]:
df1 = pd.DataFrame({'A' : [1., np.nan, 3., 5., np.nan],
'B' : [np.nan, 2., 3., np.nan, 6.]})
df1
Out[135]:
In [136]:
df2 = pd.DataFrame({'A' : [5., 2., 4., np.nan, 3., 7.],
'B' : [np.nan, np.nan, 3., 4., 6., 8.]})
df2
Out[136]:
In [137]:
df1.combine_first(df2)
Out[137]:
解释:
对于df1中NaN的元素,用df2中对应位置的元素替换!
DataFrame.combine()方法接收一个DF对象和一个combiner方法。
In [140]:
combiner = lambda x,y: np.where(pd.isnull(x), y,x)
In [141]:
df1.combine(df2, combiner)
Out[141]:
Series, DataFrame和Panel内置了许多计算统计相关指标的方法。这些方法大致分为两类:
总体来说,这些方法接收一个坐标轴参数:
In [142]:
df
Out[142]:
In [146]:
df.mean() #axis=0, 计算每一列的平均值
Out[146]:
In [147]:
df.mean(1) #计算每一行的平均值
Out[147]:
所有的这些方法都有skipna参数,含义是计算过程中是否剔除缺失值,skipna默认值为True。
In [148]:
df.sum(0, skipna=False)
Out[148]:
In [149]:
df.sum(axis=1, skipna=True)
Out[149]:
这些函数可以参与算术和广播运算。
比如:
In [152]:
ts_stand = (df-df.mean())/df.std()
In [153]:
ts_stand.std()
Out[153]:
In [154]:
xs_stand = df.sub(df.mean(1), axis=0).div(df.std(1), axis=0)
In [155]:
xs_stand.std(1)
Out[155]:
注意cumsum() cumprod()方法 保留NA值的位置。
In [156]:
df.cumsum()
Out[156]:
下面列出常用的方法及其描述。提醒每一个方法都有一个level参数用于具有层次索引的对象。
方法 | 描述 |
---|---|
count | 沿着坐标轴统计非空的行数 |
sum | 沿着坐标轴取加和 |
mean | 沿着坐标轴求均值 |
mad | 沿着坐标轴计算平均绝对偏差 |
median | 沿着坐标轴计算中位数 |
min | 沿着坐标轴取最小值 |
max | 沿着坐标轴取最大值 |
mode | 沿着坐标轴取众数 |
abs | 计算每一个值的绝对值 |
prod | 沿着坐标轴求乘积 |
std | 沿着坐标轴计算标准差 |
var | 沿着坐标轴计算无偏方差 |
sem | 沿着坐标轴计算标准差 |
skew | 沿着坐标轴计算样本偏斜 |
kurt | 沿着坐标轴计算样本峰度 |
quantile | 沿着坐标轴计算样本分位数,单位% |
cumsum | 沿着坐标轴计算累加和 |
cumprod | 沿着坐标轴计算累积乘 |
cummax | 沿着坐标轴计算累计最大 |
cummin | 沿着坐标轴计算累计最小 |
Note:所有需要沿着坐标轴计算的方法,默认axis=0,即将方法应用到每一列数据上。
Series还有一个nunique()方法返回非空数值 组成的集合的大小。
In [32]:
series = pd.Series(np.random.randn(500))
series[20:500]=np.nan
In [33]:
series[10:20]=5
In [35]:
series.nunique()
Out[35]:
In [36]:
series
Out[36]:
describe()方法非常有用,它计算数据的各种常用统计指标(比如平均值、标准差等),计算时不包括NA。拿到数据首先要有大概的了解,使用describe()方法就对了。
In [37]:
series = pd.Series(np.random.randn(1000))
series[::2]=np.nan
In [38]:
series.describe()
Out[38]:
In [39]:
frame = pd.DataFrame(np.random.randn(1000, 5), columns=['a', 'b', 'c', 'd', 'e'])
In [40]:
frame.ix[::2]=np.nan
In [41]:
frame.describe()
Out[41]:
默认describe()只包含25%, 50%, 75%, 也可以通过percentiles参数进行指定。
In [42]:
series.describe(percentiles=[.05, .25, .75, .95])
Out[42]:
如果Series内数据是非数值类型,describe()也能给出一定的统计结果
In [43]:
s = pd.Series(['a', 'a', 'b', 'b', 'a', 'a', np.nan, 'c', 'd', 'a'])
In [70]:
s.describe()
Out[70]:
如果DataFrame对象有的列是数值类型,有的列不是数值类型,describe()仅对数值类型的列进行计算。
In [47]:
frame = pd.DataFrame({'a':['Yes', 'Yes', 'NO', 'No'], 'b':range(4)})
In [48]:
frame.describe()
Out[48]:
如果非要知道非数值列的统计指标呢?describe提供了include参数,取值范围{'object', 'number', 'all'}。
看一下例子, 注意'object'和'number'都是在列表中,而'all'不需要放在列表中:
In [57]:
frame.describe(include=['object']) #只对非数值列进行统计计算
Out[57]:
In [58]:
frame.describe(include=['number'])
Out[58]:
In [59]:
frame.describe(include='all')#'all'不是列表
Out[59]:
Series和DataFrame内置的idxmin() idxmax()方法求得 最小值、最大值对应的索引值,看一下例子:
In [60]:
s1 = pd.Series(np.random.randn(5))
s1
Out[60]:
In [62]:
s1.idxmin(), s1.idxmax() #最小值:-0.296405, 最大值:1.735420
Out[62]:
In [63]:
df1 = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df1
Out[63]:
In [66]:
df1.idxmin(axis=0)
Out[66]:
In [67]:
df1.idxmax(axis=1)
Out[67]:
如果多个数值都是最大值或最小值,idxmax() idxmin()返回最大值、最小值第一次出现对应的索引值
In [68]:
df3 = pd.DataFrame([2, 1, 1, 3, np.nan], columns=['A'], index=list('edcba'))
df3
Out[68]:
In [69]:
df3['A'].idxmin()
Out[69]:
实际上,idxmin和idxmax就是NumPy中的argmin和argmax。
value_counts()计算一维度数据结构的直方图。
In [71]:
data = np.random.randint(0, 7, size=50)
data
Out[71]:
In [72]:
s = pd.Series(data)
In [73]:
s.value_counts()
Out[73]:
In [75]:
pd.value_counts(data) #也是全局方法
Out[75]:
虽然前面介绍过mode()方法了,看两个例子吧:
In [76]:
s5 = pd.Series([1,1,3,3,3,5,5,7,7,7])
In [77]:
s5.mode()
Out[77]:
In [83]:
df5 = pd.DataFrame({"A": np.random.randint(0, 7, size=50),
"B": np.random.randint(-10, 15, size=50)})
In [106]:
df5
Out[106]:
In [107]:
df5.mode()
Out[107]:
cut() qcut()方法可以对连续数据进行离散化
In [108]:
arr = np.random.randn(20)
In [109]:
factor = pd.cut(arr, 4)
In [110]:
factor
Out[110]:
In [111]:
factor = pd.cut(arr, [-5, -1, 0, 1, 5]) #输入 离散区间
In [112]:
factor
Out[112]:
qcut()方法计算样本的分位数,比如我们可以将正态分布的数据 进行四分位数离散化:
In [113]:
arr = np.random.randn(30)
In [114]:
factor = pd.qcut(arr, [0, .25, .5, .75, 1])
In [115]:
factor
Out[115]:
In [116]:
pd.value_counts(factor)
Out[116]:
离散区间也可以用极限定义
In [117]:
arr = np.random.randn(20)
In [118]:
factor = pd.cut(arr, [-np.inf, 0, np.inf])
In [119]:
factor
Out[119]:
In [ ]:
如果你想用自己写的方法或其他库方法操作pandas对象,你应该知道下面的三种方式。 具体选择哪种方式取决于你是想操作整个DataFrame对象还是DataFrame对象的某几行或某几列,或者逐元素操作。
DataFrame和Series当然能够作为参数传入方法。然而,如果涉及到多个方法的序列调用,推荐使用pipe()。看一下例子:
In [ ]:
#f, g 和h是三个方法,接收DataFrame对象,返回DataFrame对象
f(g(h(df), arg1=1), arg2=2, arg3=3)
上面一行代码推荐用下面的等价写法:
In [ ]:
(df.pipe(h).pipe(g, arg1=1).pipe(f, arg2=2, arg3=3))
注意 f g h三个方法中DataFrame都是作为第一个参数。如果DataFrame作为第二个参数呢?方法是为pipe提供(callable, data_keyword),pipe会自动调用DataFrame对象。
比如,使用statsmodels处理回归问题,他们的API期望第一个参数是公式,第二个参数是DataFrame对象data。我们使用pipe传递(sm.poisson, 'data'):
pipe灵感来自于Unix中伟大的艺术:管道。pandas中pipe()的实现很简洁,推荐阅读源代码pd.DataFrame.pipe
任意函数都可以直接对DataFrame或Panel某一坐标轴进行直接操纵,只需要使用apply()方法即可,同描述性统计方法一样,apply()方法接收axis参数。
In [5]:
df.apply(np.mean)
Out[5]:
In [7]:
df.apply(np.mean, axis=1)
Out[7]:
In [11]:
df.apply(lambda x: x.max() - x.min())
Out[11]:
In [12]:
df.apply(np.cumsum)
Out[12]:
In [13]:
df.apply(np.exp)
Out[13]:
灵活运用apply()方法可以统计出数据集的很多特性。比如,假设我们希望从数据中抽取每一列最大值的索引值。
In [21]:
tsdf = pd.DataFrame(np.random.randn(1000, 3), columns=['A', 'B', 'C'],
index=pd.date_range('1/1/2000', periods=1000))
tsdf
Out[21]:
In [22]:
tsdf.apply(lambda x:x.idxmax())
Out[22]:
apply()方法当然支持接收其他参数了,比如下面的例子:
In [23]:
def subtract_and_divide(x, sub, divide=1):
return (x - sub)/divide
In [24]:
df.apply(subtract_and_divide, args=(5,),divide=3)
Out[24]:
另一个有用的特性是对DataFrame对象传递Series方法,然后针对DF对象的每一列或每一行执行 Series内置的方法!
In [26]:
df
Out[26]:
In [27]:
df.apply(pd.Series.interpolate)
Out[27]:
既然不是所有的方法都能被向量化(接收NumPy数组,返回另一个数组或者值),但是DataFrame内置的applymap()和Series的map()方法能够接收任意的接收一个值且返回一个值的Python方法。
In [29]:
df4 = pd.DataFrame(np.random.randn(4, 3),index=['a','b','c','d'],columns=['one', 'two', 'three'])
df4
Out[29]:
In [30]:
f = lambda x:len(str(x))
In [31]:
df4['one'].map(f)
Out[31]:
In [32]:
df4.applymap(f)
Out[32]:
Series.map()还有一个功能是模仿merge(), join()
In [38]:
s = pd.Series(['six', 'seven', 'six', 'seven', 'six'], index=['a', 'b', 'c', 'd', 'e'])
In [39]:
t = pd.Series({'six':6., 'seven':7.})
In [40]:
s
Out[40]:
In [41]:
t
Out[41]:
In [42]:
s.map(t)
Out[42]:
In [ ]:
reindex()是pandas中基本的数据对其方法。其他所有依赖label对齐的方法基本都要靠reindex()实现。reindex(重新索引)意味着是沿着某条轴转换数据以匹配新设定的label。具体来说,reindex()做了三件事情:
下面是一个简单的例子:
In [43]:
s = pd.Series(np.random.randn(5), index=['a','b','c','d','e'])
In [44]:
s
Out[44]:
In [45]:
s.reindex(['e', 'b', 'f', 'd'])
Out[45]:
对于DataFrame来说,你可以同时改变列名和索引值。
In [48]:
df
Out[48]:
In [49]:
df.reindex(index=['c', 'f', 'b'], columns=['three', 'two', 'one'])
Out[49]:
如果只想改变列或者索引的label,DataFrame也提供了reindex_axis()方法,接收label和axis。
In [50]:
rs = s.reindex(df.index)
In [51]:
rs
Out[51]:
In [52]:
rs.index is df.index
Out[52]:
上面一行代码顺便说明了Series的索引和DataFrame的索引是同一类的实例。
你可能想传递一个对象,使得原来对象的label和传入的对象一样,使用reindex_like()即可。
In [3]:
df2 = pd.DataFrame(np.random.randn(3, 2),index=['a','b','c'],columns=['one', 'two'])
In [4]:
df2
Out[4]:
In [56]:
df
Out[56]:
In [57]:
df.reindex_like(df2)
Out[57]:
align()方法是让两个对象同事对齐的最快方法。它含有join参数,
align()方法返回一个元组,元素元素是重新索引的Series对象。
In [5]:
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [9]:
s1 = s[:4]
s2 = s[1:]
In [10]:
s1
Out[10]:
In [11]:
s2
Out[11]:
In [12]:
s1.align(s2)
Out[12]:
In [14]:
s1.align(s2, join='inner') #交集是 'b', 'c', 'd'
Out[14]:
对于DataFrame来说,join方法默认会应用到索引和列名。
In [16]:
df
Out[16]:
In [23]:
df2 = df.iloc[:5,:2]
In [24]:
df2
Out[24]:
In [25]:
df.align(df2, join='inner')
Out[25]:
In [26]:
df.align(df2)
Out[26]:
align()也含有一个axis参数,指定仅对于某一坐标轴进行对齐。
In [27]:
df.align(df2, join='inner', axis=0)
Out[27]:
DataFrame.align()同样能接收Series对象,此时axis指的是DataFrame对象的索引或列。
In [28]:
df.align(df2.ix[0], axis=1)
Out[28]:
reindex()方法还有一个method参数,用于填充数值,method取值如下:
以Series为例,看一下:
In [30]:
rng = pd.date_range('1/3/2000', periods=8)
In [31]:
ts = pd.Series(np.random.randn(8), index=rng)
In [32]:
ts2 = ts[[0, 3, 6]]
In [33]:
ts
Out[33]:
In [34]:
ts2
Out[34]:
In [35]:
ts2.reindex(ts.index)
Out[35]:
In [36]:
ts2.reindex(ts.index, method='ffill') #索引小那一行的数值填充NaN
Out[36]:
In [38]:
ts2.reindex(ts.index, method='bfill') #索引大的非NaN的数值填充NaN
Out[38]:
In [39]:
ts2.reindex(ts.index, method='nearest')
Out[39]:
method参数要求索引必须是有序的:递增或递减。
除了method='nearest',其他method取值也能用fillna()方法实现:
In [40]:
ts2.reindex(ts.index).fillna(method='ffill')
Out[40]:
二者的区别是:如果索引不是有序的,reindex()会报错,而fillna()和interpolate()不会检查索引是否有序。
limit和tolerance参数会对填充操作进行条件限制,通常限制填充的次数。
In [41]:
ts2.reindex(ts.index, method='ffill', limit=1)
Out[41]:
In [42]:
ts2
Out[42]:
In [43]:
ts
Out[43]:
In [44]:
ts2.reindex(ts.index, method='ffill', tolerance='1 day')
Out[44]:
和reindex()方法很相似的是drop(),用于移除索引的某些取值。
In [52]:
df
Out[52]:
In [53]:
df.drop(['A'], axis=1)
Out[53]:
rename() 方法可以对索引值重新命名,命名方式可以是字典或Series,也可以是任意的方法。
In [56]:
s
Out[56]:
In [57]:
s.rename(str.upper)
Out[57]:
唯一的要求是传入的函数调用索引值时必须有一个返回值,如果你传入的是字典或Series,要求是索引值必须是其键值。这点很好理解。
In [59]:
df = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
'three' : pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
df
Out[59]:
In [60]:
df.rename(columns={'one' : 'foo', 'two' : 'bar'},
index={'a' : 'apple', 'b' : 'banana', 'd' : 'durian'})
Out[60]:
默认情况下修改的仅仅是副本,如果想对原对象索引值修改,inplace=True.
在0.18.0版本中,rename方法也能修改Series.name
In [61]:
s.rename('sclar-name')
Out[61]:
In [ ]:
pandas中迭代操作依赖于具体的对象。迭代Series对象时类似迭代数组,产生的是值,迭代DataFrame或Panel对象时类似迭代字典的键值。
一句话,(for i in object)产生:
看一下例子吧:
In [62]:
df = pd.DataFrame({'col1' : np.random.randn(3), 'col2' : np.random.randn(3)},
index=['a', 'b', 'c'])
df
Out[62]:
In [64]:
for col in df: #产生的是列名
print col
pandas对象也有类似字典的iteritems()方法来迭代(key, value)。
为了每一行迭代DataFrame对象,有两种方法:
警告:
迭代pandas对象通常会比较慢。所以尽量避免迭代操作,可以用以下方法替换迭代:
警告:
当迭代进行时永远不要有修改操作。
类似字典的接口,iteritems()对键值对进行迭代操作:
看一下例子:
In [65]:
for item, frame in df.iteritems():
print item, frame
iterrows()方法用于迭代DataFrame的每一行,返回的是索引和Series的迭代器,但要注意Series的dtype可能和原来每一行的dtype不同。
In [68]:
for row_index, row in df.iterrows():
print row_index, row
itertuples()方法迭代DataFrame每一行,返回的是namedtuple。因为返回的不是Series,所以会保留DataFrame中值的dtype。
In [70]:
for row in df.itertuples():
print row
Series对象如果索引是datetime/period,可以用自带的.dt访问器返回日期、小时、分钟。
In [71]:
s = pd.Series(pd.date_range('20160101 09:10:12', periods=4))
In [72]:
s
Out[72]:
In [73]:
s.dt.hour
Out[73]:
In [74]:
s.dt.second
Out[74]:
In [75]:
s.dt.day
Out[75]:
改变时间的格式也很方便,Series.dt.strftime()
In [76]:
s = pd.Series(pd.date_range('20130101', periods=4))
In [77]:
s
Out[77]:
In [78]:
s.dt.strftime('%Y/%m/%d')
Out[78]:
In [ ]:
Series带有一系列的字符串处理, 默认不对NaN处理。
In [79]:
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
In [80]:
s
Out[80]:
In [81]:
s.str.lower()
Out[81]:
In [ ]:
排序方法可以分为两大类: 按照实际的值排序和按照label排序。
Series.sort_index(), DataFrame.sort_index(), 参数是ascending, axis。
In [88]:
unsorted_df = df.reindex(index=['a', 'd', 'c', 'b'],
columns=['three', 'two', 'one'])
unsorted_df
Out[88]:
In [89]:
unsorted_df.sort_index()
Out[89]:
In [90]:
unsorted_df.sort_index(ascending=False)
Out[90]:
In [91]:
unsorted_df.sort_index(axis=1)
Out[91]:
In [92]:
unsorted_df['three'].sort_index() # Series
Out[92]:
Series.sort_values(), DataFrame.sort_values()用于按照值进行排序,参数有by
In [93]:
df1 = pd.DataFrame({'one':[2,1,1,1],'two':[1,3,2,4],'three':[5,4,3,2]})
df1
Out[93]:
In [94]:
df1.sort_values(by='two')
Out[94]:
In [95]:
df1.sort_values(by=['one', 'two'])
Out[95]:
通过na_position参数处理NA值。
In [96]:
s[2] = np.nan
In [97]:
s.sort_values()
Out[97]:
In [99]:
s.sort_values(na_position='first') #将NA放在前面
Out[99]:
Series.searchsorted()类似numpy.ndarray.searchsorted()。 找到元素在排好序后的位置(下标)。
In [3]:
ser = pd.Series([1,2,3])
In [10]:
ser.searchsorted([0, 3]) #元素0下标是0, 元素3下标是2。注意不同元素之间是独立的,所以元素3的位置是2而不是插入0后的3.
Out[10]:
In [11]:
ser.searchsorted([0, 4])
Out[11]:
In [6]:
ser.searchsorted([1, 3], side='right')
Out[6]:
In [7]:
ser.searchsorted([1, 3], side='left')
Out[7]:
In [8]:
ser = pd.Series([3, 1, 2])
In [9]:
ser.searchsorted([0, 3], sorter=np.argsort(ser))
Out[9]:
Series有nsmallest() nlargest()方法能够返回最小或最大的n个值。如果Series对象很大,这两种方法会比先排序后使用head()方法快很多。
In [12]:
s = pd.Series(np.random.permutation(10))
s
Out[12]:
In [13]:
s.sort_values()
Out[13]:
In [14]:
s.nsmallest(3)
Out[14]:
In [15]:
s.nlargest(3)
Out[15]:
从v0.17.0开始,DataFrame也有了以上两个方法。
In [16]:
df = pd.DataFrame({'a': [-2, -1, 1, 10, 8, 11, -1],
'b': list('abdceff'),
'c': [1.0, 2.0, 4.0, 3.2, np.nan, 3.0, 4.0]})
In [25]:
df
Out[25]:
In [28]:
df.nlargest(5, 'a') #列 'a'最大的3个值
Out[28]:
In [27]:
df.nlargest(5, ['a', 'c'])
Out[27]:
In [22]:
df.nsmallest(3, 'a')
Out[22]:
In [24]:
df.nsmallest(5, ['a', 'c'])
Out[24]:
如果一列是多索引,你必须指定全部每一级的索引。
In [30]:
df1 = pd.DataFrame({'one':[2,1,1,1],'two':[1,3,2,4],'three':[5,4,3,2]})
In [31]:
df1.columns = pd.MultiIndex.from_tuples([('a','one'),('a','two'),('b','three')])
In [32]:
df1
Out[32]:
In [33]:
df1.sort_values(by=('a','two'))
Out[33]:
In [ ]:
copy()方法复制数据结构的值并返回一个新的对象。记住复制操作不到万不得已不使用。 比如,改变DataFrame对象值的几种方法:
几乎所有的方法都不对原对象进行直接修改,而是返回修改后的一个新对象!如果原对象数据被修改,肯定是你显示指定的修改操作。
pandas对象的主要数据类型包括: float, int, bool, datetime64[ns], datetime64[ns, tz], timedelta[ns], category, object. 除此之外还有更具体的说明存储比特数的数据类型比如int64, int32。
DataFrame的dtypes属性返回一个Series对象,Series值是DF中每一列的数据类型。
In [39]:
df = pd.DataFrame(dict(A = np.random.rand(3),
B = 1,
C = 'foo',
D = pd.Timestamp('20010102'),
E = pd.Series([1.0]*3).astype('float32'),
F = False,
G = pd.Series([1]*3,dtype='int8')))
In [40]:
df
Out[40]:
In [41]:
df.dtypes
Out[41]:
Series同样有dtypes属性
In [42]:
df['A'].dtype
Out[42]:
如果pandas对象的一列中有多种数据类型,dtype返回的是能兼容所有数据类型的类型,object范围最大的。
In [43]:
pd.Series([1,2,3,4,5,6.])
Out[43]:
In [44]:
pd.Series([1,2,3,6.,'foo'])
Out[44]:
get_dtype_counts()方法返回DataFrame中每一种数据类型的列数。
In [50]:
df.get_dtype_counts()
Out[50]:
数值数据类型可以在ndarray,Series和DataFrame中传播。
In [51]:
df1 = pd.DataFrame(np.random.randn(8, 1), columns=['A'], dtype='float32')
In [52]:
df1
Out[52]:
In [53]:
df1.dtypes
Out[53]:
In [56]:
df2 = pd.DataFrame(dict( A = pd.Series(np.random.randn(8), dtype='float16'),
B = pd.Series(np.random.randn(8)),
C = pd.Series(np.array(np.random.randn(8), dtype='uint8')) )) #这里是float16, uint8
df2
Out[56]:
In [57]:
df2.dtypes
Out[57]:
整型的默认值蕾西int64,浮点型的默认类型是float64,和你用的是32位还是64位的系统无关。
In [59]:
pd.DataFrame([1, 2], columns=['a']).dtypes
Out[59]:
In [60]:
pd.DataFrame({'a': [1, 2]}).dtypes
Out[60]:
In [61]:
pd.DataFrame({'a': 1}, index=list(range(2))).dtypes
Out[61]:
Numpy中数值的具体类型则要依赖于平台。
In [64]:
frame = pd.DataFrame(np.array([1, 2])) #如果是在32位系统,数据类型int32
不同类型结合时会upcast,即得到更通用的类型,看例子吧:
In [75]:
df1.dtypes
Out[75]:
In [76]:
df2.dtypes
Out[76]:
In [77]:
df1.reindex_like(df2).fillna(value=0.0).dtypes
Out[77]:
In [78]:
df3 = df1.reindex_like(df2).fillna(value=0.0) + df2
In [79]:
df3.dtypes
Out[79]:
使用astype()显示的进行转型。默认会返回原对象的副本,即使数据类型不变。当然可以传递copy=False参数直接对原对象转型。
In [80]:
df3
Out[80]:
In [81]:
df3.dtypes
Out[81]:
In [82]:
df3.astype('float32').dtypes
Out[82]:
convert_objects()方法能对object类型进行转型。如果想转为数字,参数是convert_numeric=True。
In [84]:
df3['D'] = '1.'
In [85]:
df3['E'] = '1'
In [86]:
df3
Out[86]:
In [88]:
df3.dtypes #现在'D' 'E'两列都是object类型
Out[88]:
In [89]:
df3.convert_objects(convert_numeric=True).dtypes
Out[89]:
In [90]:
df3['D'] = df3['D'].astype('float16')
In [91]:
df3['E'] = df3['E'].astype('int32')
In [92]:
df3.dtypes
Out[92]:
select_dtypes()方法实现了基于列dtype的构造子集方法。
In [93]:
df = pd.DataFrame({'string': list('abc'),
'int64': list(range(1, 4)),
'uint8': np.arange(3, 6).astype('u1'),
'float64': np.arange(4.0, 7.0),
'bool1': [True, False, True],
'bool2': [False, True, False],
'dates': pd.date_range('now', periods=3).values,
'category': pd.Series(list("ABC")).astype('category')})
In [94]:
df
Out[94]:
In [95]:
df['tdeltas'] = df.dates.diff()
In [96]:
df['uint64'] = np.arange(3, 6).astype('u8')
In [97]:
df['other_dates'] = pd.date_range('20130101', periods=3).values
In [98]:
df['tz_aware_dates'] = pd.date_range('20130101', periods=3, tz='US/Eastern')
In [99]:
df
Out[99]:
In [100]:
df.dtypes
Out[100]:
select_dtypes()有两个参数:include, exclude。含义是要选择的列的dtype和不选择列的dtype。
In [104]:
df.select_dtypes(include=[bool])
Out[104]:
In [105]:
df.select_dtypes(include=['bool'])
Out[105]:
In [107]:
df.dtypes
Out[107]:
In [108]:
df.select_dtypes(include=['number', 'bool'], exclude=['unsignedinteger'])
Out[108]:
如果要选择字符串类型的列,必须使用object类型。
In [109]:
df.select_dtypes(include=['object'])
Out[109]:
如果想要知道某种数据类型的所有子类型,比如numpy.number类型,你可以定义如下的方法:
In [110]:
def subdtypes(dtype):
subs = dtype.__subclasses__()
if not subs:
return dtype
return [dtype, [subdtypes(dt) for dt in subs]]
In [111]:
subdtypes(np.generic)
Out[111]:
In [ ]: