本博客为《利用Python进行数据分析》的读书笔记,请勿转载用于其他商业用途。
1、Series
Series是一种一维的数组型对象,它包含了一个值序列,并且包含了数据标签,称为索引(index)。最简单的序列可以仅仅由一个数组形成:
import pandas as pd
obj = pd.Series([4, 7, -5, 3])
print(obj)
#
0 4
1 7
2 -5
3 3
dtype: int64
交互式环境中Series的字符串表示,索引在左边,值在右边。由于不为数据指定索引,默认生成的索引是从0到N-1(N是数据的长度)。我们可以通过values属性和index属性分别获得Series对象的值和索引:
print(obj.values)
print(obj.index)
#
[ 4 7 -5 3]
RangeIndex(start=0, stop=4, step=1)
通常需要创建一个索引序列,用标签标识每个数据点:
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
print(obj2)
print(obj2.index)
#
d 4
b 7
a -5
c 3
dtype: int64
Index(['d', 'b', 'a', 'c'], dtype='object')
与Numpy相比,我们可以在从数据中选择数据的时候使用标签来进行索引:
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
print(obj2['a'])
obj2['d'] = 6
print(obj2[['c', 'a', 'd']])
#
-5
c 3
a -5
d 6
dtype: int64
这里需要注意的是,我们在输出obj2索引为 c、a、d的值时,使用了2个中括号。['c', 'a', 'd']包含的不是数字而是字符串,作为索引列表。
使用Numpy的函数或Numpy风格的操作,比如使用布尔值数组进行过滤,与标量相乘,或是应用数学函数,这些操作将保存索引值链接:
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
print(obj2[obj2 > 0])
print(obj2 * 2)
print(np.exp(obj2))
#
d 4
b 7
c 3
dtype: int64
d 8
b 14
a -10
c 6
dtype: int64
d 54.598150
b 1096.633158
a 0.006738
c 20.085537
dtype: float64
从另一个角度考虑Series,可以认为它是一个长度固定且有序的字典,因为它将索引值的数据值按位置配对。
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
print('b' in obj2)
print('e' in obj2)
#
True
False
如果已经有数据包含在Python字典中,可以使用字典生成一个Series:
sdata = {'Ohio':35000, 'Texas':71000, 'Oregon':16000, 'Utah':5000}
obj3 = pd.Series(sdata)
print(obj3)
#
Ohio 35000
Texas 71000
Oregon 16000
Utah 5000
dtype: int64
当把字典传递给Series构造函数时,产生的Series的索引将是排序好的字典键。可以将字典键按照想要的顺序传递给构造函数,从而使生成的Series的索引顺序符合预期:
sdata = {'Ohio':35000, 'Texas':71000, 'Oregon':16000, 'Utah':5000}
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = pd.Series(sdata, index=states)
print(obj4)
#
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
“NA”表示缺失数据。pandas中使用isnull和notnull来检查缺失数据:
print(pd.isnull(obj4))
print(pd.notnull(obj4))
#
California True
Ohio False
Oregon False
Texas False
dtype: bool
California False
Ohio True
Oregon True
Texas True
dtype: bool
isnull和notnull也是Series的实例方法:
print(obj4.isnull())
#
California True
Ohio False
Oregon False
Texas False
dtype: bool
Series对象自身和其索引都有name属性,这个特性与pandas其他重要功能集成在一起:
obj4.name = 'population'
obj4.index.name = 'states'
print(obj4)
#
states
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
Name: population, dtype: float64
Series的索引可以通过按位置赋值的方式进行改变:
obj = pd.Series([4, 7, -5, 3])
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
print(obj)
#
Bob 4
Steve 7
Jeff -5
Ryan 3
dtype: int64
2、DataFrame
DataFrame表示的是矩阵的数据表,它包含已排序的列集合,每一列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被视为一个共享相同索引的Series的字典。在DataFrame中,数据被储存为一个以上的二维块,而不是列表、字典或其他一维数组的集合。
尽管DataFrame是二维的,但我们可以利用分层索引在DataFrame中展现更高维度的数据。分层索引是pandas中一种更为高级的数据处理特性。
有多种方式可以构建DataFrame,其中最常用的方式是利用包含等长度列表或Numpy数组的字典来形成DataFrame:
data = {'states': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002, 2003],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)
print(frame)
#
states year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
5 Nevada 2003 3.2
产生的DataFrame会自动为Series分配索引,并且列会按照排序的顺序排列。对于大型DataFrame,head方法将会只选出头部的5行:
print(frame.head())
#
states year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
如果指定了列的顺序,DataFrame的列将会按照指定顺序排列:
frame1 = pd.DataFrame(data, columns=['year', 'states', 'pop'])
print(frame1)
#
year states pop
0 2000 Ohio 1.5
1 2001 Ohio 1.7
2 2002 Ohio 3.6
3 2001 Nevada 2.4
4 2002 Nevada 2.9
5 2003 Nevada 3.2
如果传的列不包含在字典中,将会在结果中出现缺失值:
frame2 = pd.DataFrame(data, columns=['year', 'states', 'pop', 'debt'],
index=['one', 'two', 'three', 'four', 'five', 'six'])
print(frame2)
#
year states 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
six 2003 Nevada 3.2 NaN
DataFrame中的一列,可以按字典型标记或属性那样检索为Series:
print(frame2['states'])
print(frame2.year)
#
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
six Nevada
Name: states, dtype: object
one 2000
two 2001
three 2002
four 2001
five 2002
six 2003
Name: year, dtype: int64
注意,返回的Series与原DataFrame有相同的索引,且Series的name属性也会被合理设置。行也可以通过为止或特殊属性loc进行选取:
print(frame2.loc['three'])
#
year 2002
states Ohio
pop 3.6
debt NaN
Name: three, dtype: object
列的引用是可以修改的,例如空的“debt”列可以赋值为标量值或数组值:
frame2['debt'] = 16.5
print(frame2)
#
year states pop debt
one 2000 Ohio 1.5 16.5
two 2001 Ohio 1.7 16.5
three 2002 Ohio 3.6 16.5
four 2001 Nevada 2.4 16.5
five 2002 Nevada 2.9 16.5
six 2003 Nevada 3.2 16.5
frame2['debt'] = np.arange(6)
print(frame2)
#
year states pop debt
one 2000 Ohio 1.5 0
two 2001 Ohio 1.7 1
three 2002 Ohio 3.6 2
four 2001 Nevada 2.4 3
five 2002 Nevada 2.9 4
six 2003 Nevada 3.2 5
当我们将列表或数组赋值给一个列时,值的长度必须和DataFrame的长度相匹配。如果我们将Series赋值给一列时,Series的索引将会按照DataFrame的索引重新排列,并在空缺的地方填充缺失值:
val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
print(frame2)
#
year states pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7
six 2003 Nevada 3.2 NaN
如果被赋值的列并不存在,则会生成一个新的列。del关键字可以像在字典中那样对DataFrame删除列。
在del的例子中,我们首先增加一列,这一列时布尔值,判断条件是states列是否为‘Ohio’:
frame2['eastern'] = frame2.states == 'Ohio'
print(frame2)
#
year states pop debt eastern
one 2000 Ohio 1.5 NaN True
two 2001 Ohio 1.7 NaN True
three 2002 Ohio 3.6 NaN True
four 2001 Nevada 2.4 NaN False
five 2002 Nevada 2.9 NaN False
six 2003 Nevada 3.2 NaN False
注意:frame.eastern的语法无法创建新的列。
del方法可以用于移除之前新建的列:
del frame2['eastern']
print(frame2.columns)
#
Index(['year', 'states', 'pop', 'debt'], dtype='object')
注意:从DataFrame中选取的列是数据的视图,而不是拷贝。因此,对Series的修改会映射到DataFrame中。如果需要复制,则应当显式地使用Series的copy方法。
另一种常用的数据形式是包含字典的嵌套字典。如果嵌套字典被赋值给DataFrame,pandas会将字典的键作为列,将内部字典的键作为行显式:
pop = {'Nevada': {2001: 2.4, 2002: 2.9},
'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
frame3 = pd.DataFrame(pop)
print(frame3)
#
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2000 NaN 1.5
可以将使用类似Numpy的语法对DataFrame进行转置操作(调换行和列):
print(frame3.T)
#
2001 2002 2000
Nevada 2.4 2.9 NaN
Ohio 1.7 3.6 1.5
内部字典的键被联合、排序后形成了结果的索引。如果已经显式指明索引的话,内部字典的键将不会被排序:
print(pd.DataFrame(pop, index=[2001, 2002, 2003]))
#
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2003 NaN NaN
包含Series的字典也可以用于构造DataFrame:
pdata = {'Ohio': frame3['Ohio'][:-1],
'Nevada': frame3['Nevada'][:2]}
print(pd.DataFrame(pdata))
#
Ohio Nevada
2001 1.7 2.4
2002 3.6 2.9
和Series类似,DataFrame的values属性会将包含在DataFrame中的数据以二维ndarray的形式返回:
print(frame3.values)
#
[[2.4 1.7]
[2.9 3.6]
[nan 1.5]]
如果DataFrame的列是不同dtypes,则values的dtype会自动选择适合所有列的类型:
print(frame2.values)
#
[[2000 'Ohio' 1.5 nan]
[2001 'Ohio' 1.7 nan]
[2002 'Ohio' 3.6 nan]
[2001 'Nevada' 2.4 nan]
[2002 'Nevada' 2.9 nan]
[2003 'Nevada' 3.2 nan]]
DataFrame构造函数的有效输入
类型
注释
2D ndarray
数据的矩阵,行和列的标签是可选参数
数组、列表和元组构成的字典
每个序列称为DataFrame的一列,所有的序列必须长度相等
NumPy结构化/记录化数组
与数组构成的字典一致
Series构成的字典
每个值称为一列,每个Series的索引联合起来形成结果的行索引,也可以显式地传递索引
字典构成的字典
每一个内部字典称为一列,键联合起来形成结果的行索引
字典或Series构成的列表
列表中的一个元素形成DataFrame的一行,字典键或Series索引联合起来形成DataFrame的列标签
列表或元组构成的列表
与2D ndarray的情况一致
其他DataFrame 如果不显示传递索引,则会使用原DataFrame的索引 NumPy MaskedArray 与2D ndarray的情况类似,但隐蔽值会在结果DataFrame中称为NA/缺失值3、索引对象
pandas中的索引对象是用于储存轴标签和其他元数据的。在构造Series或DataFrame时,我们所使用的任意数组或标签都可以在内部转换为索引对象:
obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
print(obj)
print(index)
print(index[1:])
#
a 0
b 1
c 2
dtype: int64
Index(['a', 'b', 'c'], dtype='object')
Index(['b', 'c'], dtype='object')
索引对象是不可改变的,因此用户是无法修改索引对象的。不变性是的在多种数据结构中分享索引对象更为安全:
labels = pd.Index(np.arange(3))
print(labels)
obj2 = pd.Series([1.5, -2.5, 0], index=labels)
print(obj2)
print(obj2.index is labels)
#
Int64Index([0, 1, 2], dtype='int64')
0 1.5
1 -2.5
2 0.0
dtype: float64
True
一些用户并不经常利用索引对象提供的功能,但是因为一些操作会产生包含索引化数据的结果,理解索引如何工作还是很重要的。
方法 | 描述 |
append | 将额外的索引对象粘贴到原索引后,产生一个新的索引 |
difference | 计算两个索引的差集 |
intersection | 计算两个索引的交集 |
union | 计算两个索引的并集 |
isin | 计算表示每一个值是否在传值容器中的布尔数组 |
delete | 将位置i的元素删除,并产生新的索引 |
drop | 根据传参删除指定索引值,并产生新的索引 |
insert | 在位置i插入元素,并产生新的索引 |
is_monotonic | 如果索引序列递增则返回True |
is_unique | 如果索引序列唯一则返回True |
unique | 计算索引的唯一序列值 |