数据分析之Pandas——数据结构
来源:互联网 发布:数据库审计产品排名 编辑:程序博客网 时间:2024/06/07 05:23
数据结构介绍
Pandas的数据对象中都包含最基本的属性,如数据类型,索引,标签等。
要使用Pandas的数据结构首先需要引入pandas和numpy:
In [1]: import numpy as npIn [2]: import pandas as pd
有一个基本原则要牢记:数据对齐是默认的。数据和标签的关联不会被破坏,除非认为更改。
本章将做一个关于数据结构的简介,然后在其他章节中做更全面的介绍。
Series
Series 是一维标签数组,能够保存任何数据类型(整型,浮点型,字符串或其他Python对象类型)。轴标签被称为索引。创建一个最基本的Series结构,代码如下:
s = pd.Series(data, index=index)
data可以是很多类型:
- 一个 Python 字典
- 一个 ndarray 对象
- 一个标量值(如5)
index是轴标签的列表。因此,这将根据data的不同分为几种情况:
由ndarray构造
如果传递的data是一个ndarray对象,index的长度必须和data的长度保持一致。如果没有对index参数赋值,那么索引值会默认为[0, … , len(data) -1],即由0开始,与data数据等长的递增列表。
In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
这里构造了一个名为s的Serise对象,其data为5个随机数,那么对应的index长度也为5, 分别为a至e的小写字母。
那么s打印出来的结果如下:
In [4]: sOut[4]: a -1.317092b 0.898475c -0.026741d -0.090660e -0.783084dtype: float64
通过输入s.index可以查看索引
In [6]: s.indexOut[6]: Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')
如果不为index参数赋值,那么构造的Series对象结果为
In [7]: s = pd.Series(np.random.randn(5))In [8]: sOut[8]: 0 -2.7509071 2.4026232 -2.4792443 1.8265354 -1.270192dtype: float64
注意:从v0.8.0开始,pandas可以支持索引值不唯一。
如:
In [6]: s = pd.Series(np.random.randn(5), index=[‘a’, ‘b’, ‘b’, ‘c’, ‘d’])
In [7]: s
Out[7]:
a 0.285951
b -0.153731
b 0.536586
c 2.156944
d -0.113776
dtype: float64
由dict 字典类型构造
如果传递的data是一个dict字典类型对象,并且传递了index参数,那么对应的值将从字典中取出。
In [8]: d = {'a':0, 'b':1, 'c':2}In [11]: pd.Series(d, index=['b','c','d', 'a'])Out[11]: b 1c 2d NaNa 0dtype: float64
注意:NaN(not a number)是Pandas中使用的数据缺失的标记,由于data中没有包含key为’d’的数据,所以返回数据缺失,标记为NaN。
否则,index的值将由字典对象里的key值进行构造。
In [8]: d = {'a':0, 'b':1, 'c':2}In [9]: pd.Series(d)Out[9]: a 0b 1c 2dtype: int64
由标量值构造
如果传递的data是一个标量值,那么Index参数必须提供。其构造的二维数组对象将根据索引的长度进行重复。
In [12]: pd.Series(5, index=['b', 'c', 'd', 'a'])Out[12]: b 5c 5d 5a 5dtype: int64
Series类似于ndarray
Serise扮演的角色非常类似ndarray,并且它可以作为大多数Numpy函数的参数。也可以通过对索引切割来进行数据切片。
In [14]: s[0]Out[14]: 0.28595142701029524In [15]: s[:3]Out[15]: a 0.285951b -0.153731b 0.536586dtype: float64In [16]: s[s > s.median()]Out[16]: b 0.536586c 2.156944dtype: float64In [17]: s[[4, 3, 1]]Out[17]: d -0.113776c 2.156944b -0.153731dtype: float64In [18]: np.exp(s)Out[18]: a 1.331028b 0.857502b 1.710159c 8.644678d 0.892458dtype: float64
Series类似于dict
Series类似于定长的字典对象,你可以通过index标签获取或设置值。
In [19]: s['a']Out[19]: 0.28595142701029524In [20]: s['c'] = 12In [21]: sOut[21]: a 0.285951b -0.153731b 0.536586c 12.000000d -0.113776In [22]: 'b' in sOut[22]: TrueIn [23]: 'e' in sOut[23]: False
如果输入的标签不存在,那么将报异常:
In [24]: s['e']KeyError: 'e'
如果使用get方法,不存在的标签将会返回空值或指定默认值:
In [25]: s.get('e')In [26]: s.get('e', np.nan)Out[26]: nan
向量操作和标签对齐
当做数据分析时, 和Numpy的数组一样,一个一个的循环遍历Series中的值通常是不必要的。Series对象也可以像ndarray一样,传递到大多数Numpy方法中。
In [27]: s + sOut[27]: a 0.571903b -0.307463b 1.073173c 24.000000d -0.227552dtype: float64In [28]: s * 2Out[28]: a 0.571903b -0.307463b 1.073173c 24.000000d -0.227552dtype: float64In [29]: np.exp(s)Out[29]: a 1.331028b 0.857502b 1.710159c 162754.791419d 0.892458dtype: float64
Series和ndarray关键的区别在于,Series间的操作会自动根据标签对齐数据。因此,你可以直接编写计算,而不用考虑所涉及到的Series是否具有相同的标签。
In [30]: s[1:] + s[:-1]Out[30]: a NaNb -0.307463b 0.382855b 0.382855b 1.073173c 24.000000d NaNdtype: float64
在未对齐的Series间操作,结果将包含索引的集合。如果标签在一个或另一个Series中未找到,结果将标记为缺失NaN。所以可以在不进行任何显示数据对齐的情况下编写代码,在交互数据分析和研究中提供了巨大的自由度和灵活性。Pandas数据结构的综合数据排列特征使Pandas有别于大多数用于标记数据的相关工具。
Name 属性
Series也有Name属性
In [31]: s = pd.Series(np.random.randn(5), name='something')In [32]: sOut[32]: 0 1.5227741 0.7335612 -0.7024623 0.0222054 1.704067Name: something, dtype: float64
许多情况下,Series的Name将被自动分配,特别是下面即将看到的对于DataFrame的一维切片时。
可以通过方法pandas.Series.rename()对Series进行重命名。
In [33]: s2 = s.rename("different")In [34]: s2.nameOut[35]: 'different'
注意s和s2分别引用的是两个不同的对象。
DataFrame
DataFrame是一个2维标签的数据结构,它的列可以存在不同的类型。你可以把它简单的想成Excel表格或SQL Table,或者是包含字典类型的Series。它是最常用的Pandas对象。和Series一样,DataFrame接受许多不同的类型输入:
- 包含1维ndarray,列表对象,字典对象或者Series对象的字典对象
- 2维的ndarray对象
- 结构化或记录型的ndarray
- Series对象
- 另一个DataFrame对象
可以通过传递索引(行标签)和列(列标签)参数来操作数据。如果传递了索引和/或列,可以得到包含索引和/或列的DataFrame结果集。因此,一个字典类型的Series加上一个特定的索引,将会丢弃所有与传递的所以不匹配的数据。
如果没有传递轴标签,他们将基于常用规则的输入数据进行创建。
由包含Series的字典或嵌套字典构造
结果的索引将是各个Series索引的并集。如果有任何嵌套的字典对象,都将先转换成Series。如果没有传递任何列,那么列将是已排序的字典对象的Key值。
In [20]: d = {'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']), ...: 'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}In [21]: df = pd.DataFrame(d)In [22]: dfOut[22]: one twoa 1 1b 2 2c 3 3d NaN 4In [23]: pd.DataFrame(d, index=['d', 'b', 'a'])Out[23]: one twod NaN 4b 2 2a 1 1In [24]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])Out[24]: two threed 4 NaNb 2 NaNa 1 NaN
通过访问索引和列属性,可以分别访问行和列标签:
In [25]: df.indexOut[25]: Index([u'a', u'b', u'c', u'd'], dtype='object')df.columnsOut[26]: Index([u'one', u'two'], dtype='object')
由包含ndarray或列表的字典构造
ndarray的长度必须一致。如果一个索引被传递,它必须与数组的长度相同。如果没有索引被传递,结果将是range(n),n是数组的长度。
In [27]: d = {'one':[1., 2., 3., 4.], ...: 'two': [4., 3., 2., 1.]}In [28]: pd.DataFrame(d)Out[28]: one two0 1 41 2 32 3 23 4 1In [29]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])Out[29]: one twoa 1 4b 2 3c 3 2d 4 1
由数组构造
这个例子的处理与数组字典的完全相同
In [39]: data = np.zeros((2,), dtype=[('A', 'i4'), ('B', 'f4'), ('C', 'a10')])In [40]: data[:] = [(1, 2., 'Hello'), (2, 3., 'World')]In [41]: pd.DataFrame(data)Out[41]: A B C0 1 2 Hello1 2 3 WorldIn [42]: pd.DataFrame(data, index=['first', 'second'])Out[42]: A B Cfirst 1 2 Hellosecond 2 3 WorldIn [43]: pd.DataFrame(data, columns=['C', 'A', 'B'])Out[43]: C A B0 Hello 1 21 World 2 3
注意:DataFrame的工作方式与2维的ndarray并不一样
由包含字典的列表构造
In [44]: data = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]In [45]: pd.DataFrame(data)Out[45]: a b c0 1 2 NaN1 5 10 20In [47]: pd.DataFrame(data, index=['first', 'second'])Out[47]: a b cfirst 1 2 NaNsecond 5 10 20In [48]: pd.DataFrame(data, columns=['a', 'b'])Out[48]: a b0 1 21 5 10
由包含元组的字典构造
In [49]: pd.DataFrame({('a', 'b'): {('A', 'B'): 1, ('A', 'C'): 2}, ...: ('a', 'a'): {('A', 'C'): 3, ('A', 'B'): 4}, ...: ('a', 'c'): {('A', 'B'): 5, ('A', 'C'): 6}, ...: ('b', 'a'): {('A', 'C'): 7, ('A', 'B'): 8}, ...: ('b', 'b'): {('A', 'D'): 9, ('A', 'B'): 10}})Out[49]: a b a b c a bA B 4 1 5 8 10 C 3 2 6 7 NaN D NaN NaN NaN NaN 9
由Series构造
结果将是索引与输入的Series相同,并且有一列数据,列名与Series的名称一致(仅在没有提供其他列名的情况下)。
In [58]: s = pd.Series([1, 2, 3], index=['a', 'b', 'c'], name='first')In [59]: sOut[59]: a 1b 2c 3Name: first, dtype: int64In [60]: pd.DataFrame(s)Out[60]: firsta 1b 2c 3
缺失数据
跟多的缺失数据相关内容将在其他章节介绍。为了构造一个包含缺失数据的DataFrame,对于那些缺失的值需要用到np.nan。或者,将numpy.MaskedArray作为data参数传递给DataFrame的构造函数,它所遮盖的条目将被认为是缺失的。
其他构造方式
DataFrame.from_dict
DataFrame.from_dict将获取一个嵌套字典或者数组字典,并返回一个DataFrame。它的操作方式类似于DataFrame的构造函数,除了orient参数默认为column,但是可以将它设置为index,让字典的key值作为行标签。
DataFrame.from_records
DataFrame.from_records将获取一个元组构成的列表或者一个结构化的ndarray对象。与普通的DataFrame构造函数类似,除了索引可能是结构化的dtype的特定字段。例如:
In [61]: dataOut[61]: [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]In [62]: data = np.zeros((2,), dtype=[('A', 'i4'),('B', 'f4'),('C', 'a10')])In [63]: data[:] = [(1, 2, 'Hello'), (2, 3, 'World')]In [64]: dataOut[64]: array([(1, 2.0, 'Hello'), (2, 3.0, 'World')], dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])In [66]: pd.DataFrame.from_records(data, index='C')Out[66]: A BC Hello 1 2World 2 3
DataFrame.from_items
DataFrame.from_items 运行机制类似于dict的构造函数,传递一个键值对序列作为参数。Key是列名(或索引名,orient=’index’),Value是列的值(或行的值)。这对于构造具有特定顺序的列的DataFrame是很有用的,而不用传递列的明确列表:
In [68]: pd.DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])])Out[68]: A B0 1 41 2 52 3 6
如果传递orient=’index’,key值将作为索引标签。但是在下面的例子中任需要列名:
In [73]: pd.DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])], orient='index', columns=['one', 'two', 'three'])Out[73]: one two threeA 1 2 3B 4 5 6
列的选择、添加和删除
类似于对字典操作的语法,你可以对一个DataFrame进行获取列的值,对列赋值或删除列。
In [74]: df['one']Out[74]: a 1b 2c 3d NaNName: one, dtype: float64In [75]: df['three'] = df['one'] * df['two']In [76]: df['flag'] = df['one'] > 2In [77]: dfOut[77]: one two three flaga 1 1 1 Falseb 2 2 4 Falsec 3 3 9 Trued NaN 4 NaN False
列可以类似于dict一样,删除或者取出
In [78]: del df['two']In [79]: three = df.pop('three')In [80]: dfOut[80]: one flaga 1 Falseb 2 Falsec 3 Trued NaN FalseIn [81]: threeOut[81]: a 1b 4c 9d NaNName: three, dtype: float64
当插入一个标量值时,它会自动的填满整列
In [82]: df['foo'] = 'bar'In [83]: dfOut[83]: one flag fooa 1 False barb 2 False barc 3 True bard NaN False bar
当插入一个与DataFrame没有相同索引的Series时,它将匹配DataFrame的索引
In [84]: df['one_trunc'] = df['one'][:2]In [85]: dfOut[85]: one flag foo one_trunca 1 False bar 1b 2 False bar 2c 3 True bar NaNd NaN False bar NaN
也可以插入ndarray,但是它的长度必须与DataFrame的索引长度匹配。
默认情况下,列在最后插入。insert函数可用于插入在列的制定位置:
In [87]: dfOut[87]: one bar flag foo one_trunca 1 1 False bar 1b 2 2 False bar 2c 3 3 True bar NaNd NaN NaN False bar NaN
通过方法分配新列
DataFrame具有assign()方法,允许你很方便的创建从现有列派生出来的新列。
In [47]: iris = pd.read_csv(u'data/iris.csv')In [48]: iris.head()Out[48]: SepalLength SepalWidth PetalLength PetalWidth Name0 5.1 3.5 1.4 0.2 Iris-setosa1 4.9 3.0 1.4 0.2 Iris-setosa2 4.7 3.2 1.3 0.2 Iris-setosa3 4.6 3.1 1.5 0.2 Iris-setosa4 5.0 3.6 1.4 0.2 Iris-setosaIn [49]: (iris.assign(sepal_ratio = iris['SepalWidth'] / iris['SepalLength']).head())Out[49]: SepalLength SepalWidth PetalLength PetalWidth Name sepal_ratio0 5.1 3.5 1.4 0.2 Iris-setosa 0.6862751 4.9 3.0 1.4 0.2 Iris-setosa 0.6122452 4.7 3.2 1.3 0.2 Iris-setosa 0.6808513 4.6 3.1 1.5 0.2 Iris-setosa 0.6739134 5.0 3.6 1.4 0.2 Iris-setosa 0.720000
以上的例子中,先原有的数据中增加了一个预先计算的值。我们同样还可以传递带有一个参数的函数
In [50]: iris.assign(sepal_ratio = lambda x: (x['SepalWidth']/x['SepalLength'])).head()Out[50]: SepalLength SepalWidth PetalLength PetalWidth Name sepal_ratio0 5.1 3.5 1.4 0.2 Iris-setosa 0.6862751 4.9 3.0 1.4 0.2 Iris-setosa 0.6122452 4.7 3.2 1.3 0.2 Iris-setosa 0.6808513 4.6 3.1 1.5 0.2 Iris-setosa 0.6739134 5.0 3.6 1.4 0.2 Iris-setosa 0.720000
assign 始终返回数据的副本,让原始的DataFrame保持原样。
传递一个可调用的,而不是要插入的实际值,当你没有对DataFrame引用时,这是非常有帮助的。在操作链中使用assign,这是很常见的。例如,我们可以把DataFrame限定为花萼长度大于5的数据,然后计算这个比例,进行绘图:
In [51]: (iris.query('SepalLength > 5') ...: .assign(SepalRatio = lambda x: x.SepalWidth / x.SepalLength, ...: PetalRatio = lambda x: x.PetalWidth / x.PetalLength) ...: .plot(kind='scatter', x='SepalRatio', y='PetalRatio'))Out[51]: <matplotlib.axes._subplots.AxesSubplot at 0x1049b8b0>
当函数被传入,函数将在分配给DataFrame时进行计算。重点时,这是将数据过滤为Sepal 长度大于5的行。数据首先被过滤,然后再进行比例的计算。
assign方法的参数 **kwargs。key是列名,value是要插入的值(如Series或Numpy的 array),或者是含有一个参数的函数。调用后将返回,原有的DataFrame的副本加上新增的值。
警告:由于方法的参数为**kwargs,一个字典类型,所以产生的DataFrame中的新列的顺序不能保证与你传入的顺序相同。为了让结果可以预测,在DataFrame的末尾,数据条目将按字母顺序插入。
所有的表达式先行计算,再分配。因此,不能引用另一个在调用时分配的列。比如:
`In [74]: # 不用这样做, 无法引用‘C’列
df.assign(C = lambda x: x[‘A’] + x[‘B’],
D = lambda x: x[‘A’] + x[‘C’])
In [2]: # 更改为调用两次assign方法
(df.assign(C = lambda x: x[‘A’] + x[‘B’])
.assign(D = lambda x: x[‘A’] + x[‘C’]))’
索引/选择
索引的基本操作如下:
行选择器,如,根据索引返回列的Series:
#沿用之前的df对象In [63]: dfOut[63]: one bar flag foo one_trunca 1 1 False bar 1b 2 2 False bar 2c 3 3 True bar NaNd NaN NaN False bar NaN#根据索引标签选择In [64]: df.loc['b']Out[64]: one 2bar 2flag Falsefoo barone_trunc 2Name: b, dtype: object#根据位置选择In [65]: df.iloc[2]Out[65]: one 3bar 3flag Truefoo barone_trunc NaNName: c, dtype: object
数据对齐和运算
DataFrame对象之间的数据对齐会自动在列和索引(行标签)上对齐。同样,生产的对象将是列和行标签的并集。
In [69]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])In [70]: dfOut[70]: A B C D0 -1.081213 0.964799 -1.526936 0.8570951 0.786559 -0.824999 0.373886 0.3831982 -0.026515 -0.539306 0.987269 0.0451013 -0.726887 -1.176843 -0.799625 -0.1921554 -1.180493 2.145532 0.682645 0.3172005 1.041298 -1.334093 0.346744 -0.2224026 -0.553535 -1.031090 -1.738747 -0.4042987 0.367074 -1.312607 0.811453 -0.8290418 1.150281 -0.435246 0.686140 1.6727139 -2.811454 -0.064040 -0.173748 0.156016In [71]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])In [72]: df2Out[72]: A B C0 -0.116847 2.508202 -0.2060531 -0.264634 -0.440654 0.3559292 -0.805070 1.162288 0.6372933 -0.423643 0.854117 -0.3854284 0.790752 0.084708 -0.6994945 2.139285 -0.546327 0.3814956 -0.086828 1.019701 0.448619In [73]: df + df2Out[73]: A B C D0 -1.198059 3.473001 -1.732989 NaN1 0.521925 -1.265653 0.729814 NaN2 -0.831585 0.622982 1.624562 NaN3 -1.150530 -0.322726 -1.185053 NaN4 -0.389741 2.230240 -0.016849 NaN5 3.180583 -1.880420 0.728239 NaN6 -0.640363 -0.011389 -1.290128 NaN7 NaN NaN NaN NaN8 NaN NaN NaN NaN9 NaN NaN NaN NaN
当在DataFrame和Series之间进行操作时,默认的行为是在DataFrame列上对其Series索引,然后安装行的宽度进行广播。例如:
In [74]: df.iloc[0]Out[74]: A -1.081213B 0.964799C -1.526936D 0.857095Name: 0, dtype: float64In [75]: df - df.iloc[0]Out[75]: A B C D0 0.000000 0.000000 0.000000 0.0000001 1.867771 -1.789798 1.900821 -0.4738972 1.054698 -1.504105 2.514205 -0.8119943 0.354326 -2.141642 0.727311 -1.0492504 -0.099280 1.180733 2.209580 -0.5398965 2.122511 -2.298892 1.873680 -1.0794986 0.527677 -1.995888 -0.211811 -1.2613937 1.448286 -2.277405 2.338389 -1.6861368 2.231494 -1.400045 2.213076 0.8156189 -1.730241 -1.028839 1.353188 -0.701080
在处理时间Series数据的特殊情况下,并且DataFrame索引也包含日期,将根据列的宽度进行广播:
In [76]: index = pd.date_range('1/1/2000', periods=8)In [77]: indexOut[77]: DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04', '2000-01-05', '2000-01-06', '2000-01-07', '2000-01-08'], dtype='datetime64[ns]', freq='D', tz=None)In [78]: df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=list('ABC'))In [79]: dfOut[79]: A B C2000-01-01 1.658336 0.312690 0.4343802000-01-02 1.588613 1.044227 -0.5480432000-01-03 1.453697 0.634530 -1.1254642000-01-04 1.799968 -0.579391 0.0478572000-01-05 -0.053769 0.067639 0.1956622000-01-06 -1.863360 0.772522 0.6907782000-01-07 -0.157916 -0.605435 0.3247582000-01-08 -1.265800 0.157990 0.022863In [80]: type(df['A'])Out[80]: pandas.core.series.SeriesIn [81]: df - df['A']Out[81]: 2000-01-01 00:00:00 2000-01-02 00:00:00 2000-01-03 00:00:00 \2000-01-01 NaN NaN NaN 2000-01-02 NaN NaN NaN 2000-01-03 NaN NaN NaN 2000-01-04 NaN NaN NaN 2000-01-05 NaN NaN NaN 2000-01-06 NaN NaN NaN 2000-01-07 NaN NaN NaN 2000-01-08 NaN NaN NaN 2000-01-04 00:00:00 ... 2000-01-08 00:00:00 A B C 2000-01-01 NaN ... NaN NaN NaN NaN 2000-01-02 NaN ... NaN NaN NaN NaN 2000-01-03 NaN ... NaN NaN NaN NaN 2000-01-04 NaN ... NaN NaN NaN NaN 2000-01-05 NaN ... NaN NaN NaN NaN 2000-01-06 NaN ... NaN NaN NaN NaN 2000-01-07 NaN ... NaN NaN NaN NaN 2000-01-08 NaN ... NaN NaN NaN NaN [8 rows x 11 columns]
警告
df-df['A']
现在已被弃用,并将被删除。实现这种行为的最佳方式
df.sub(df['A'], axis=0)
标量的操作正如你期望的那样:
In [85]: df * 5 + 2Out[85]: A B C2000-01-01 10.291678 3.563450 4.1719002000-01-02 9.943063 7.221136 -0.7402132000-01-03 9.268486 5.172651 -3.6273192000-01-04 10.999838 -0.896953 2.2392862000-01-05 1.731153 2.338194 2.9783082000-01-06 -7.316800 5.862611 5.4538922000-01-07 1.210420 -1.027175 3.6237912000-01-08 -4.329001 2.789950 2.114315In [86]: 1 / dfOut[86]: A B C2000-01-01 0.603014 3.198056 2.3021322000-01-02 0.629480 0.957646 -1.8246752000-01-03 0.687901 1.575969 -0.8885232000-01-04 0.555566 -1.725951 20.8954892000-01-05 -18.597913 14.784416 5.1108672000-01-06 -0.536665 1.294461 1.4476422000-01-07 -6.332484 -1.651705 3.0792152000-01-08 -0.790014 6.329511 43.738650In [87]: df ** 4Out[87]: A B C2000-01-01 7.562925 0.009560 3.560239e-022000-01-02 6.369012 1.188995 9.021058e-022000-01-03 4.465763 0.162110 1.604450e+002000-01-04 10.496843 0.112690 5.245535e-062000-01-05 0.000008 0.000021 1.465621e-032000-01-06 12.055550 0.356159 2.276957e-012000-01-07 0.000622 0.134360 1.112346e-022000-01-08 2.567206 0.000623 2.732364e-07
布尔运算同样有效
In [88]: df1 = pd.DataFrame({'a': [1, 0, 1], 'b': [0, 1, 1]}, dtype=bool)In [89]: df2 = pd.DataFrame({'a': [0, 1, 1], 'b': [1, 1, 0]}, dtype=bool)In [90]: df1 & df2Out[90]: a b0 False False1 False True2 True FalseIn [91]: df1 | df2Out[91]: a b0 True True1 True True2 True TrueIn [92]: df1 ^ df2Out[92]: a b0 True True1 True False2 False TrueIn [93]: -df1Out[93]: a b0 False True1 True False2 False False
行列转换
对于行列转换,访问T属性(也就是transpose函数),类似于ndarray:
In [95]: df[:5]Out[95]: A B C2000-01-01 1.658336 0.312690 0.4343802000-01-02 1.588613 1.044227 -0.5480432000-01-03 1.453697 0.634530 -1.1254642000-01-04 1.799968 -0.579391 0.0478572000-01-05 -0.053769 0.067639 0.195662In [96]: df[:5].TOut[96]: 2000-01-01 2000-01-02 2000-01-03 2000-01-04 2000-01-05A 1.658336 1.588613 1.453697 1.799968 -0.053769B 0.312690 1.044227 0.634530 -0.579391 0.067639C 0.434380 -0.548043 -1.125464 0.047857 0.195662
DataFrame与Numpy函数的互操作
如果对象中的数据是数值型的,那么可以在DataFrame上使用Numpy的ufunc(log, exp, sqrt,…)和其他各种函数:
In [97]: np.exp(df)Out[97]: A B C2000-01-01 5.250565 1.367098 1.5440052000-01-02 4.896950 2.841202 0.5780802000-01-03 4.278905 1.886136 0.3245022000-01-04 6.049451 0.560240 1.0490212000-01-05 0.947651 1.069979 1.2161152000-01-06 0.155150 2.165220 1.9952682000-01-07 0.853922 0.545837 1.3836962000-01-08 0.282014 1.171155 1.023126In [98]: np.asarray(df)Out[98]: array([[ 1.65833568, 0.31269 , 0.43437997], [ 1.58861263, 1.04422716, -0.54804266], [ 1.45369711, 0.63453025, -1.12546386], [ 1.79996757, -0.57939064, 0.04785722], [-0.05376948, 0.06763879, 0.19566152], [-1.86335996, 0.77252217, 0.69077835], [-0.15791591, -0.60543491, 0.3247581 ], [-1.26580024, 0.15799008, 0.02286307]])
DataFrame上的dot方法,实现了矩阵的点积运算:
In [99]: df.T.dot(df)Out[99]: A B CA 15.729075 0.509448 -3.078136B 0.509448 2.919385 -0.824455C -3.078136 -0.824455 2.379445
类似的,Series的dot方法也实现了点积运算:
In [101]: s1 = pd.Series(np.arange(5, 10))In [102]: s1Out[102]: 0 51 62 73 84 9dtype: int32In [103]: s1.dot(s1)Out[103]: 255
控制台显示
非常大的DataFrame将在控制台中被截断显示。你可以使用info()来获取摘要信息。
In [108]: iris = pd.read_csv(u'data/iris.csv')In [109]: print(iris) SepalLength SepalWidth PetalLength PetalWidth Name0 5.1 3.5 1.4 0.2 Iris-setosa1 4.9 3.0 1.4 0.2 Iris-setosa2 4.7 3.2 1.3 0.2 Iris-setosa3 4.6 3.1 1.5 0.2 Iris-setosa4 5.0 3.6 1.4 0.2 Iris-setosa5 5.2 3.5 1.4 0.2 Iris-setosa6 4.9 3.0 1.7 0.2 Iris-setosa7 5.4 3.2 1.5 0.3 Iris-setosa8 4.6 3.1 1.4 0.2 Iris-setosa9 5.3 3.6 1.4 0.2 Iris-setosa10 5.1 3.5 1.4 0.2 Iris-setosa11 4.9 3.0 1.4 0.3 Iris-setosa12 4.7 3.6 1.3 0.2 Iris-setosa13 4.6 3.1 1.5 0.2 Iris-setosa14 5.0 3.6 1.4 0.2 Iris-setosa15 5.2 3.5 1.4 0.2 Iris-setosa16 4.9 3.0 1.6 0.2 Iris-setosa17 5.4 3.2 1.7 0.3 Iris-setosa18 4.6 3.2 1.5 0.2 Iris-setosa19 5.3 3.1 1.4 0.4 Iris-setosa20 5.3 3.6 1.4 0.2 Iris-setosa21 5.1 3.0 1.4 0.2 Iris-setosa22 4.9 3.2 1.4 0.2 Iris-setosa23 4.7 3.1 1.4 0.5 Iris-setosa24 4.9 3.6 1.3 0.2 Iris-setosa25 4.7 3.5 1.5 0.3 Iris-setosa26 4.6 3.0 1.4 0.2 Iris-setosa27 5.3 3.6 1.3 0.2 Iris-setosa28 5.3 3.1 1.8 0.2 Iris-setosa29 5.3 3.0 1.4 0.7 Iris-setosa.. ... ... ... ... ...573 5.1 3.5 1.4 0.2 Iris-setosa574 4.9 3.0 1.4 0.3 Iris-setosa575 4.7 3.6 1.3 0.2 Iris-setosa576 4.6 3.1 1.5 0.2 Iris-setosa577 5.0 3.6 1.4 0.2 Iris-setosa578 5.2 3.5 1.4 0.2 Iris-setosa579 4.9 3.0 1.6 0.2 Iris-setosa580 5.4 3.2 1.7 0.3 Iris-setosa581 4.6 3.2 1.5 0.2 Iris-setosa582 5.3 3.1 1.4 0.4 Iris-setosa583 5.3 3.6 1.4 0.2 Iris-setosa584 5.1 3.0 1.4 0.2 Iris-setosa585 4.9 3.2 1.4 0.2 Iris-setosa586 4.7 3.1 1.4 0.5 Iris-setosa587 4.9 3.6 1.3 0.2 Iris-setosa588 4.7 3.5 1.5 0.3 Iris-setosa589 4.6 3.0 1.4 0.2 Iris-setosa590 5.3 3.6 1.3 0.2 Iris-setosa591 5.3 3.1 1.8 0.2 Iris-setosa592 5.3 3.0 1.4 0.7 Iris-setosa593 5.1 3.2 1.4 0.2 Iris-setosa594 4.9 3.1 1.4 0.2 Iris-setosa595 4.7 3.6 1.3 0.2 Iris-setosa596 5.1 3.1 1.5 0.2 Iris-setosa597 4.9 3.6 1.4 0.3 Iris-setosa598 5.2 3.5 1.4 0.2 Iris-setosa599 4.9 3.0 1.6 0.2 Iris-setosa600 5.4 3.2 1.4 0.2 Iris-setosa601 4.6 3.1 1.3 0.7 Iris-setosa602 5.3 3.6 1.8 0.2 Iris-setosa[603 rows x 5 columns]In [110]: iris.info()<class 'pandas.core.frame.DataFrame'>Int64Index: 603 entries, 0 to 602Data columns (total 5 columns):SepalLength 603 non-null float64SepalWidth 603 non-null float64PetalLength 603 non-null float64PetalWidth 603 non-null float64Name 603 non-null objectdtypes: float64(4), object(1)memory usage: 25.9+ KBIn [111]: iris = pd.read_csv(u'data/iris.csv')In [112]: print(iris) SepalLength SepalWidth PetalLength PetalWidth Name0 5.1 3.5 1.4 0.2 Iris-setosa1 4.9 3.0 1.4 0.2 Iris-setosa2 4.7 3.2 1.3 0.2 Iris-setosa3 4.6 3.1 1.5 0.2 Iris-setosa.. ... ... ... ................600 5.4 3.2 1.4 0.2 Iris-setosa601 4.6 3.1 1.3 0.7 Iris-setosa602 5.3 3.6 1.8 0.2 Iris-setosa[603 rows x 5 columns]In [113]: iris.info()<class 'pandas.core.frame.DataFrame'>Int64Index: 603 entries, 0 to 602Data columns (total 5 columns):SepalLength 603 non-null float64SepalWidth 603 non-null float64PetalLength 603 non-null float64PetalWidth 603 non-null float64Name 603 non-null objectdtypes: float64(4), object(1)memory usage: 25.9+ KB
然而,使用to_string将以字符串的形式显示DataFrame,虽然它并不总是适合于控制台的宽度
In [116]: print(iris.iloc[-20:, ].to_string()) SepalLength SepalWidth PetalLength PetalWidth Name583 5.3 3.6 1.4 0.2 Iris-setosa584 5.1 3.0 1.4 0.2 Iris-setosa585 4.9 3.2 1.4 0.2 Iris-setosa586 4.7 3.1 1.4 0.5 Iris-setosa587 4.9 3.6 1.3 0.2 Iris-setosa588 4.7 3.5 1.5 0.3 Iris-setosa589 4.6 3.0 1.4 0.2 Iris-setosa590 5.3 3.6 1.3 0.2 Iris-setosa591 5.3 3.1 1.8 0.2 Iris-setosa592 5.3 3.0 1.4 0.7 Iris-setosa593 5.1 3.2 1.4 0.2 Iris-setosa594 4.9 3.1 1.4 0.2 Iris-setosa595 4.7 3.6 1.3 0.2 Iris-setosa596 5.1 3.1 1.5 0.2 Iris-setosa597 4.9 3.6 1.4 0.3 Iris-setosa598 5.2 3.5 1.4 0.2 Iris-setosa599 4.9 3.0 1.6 0.2 Iris-setosa600 5.4 3.2 1.4 0.2 Iris-setosa601 4.6 3.1 1.3 0.7 Iris-setosa602 5.3 3.6 1.8 0.2 Iris-setosa
如果DataFrame有10列,他们超过控制台宽度的列默认将隔行显示:
In [117]: pd.DataFrame(np.random.randn(3, 12))Out[117]: 0 1 2 3 4 5 6 \0 -0.119700 0.086073 -1.741760 0.115469 -0.264237 -0.191981 -1.666531 1 -0.650737 0.689219 -1.286211 0.165378 1.189919 0.871147 -0.109856 2 0.507395 0.339061 -1.119778 1.177230 0.046027 0.339424 1.027529 7 8 9 10 11 0 0.156251 -0.839636 1.287716 0.354855 -0.288980 1 0.824025 0.533401 -0.438582 -0.217816 -1.026814 2 -0.302536 1.702276 0.560161 -1.123736 -0.498265
通过设置display.with选项,可以改变控制台每一行显示的列个数
In [118]: pd.set_option('display.width', 40) #默认为80In [119]: pd.DataFrame(np.random.randn(3, 12))Out[119]: 0 1 2 \0 1.217084 -0.558679 -1.257722 1 -0.214153 1.239619 0.903324 2 -0.290766 0.698407 0.009694 3 4 5 \0 0.308694 -0.057101 0.572316 1 0.475061 -1.139262 2.080925 2 1.201881 -0.486657 -1.642377 6 7 8 \0 -0.547218 -1.311481 0.778549 1 -0.633969 0.764801 -1.325743 2 0.854663 1.932424 -0.146767 9 10 11 0 0.613871 1.603854 -0.992278 1 -0.848804 0.358653 -0.689318 2 0.204168 1.043873 -0.345096
可以通过设置display.max_colwidth来调整各个列的最大宽度
In [120]: datafile={'filename': ['filename_01','filename_02'], ...: .....: 'path': ["media/user_name/storage/folder_01/filename_01", ...: .....: "media/user_name/storage/folder_02/filename_02"]}In [121]: pd.set_option('display.max_colwidth', 30)In [122]: pd.DataFrame(datafile)Out[122]: filename \0 filename_01 1 filename_02 path 0 media/user_name/storage/fo... 1 media/user_name/storage/fo... In [123]: pd.set_option('display.max_colwidth', 100)In [124]: pd.DataFrame(datafile)Out[124]: filename \0 filename_01 1 filename_02 path 0 media/user_name/storage/folder_01/filename_01 1 media/user_name/storage/folder_02/filename_02
还可以通过扩展framerepr选项禁用此功能。这将在一个块中打印表。
DataFrame列属性访问
如果DataFrame的列标签是一个Python的变量名,那么列可以像属性一样访问:
In [125]: df = pd.DataFrame({'foo1': np.random.randn(5), ...: 'foo2': np.random.randn(5)})In [126]: dfOut[126]: foo1 foo20 1.095587 -0.1351471 1.049579 -0.1178082 1.029435 1.4387573 0.177883 0.1231954 -0.964396 -2.319625In [127]: df.foo1Out[127]: 0 1.0955871 1.0495792 1.0294353 0.1778834 -0.964396Name: foo1, dtype: float64
Panel
Panel很少用到,但它仍然是三维数据的重要容器。术语panel data来源于计量经济学,它对pandas的命名有部分借鉴意义:pan(el)-da(ta)-s。三个轴的名称旨在为描述panel data的操作提供一些语义上的描述,尤其是,panel data的计量经济分析。但是,为了严格的分割DataFrame对象的集合,你可能会发现这些轴的名称有些随意:
- items: 轴0, 每个item相当于一个DataFrame包含在其中
- major_axis: 轴1,它是每个DataFrame的索引(行)
- minor_axis: 轴2, 它是每个DataFrame的列
Panel的构造方式和你想的一样:
从带有可选轴标签的3D ndarray构造
In [135]: 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'])In [136]: wpOut[136]: <class 'pandas.core.panel.Panel'>Dimensions: 2 (items) x 5 (major_axis) x 4 (minor_axis)Items axis: item1 to item2Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00Minor_axis axis: A to D
从包含DataFrame的字典类型构造
In [137]: data = {'Item1': pd.DataFrame(np.random.randn(4, 3)), ...: 'Item2': pd.DataFrame(np.random.randn(4, 2))}In [138]: pd.Panel(data)Out[138]: <class 'pandas.core.panel.Panel'>Dimensions: 2 (items) x 4 (major_axis) x 3 (minor_axis)Items axis: Item1 to Item2Major_axis axis: 0 to 3Minor_axis axis: 0 to 2
注意,字典中的Value只需要可以被转换为DataFrame。因此,他们可以是DataFrame的任何其他有效输入。
一个有效的工厂方法是Panel.from_dict,它使用了上面的DataFrame字典,以及下面的命名参数:
例如,与前面的构造方式比较:
In [139]: pd.Panel.from_dict(data, orient='minor')Out[139]: <class 'pandas.core.panel.Panel'>Dimensions: 3 (items) x 4 (major_axis) x 2 (minor_axis)Items axis: 0 to 2Major_axis axis: 0 to 3Minor_axis axis: Item1 to Item2
orient对于混合类型的DataFrame尤其有帮助。如果你传递了一个含有混合类型列DataFrame的字典对象,所有的数据都将被显示为dtype=object,除非你将设置orient=’minor’:
In [140]: df = pd.DataFrame({'a': ['foo', 'bar', 'baz'], ...: 'b': np.random.randn(3)})In [141]: dfOut[141]: a b0 foo 0.0758891 bar -0.4502202 baz 1.570256In [142]: data = {'item1': df, 'item2': df}In [143]: panel = pd.Panel.from_dict(data, orient='minor')In [144]: panel['a']Out[144]: item1 item20 foo foo1 bar bar2 baz bazIn [145]: panel['b']Out[145]: item1 item20 0.075889 0.0758891 -0.450220 -0.4502202 1.570256 1.570256In [146]: panel['b'].dtypesOut[146]: item1 float64item2 float64dtype: object
注意:不幸的是,panel相较于Series和DataFrame更少被使用,因为它在功能的完整性上被忽视了。DataFrame中的许多有效的方法和选项在panel中都不能使用。当然,这将在未来的版本中得到解决。
使用to_panel方法从DataFrame构造
这个方法是在v0.7中引进的,用于取代LongPanel.to_long,将一个带有双级索引的DataFrame转换为一个Panel。
In [149]: midx = pd.MultiIndex(levels=[['one', 'two'], ['x', 'y']], labels=[[1, 1, 0, 0], [1, 0, 1, 0]])In [150]: df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]}, index=midx)In [151]: dfOut[151]: A Btwo y 1 5 x 2 6one y 3 7 x 4 8In [152]: df.to_panel()Out[152]: <class 'pandas.core.panel.Panel'>Dimensions: 2 (items) x 2 (major_axis) x 2 (minor_axis)Items axis: A to BMajor_axis axis: one to twoMinor_axis axis: x to y
Item的选择/添加/删除
正如DataFrame的操作类似于含有字典类型的Series, 而Penel则类似于含有字典类型的DataFrame:
In [156]: wp['item1']Out[156]: A B C D2000-01-01 -1.459119 -0.167279 -0.105919 -1.5891552000-01-02 -1.224224 -0.500770 -0.169742 0.2475582000-01-03 -1.064092 -1.832947 0.094414 -0.4458642000-01-04 -0.092463 -1.629868 0.183957 -0.7023272000-01-05 1.086481 -2.833691 0.010039 -0.101303In [157]: wp['item3'] = wp['item1'] / wp['item2']In [158]: wpOut[158]: <class 'pandas.core.panel.Panel'>Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)Items axis: item1 to item3Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00Minor_axis axis: A to D
插入和删除的API和DataFrame相同。同DataFrame一样,如果item是一个有效的标识符,那么可以将它作为属性来访问。
转换
Panel可以通过transpose方法来进行重新排列(除非数据是异构的,否则默认情况下不会生成副本)
In [160]: wpOut[160]: <class 'pandas.core.panel.Panel'>Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)Items axis: item1 to item3Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00Minor_axis axis: A to DIn [161]: wp.transpose(2, 0, 1)Out[161]: <class 'pandas.core.panel.Panel'>Dimensions: 4 (items) x 3 (major_axis) x 5 (minor_axis)Items axis: A to DMajor_axis axis: item1 to item3Minor_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
索引和选择
例如,使用前面的数据,我们可以这样做:
In [164]: wp['item1']Out[164]: A B C D2000-01-01 -1.459119 -0.167279 -0.105919 -1.5891552000-01-02 -1.224224 -0.500770 -0.169742 0.2475582000-01-03 -1.064092 -1.832947 0.094414 -0.4458642000-01-04 -0.092463 -1.629868 0.183957 -0.7023272000-01-05 1.086481 -2.833691 0.010039 -0.101303In [165]: wp.major_xs(wp.major_axis[2])Out[165]: item1 item2 item3A -1.064092 0.813871 -1.307446B -1.832947 -2.016451 0.908996C 0.094414 -0.456631 -0.206762D -0.445864 -0.417404 1.068182In [166]: wp.minor_axisOut[166]: Index([u'A', u'B', u'C', u'D'], dtype='object')In [167]: wp.minor_xs('C')Out[167]: item1 item2 item32000-01-01 -0.105919 1.211176 -0.0874512000-01-02 -0.169742 1.823682 -0.0930772000-01-03 0.094414 -0.456631 -0.2067622000-01-04 0.183957 0.585720 0.3140702000-01-05 0.010039 0.622204 0.016134
压缩
另一种改变对象维数的方法是squeeze 一个一维的对象,类似于wp[‘item1’]
In [168]: wp.reindex(items=['item1']).squeeze()Out[168]: A B C D2000-01-01 -1.459119 -0.167279 -0.105919 -1.5891552000-01-02 -1.224224 -0.500770 -0.169742 0.2475582000-01-03 -1.064092 -1.832947 0.094414 -0.4458642000-01-04 -0.092463 -1.629868 0.183957 -0.7023272000-01-05 1.086481 -2.833691 0.010039 -0.101303In [169]: wp.reindex(items=['item1'], minor=['B']).squeeze()Out[169]: 2000-01-01 -0.1672792000-01-02 -0.5007702000-01-03 -1.8329472000-01-04 -1.6298682000-01-05 -2.833691Freq: D, Name: B, dtype: float64
转换为DataFrame
一个Panel可以用2D的形式表示一个分层索引的DataFrame.要将Panel对象转换为DataFrame,可以使用toframe方法:
In [171]: panel = pd.Panel(np.random.randn(3, 5, 4), items=['one', 'two', 'three'], ...: major_axis=pd.date_range('1/1/2000', periods=5), ...: minor_axis=['a', 'b', 'c', 'd'])In [172]: panel.to_frame()Out[172]: one two threemajor minor 2000-01-01 a -0.058576 -0.026163 0.289173 b 1.333492 1.514565 -0.233190 c -0.817197 2.144006 -0.126894 d -1.205514 -0.572632 -0.3096792000-01-02 a 0.230310 2.712063 -0.311404 b -0.070901 -1.373851 1.284403 c 0.928690 2.084200 -0.151439 d 1.326599 -0.571143 -0.2423542000-01-03 a -0.684355 1.875092 0.692001 b 1.542806 -1.416353 -0.555132 c 1.048785 0.873523 -0.186362 d 1.457121 -1.266636 -0.9353502000-01-04 a -0.821748 -0.900330 -1.458795 b 0.964931 0.119338 -0.534120 c -0.778703 0.470976 0.913389 d -0.078422 0.308533 -0.1280642000-01-05 a -0.075534 0.700830 0.292943 b 0.291545 0.636898 -0.927162 c 1.103668 -0.697442 -1.354032 d -1.209118 0.258653 -0.119056
- 数据分析之Pandas——数据结构
- 利用Pandas进行数据分析(1)——pandas数据结构
- [Python数据分析-01]Pandas数据结构之Series
- [Panads数据分析-02]Pandas数据结构之DataFrame
- python数据分析:pandas数据结构与操作
- python数据分析复盘——数据分析相关库之Pandas
- Python——数据分析Pandas入门
- 数据分析之Pandas-05数据加载
- 利用pandas进行数据分析之二:DataFrame与Series数据结构对比
- python数据分析之(3)pandas
- Python数据分析之pandas学习
- python数据分析之pandas包
- Python数据分析之pandas基础
- Python数据分析之pandas统计分析
- Python数据分析之pandas学习
- 数据分析之Pandas-03绘图函数
- Python数据分析之pandas学习
- Python数据分析之pandas ,part1
- Android开发动态添加布局且平均占屏幕大小
- 玩转Eclipse — 自动代码规范检查工具Checkstyle
- unity3d 给游戏添加音源 Unity3d adds a sound source to the game
- java中字符串()的用法
- POJ
- 数据分析之Pandas——数据结构
- C#事件应用
- 快速乘法
- flume+kafka+zookeeper 单机实现实时数据的获取
- Cocos2d-X开发教程-捕鱼达人 Cocos2-x development tutorial
- 查看Linux下系统资源占用常用命令(top、free、uptime)
- java中String和StringBuffer的区别
- Android 贝塞尔曲线简单应用(一)
- 3d角色模型 制作 全过程 。3d max 。3d role model making process.3d Max