Pandas是基于Numpy构建的库,在数据处理方面可以把它理解为numpy加强版。
核心数据结构
Series
Series是一种类似一维数组的数据结构,由一组数据和与之相关的index组成,这个结构看似与dict字典差不多。字典是一种无序的数据结构,而pandas中的Series的相当于定长有序的字典,并且它的index和value之间是独立的。两者的索引还是有区别的,Series的index是可变的,而dict字典的key值是不可变的。
1、创建
基本的创建函数是:s = pd.Series(data, index=index)
index 是一个列表,用来作为数据的标签;
data 可以是不同的数据类型:Python 字典、ndarray 对象、一个标量值。
导入numpy与pandas
import pandas as pd
import numpy as np
(1)从 ndaray 创建
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
print(s)
print(s.index)
# 运行结果
a -0.258132
b 1.048571
c -0.963465
d 2.857813
e -0.601621
dtype: float64
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
# 当不指定index时,将默认分配
s = pd.Series(np.random.randn(5))
print(s)
print(s.index)
# 运行结果
0 0.324214
1 -0.183776
2 -0.518808
3 0.866421
4 -0.601668
dtype: float64
Int64Index([0, 1, 2, 3, 4], dtype='int64')
(2)从字典创建
d = {'a' : 0., 'b' : 1., 'd' : 3}
s = pd.Series(d, index=list('abcd'))
print(s)
# 运行结果
a 0
b 1
c NaN # 空值默认处理为NaN
d 3
dtype: float64
(3)从标量创建
s = pd.Series(3, index=list('abcde'))
print(s)
# 运行结果
a 3
b 3
c 3
d 3
e 3
dtype: int64
2、特性
(1)类 ndarray 对象
Series具有ndarray 对象的特性。
s = pd.Series(np.random.randn(5))
print(s)
# 运行结果
0 0.043001
1 1.012048
2 -0.377930
3 -0.106193
4 -0.366936
dtype: float64
基本索引
print(s[0])
# 运行结果
0.043000852817569823
print(s[:3])
# 运行结果
0 0.043001
1 1.012048
2 -0.377930
dtype: float64
print(s[[1, 3, 4]])
# 运行结果
1 1.012048
3 -0.106193
4 -0.366936
dtype: float64
函数
np.exp(s)
# 运行结果
0 1.043939
1 2.751231
2 0.685279
3 0.899251
4 0.692854
dtype: float64
np.sin(s)
# 运行结果
0 0.042988
1 0.847920
2 -0.368997
3 -0.105993
4 -0.358757
dtype: float64
(2)类字典对象
Series也具有字典的属性。
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
print(s)
# 运行结果
a -1.394636
b 0.124908
c -0.482848
d -2.381200
e 0.657940
dtype: float64
访问
print(s['a'])
# 运行结果
-1.3946361437252535
赋值
s['e'] = 5
print(s)
# 运行结果
a -1.394636
b 0.124908
c -0.482848
d -2.381200
e 5.000000
dtype: float64
添加元素
s['g'] = 100
print(s)
# 运行结果
a -1.394636
b 0.124908
c -0.482848
d -2.381200
e 5.000000
g 100.000000
dtype: float64
判断元素是否存在
'e' in s
# 运行结果
True
'f' in s
# 运行结果
False
访问不存在的元素
print(s.get('f'))
# 运行结果
None
print(s.get('f', np.nan))
# 运行结果
nan
标签对齐
s1 = pd.Series(np.random.randn(3), index=['a', 'c', 'e'])
s2 = pd.Series(np.random.randn(3), index=['a', 'd', 'e'])
print('{0}\n\n{1}'.format(s1, s2))
# 运行结果
a -0.580191
c 0.605747
e 1.426223
dtype: float64
a 0.651777
d 0.271546
e 0.526227
dtype: float64
print(s1 + s2)
# 运行结果
a 0.071586
c NaN
d NaN
e 1.952450
dtype: float64
(3)name 属性
可以对Series进行命名。
s = pd.Series(np.random.randn(5), name='Some Thing')
print(s)
# 运行结果
0 0.623787
1 0.517239
2 1.551314
3 1.414463
4 -1.224611
Name: Some Thing, dtype: float64
print(s.name)
# 运行结果
'Some Thing'
DataFrame
DataFrame这种数据结构可以看作是一张二维表,Excel表格差不多。DataFrame的横行称为columns,竖列和Series一样称为index,DataFrame每一列可以是不同类型的值集合,所以DataFrame你也可以把它视为不同数据类型同一index的Series集合。
1、创建
创建 DataFrame 的基本格式是:
df = pd.DataFrame(data, index=index, columns=columns)
index 是行标签;
columns 是列标签;
data 可以是如下数据:一维 numpy 数组或list或Series 构成的字典、二维 numpy 数组、 Series、另外的 DataFrame 对象。
(1)从字典创建
Series 构成的字典
d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}
pd.DataFrame(d)
pd.DataFrame(d, index=['d', 'b', 'a'])
pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
list 构成的字典
d = {'one' : [1, 2, 3, 4],
'two' : [21, 22, 23, 24]}
pd.DataFrame(d)
pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
元组构成的复杂字典
d = {('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}}
pd.DataFrame(d)
(2)从结构化数据中创建
元组列表
data = [(1, 2.2, 'Hello'), (2, 3., "World")]
pd.DataFrame(data)
pd.DataFrame(data, index=['first', 'second'], columns=['A', 'B', 'C'])
字典列表
data = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
pd.DataFrame(data)
pd.DataFrame(data, index=['first', 'second'], columns=['a', 'b'])
(3)从 Series 创建
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
pd.DataFrame(s)
pd.DataFrame(s, index=['a', 'c', 'd'], columns=['A'])
2、特性
(1)列赋值/增加/删除
df = pd.DataFrame(np.random.randn(6, 4), columns=['one', 'two', 'three', 'four'])
df
为列赋值
df['three'] = df['one'] + df['two']
df
添加布尔值列
df['flag'] = df['two'] > 0
df
添加标量列
df['five'] = 5
df
复制某一列
df['one_trunc'] = df['one'][:2]
df
指定插入位置
df.insert(1, 'bar', df['one'])
df
删除列
del df['three'] #或df.drop(['two', 'four'], axis=1) 当axis=0时为删除行
df
弹出列
s = df.pop('four')
print(s)
df
使用 assign() 方法来插入新列
该方法不会改变原表格
df.assign(Ratio = df['one'] / df['two'])
df.assign(AB_add = lambda x: x.one + x.two)
(2)基本索引和选择
df = pd.DataFrame(np.random.randint(1, 10, (6, 4)), index=list('abcdef'), columns=list('ABCD'))
df
选择一列
df['A']
# 运行结果
a 3
b 7
c 8
d 5
e 3
f 7
Name: A, dtype: int32
选择一行
df.loc['a'] #也可用df.iloc[0]
# 运行结果
A 3
B 5
C 8
D 1
Name: a, dtype: int32
选择某几行
df[1:4]
df[[False, True, True, False, True, False]]
(3)数据对齐
DataFrame 在进行数据计算时,会自动按行和列进行数据对齐。最终的计算结果会合并两个 DataFrame。
df1 = pd.DataFrame(np.random.randn(10, 4), index=list('abcdefghij'), columns=['A', 'B', 'C', 'D'])
df1
df2 = pd.DataFrame(np.random.randn(7, 3), index=list('cdefghi'), columns=['A', 'B', 'C'])
df2
df1 + df2
df1 - df1.iloc[0]
(3)使用 numpy 函数
Pandas 与 numpy 在核心数据结构上是完全兼容的。
df = pd.DataFrame(np.random.randn(10, 4), columns=['one', 'two', 'three', 'four'])
df
np.exp(df)
np.asarray(df) == df.values
# 运行结果
array([[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True]])
type(np.asarray(df))
# 运行结果
numpy.ndarray
基础运算
更改索引值
1、更改Series的索引值
s = pd.Series([1, 3, 5, 6, 8], index=list('acefh'))
s
# 运行结果
a 1
c 3
e 5
f 6
h 8
dtype: int64
重新指定索引值,多出的索引后默认为NaN
s.reindex(list('abcdefgh'))
# 运行结果
a 1.0
b NaN
c 3.0
d NaN
e 5.0
f 6.0
g NaN
h 8.0
dtype: float64
可指定默认值为某一数字
s.reindex(list('abcdefgh'), fill_value=0)
# 运行结果
a 1
b 0
c 3
d 0
e 5
f 6
g 0
h 8
dtype: int64
使用前面的数值进行填充
s.reindex(list('abcdefgh'), method='ffill')
# 运行结果
a 1
b 1
c 3
d 3
e 5
f 6
g 6
h 8
dtype: int64
使用后面的数值进行填充
s.reindex(list('abcdefgh'), method='bfill')
# 运行结果
a 1
b 3
c 3
d 5
e 5
f 6
g 8
h 8
dtype: int64
2、更改DataFrame的索引值
df = pd.DataFrame(np.random.randn(4, 6), index=list('ADFH'), columns=['one', 'two', 'three', 'four', 'five', 'six'])
df
重新指定行索引,多出的行中默认为NaN
df2 = df.reindex(index=list('ABCDEFGH'))
df2
重新指定列索引,多出的列中默认为NaN
df.reindex(columns=['one', 'three', 'five', 'seven'])
可指定默认值为某一数字
df.reindex(columns=['one', 'three', 'five', 'seven'], fill_value=0)
可使用前一行数值填充默认值,该方法仅对行有效
df.reindex(list('ABCDEFGH'), method='ffill')
使用后一行数值填充默认值
df.reindex(index=list('ABCDEFGH'), method='bfill')
函数应用
apply: 将数据按行或列进行计算
df = pd.DataFrame(np.arange(12).reshape(4, 3), index=['one', 'two', 'three', 'four'], columns=list('ABC'))
df
每一列作为一个 Series 作为参数传递给 lambda 函数
df.apply(lambda x: x.max() - x.min())
# 运行结果
A 9
B 9
C 9
dtype: int64
每一行作为一个 Series 作为参数传递给 lambda 函数
df.apply(lambda x: x.max() - x.min(), axis=1)
# 运行结果
one 2
two 2
three 2
four 2
dtype: int64
返回多个值组成的 Series
def min_max(x):
return pd.Series([x.min(), x.max()], index=['min', 'max'])
df.apply(min_max, axis=1)
applymap: 将数据按元素为进行计算
df = pd.DataFrame(np.random.randn(4, 3), index=['one', 'two', 'three', 'four'], columns=list('ABC'))
df
每个元素保留两位小数
df.applymap('{0:.02f}'.format)
排序和排名
1、Series的排名
s = pd.Series([3, 6, 2, 6, 4])
s
# 运行结果
0 3
1 6
2 2
3 6
4 4
dtype: int64
显示每个索引对应的数值排名,当数值相同时,排名默认取平均
s.rank()
# 运行结果
0 2.0
1 4.5
2 1.0
3 4.5
4 3.0
dtype: float64
可指定先出现的排名靠前
s.rank(method='first')
# 运行结果
0 2.0
1 4.0
2 1.0
3 5.0
4 3.0
dtype: float64
2、DataFrame的排序和排名
df = pd.DataFrame(np.random.randint(1, 10, (4, 3)), index=list('ABCD'), columns=['one', 'two', 'three'])
df
指定按某列数值正序排列
df.sort_values(by='one')
指定按某列数值逆序排列
df.sort_values(by='one',ascending=False)
显示每个位置对应的数值排名,当数值相同时,排名默认取平均
df.rank()
可指定先出现的排名靠前
df.rank(method='first')
数据唯一性及成员资格
s = pd.Series(list('abbcdabacad'))
s
查看包含哪些元素
s.unique()
# 运行结果
array(['a', 'b', 'c', 'd'], dtype=object)
查看每个元素出现的次数
s.value_counts()
# 运行结果
a 4
b 3
d 2
c 2
dtype: int64
查看元素是否在某一集合中
s.isin(['a', 'b', 'c'])
# 运行结果
0 True
1 True
2 True
3 True
4 False
5 True
6 True
7 True
8 True
9 True
10 False
dtype: bool
索引
索引类
pd.*Index?
# 运行结果
pd.CategoricalIndex
pd.DatetimeIndex
pd.Float64Index
pd.Index
pd.Int64Index
pd.IntervalIndex
pd.MultiIndex
pd.PeriodIndex
pd.RangeIndex
pd.TimedeltaIndex
pd.UInt64Index
重复索引
创建一个具有重复索引的Series
s = pd.Series(np.arange(6), index=list('abcbda'))
s
# 运行结果
a 0
b 1
c 2
b 3
d 4
a 5
dtype: int64
对重复的索引值进行索引
s['a']
# 运行结果
a 0
a 5
dtype: int32
判断索引是否唯一
s.index.is_unique
# 运行结果
False
查看存在哪些索引值
s.index.unique()
# 运行结果
Index(['a', 'b', 'c', 'd'], dtype='object')
对重复索引进行处理:sum()相加、first()取第一项、mean()取平均值······
s.groupby(s.index).sum()
# 运行结果
a 5
b 4
c 2
d 4
dtype: int32
多层索引
可以使数据在一个轴上有多个索引级别。即可以用二维的数据表达更高维度的数据,使数据组织方式更清晰。它使用 pd.MultiIndex 类来表示。
比如我们在分析股票数据,我们的一级行索引可以是日期;二级行索引可以是股票代码,列索引可以是股票的交易量,开盘价,收盘价等等。这样我们就可以把多个股票放在同一个时间维度下进行考察和分析。
1、Series 多层索引
a = [['a', 'a', 'a', 'b', 'b', 'c', 'c'], [1, 2, 3, 1, 2, 2, 3]]
tuples = list(zip(*a))
tuples
# 运行结果
[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('c', 2), ('c', 3)]
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
s = pd.Series(np.random.randn(7), index=index)
s
# 运行结果
first second
a 1 -0.446358
2 -0.534837
3 -2.068372
b 1 1.446610
2 -1.249978
c 2 0.737744
3 0.631212
dtype: float64
查看索引
s.index
# 运行结果
MultiIndex([('a', 1),
('a', 2),
('a', 3),
('b', 1),
('b', 2),
('c', 2),
('c', 3)],
names=['first', 'second'])
s.index.levels[0]
# 运行结果
Index([u'a', u'b', u'c'], dtype='object', name=u'first')
s.index.levels[1]
# 运行结果
Int64Index([1, 2, 3], dtype='int64', name='second')
查看不同索引下的数据
s['b']
# 运行结果
second
1 1.446610
2 -1.249978
dtype: float64
s['b':'c']
# 运行结果
first second
b 1 1.446610
2 -1.249978
c 2 0.737744
3 0.631212
dtype: float64
s[:, 2]
# 运行结果
first
a -0.534837
b -1.249978
c 0.737744
dtype: float64
2、DataFrame 多层索引
df = pd.DataFrame(np.random.randint(1, 10, (4, 3)),
index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
columns=[['one', 'one', 'two'], ['blue', 'red', 'blue']])
df.index.names = ['row-1', 'row-2']
df.columns.names = ['col-1', 'col-2']
df
查看行索引
df.index
# 运行结果
MultiIndex([('a', 1),
('a', 2),
('b', 1),
('b', 2)],
names=['row-1', 'row-2'])
查看列索引
df.columns
# 运行结果
MultiIndex([('one', 'blue'),
('one', 'red'),
('two', 'blue')],
names=['col-1', 'col-2'])
查看某一索引下的内容
df.loc['a']
type(df.loc['a'])
# 运行结果
pandas.core.frame.DataFrame
索引交换及排序
df2 = df.swaplevel('row-1', 'row-2')
df2
交换索引后重新排序
df2.sort_values('row-2')
按照索引级别进行统计
df.sum(level=0)
df.sum(level=1)
索引与列的转换
df = pd.DataFrame({
'a': range(7),
'b': range(7, 0, -1),
'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'],
'd': [0, 1, 2, 0, 1, 2, 3]
})
df
将c列设置为行索引
df.set_index('c')
将c列设置为一级行索引,d列设置为二级行索引
df2 = df.set_index(['c', 'd'])
df2
将多层索引展开
df3 = df2.reset_index().sort_index('columns')
df3