参考资料:
一、pandas中的数据结构
主要涉及到的库有以下
import pandas as pd
from pandas import Series, DataFrame
1、Series对象
series是一个像数组一样的一维序列,并有一个index的数组
obj = pd.Series([4, 7, -5, 3])
0 4
1 7
2 -5
3 3
dtype: int64
如上所示,index和value都可以通过属性查看
# 查看value
obj.values
# 查看index
obj.index
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
d 4
b 7
a -5
c 3
dtype: int64
obj2['a']
obj2[['a', 'c', 'b']]
值得注意的是第二种索引的方式,是将一个列表作为索引,而返回的也是Series的对象
# 返回所有值大于2的元素组成的Series对象
obj[obj > 2]
# 所有的值都乘2
obj2 * 2
# 使用numpy中的函数也可以处理
import numpy as np
np.exp(obj2)
# series从结构上看,明显像是字典,返回True或False
'b' in obj2
# 也可以使用dict来创建series
dict_1 = {'a':1, 'b':2}
obj = pd.Series(dict_1)
# 传字典时调整顺序,可以借助index
index = ['b', 'a']
obj = pd.Series(dict_1, index=index)
值得注意的是,在使用index调整顺序的时候,如果index中包含字典中没有的值,那就是导致出现空值,也就是NaN
# 若元素为空则对应位置返回True
pd.isnull(obj)
# 若元素非空则对应位置返回True
pd.notnull(obj)
# 若元素为空则对应位置返回True
obj.isnull()
相加的原理是根据键,相同的键对应的值相加,若某个键只存在于一方,则得到的结果是NaN,也就是空
series的value和index都有一个name的属性,这个能和其他pandas的函数进行整合(??)
obj.name = 'values'
obj.index.name = 'index'
# obj.index [0, 1, 2, 3]
obj.index = ['a', 'b', 'c', 'd']
2、DataFrame
DataFrame表示一个长方形,并包含排好序的列,每一列都可以是不同的数值类型。
data = {'a': [1, 2, 3], 'b': [11, 12, 13], 'c': ['21', '22', '23']}
frame = pd.DataFrame(data)
a b c
0 1 11 21
1 2 12 22
2 3 13 23
dataframe也会想series一样自动生成index,而列会按顺序排好
生成DataFrame如果指定列的话,会按列指定的顺序排序
pd.DataFrame(data, columns=['c', 'b', 'a'])
c b a
如果这时输入一个不存在的列名,对应一列的值全部为空
frame.columns
Index(['a', 'b', 'c'], dtype='object')
从DataFrame单独取出一列的话,就会变成series对象
据原文所说,这两种方式的区别在于,前者可以对应任何列名,而后者必须有效,但我测试结果却是两个都会报错,只要列名是无效的话。
# 直接index的键名即可
frame.loc(1)
也可以把一个series的对象赋值过去,根据对应的index,若不存则为空。
如果列不存在的话,则会创建新的列
data = {'Nevada': {2001: 2.4, 2002: 2.9},
'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
这里内层的字典的键会变成index的键名
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
如果frame的index和column有name属性的话,也会被显示
frame.index.name = 'index'
frame.columns.name = 'columns'
# 这个会返回一个二维数组(array对象)
frame.values
3、索引对象
pandas中的索引除了保存index之外,还保存一些name的数据。
index = obj.index
index[1:]
# 但index是不可更改的,下面的操作会报错
index[1] = 'd'
# labels是一个索引对象
labels = pd.Index(np.arange(3))
obj = pd.Series([1.5, -2.5, 0], index=labels)
obj.index is labels
True
与python中的set不同的是,index允许重复的元素出现
dup_labels = pd.Index(['a', 'a', 'b', 'c'])
在这种重复便签中选择的话,会选择所有相同的标签。
二、主要功能
1、重新索引
重新索引的意思就是将一个已经有索引的对象,修改其索引
import pandas as pd
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj = obj.reindex(['a', 'b', 'c', 'd', 'e'])
如果没有对应的index的话为空
但是我感觉这没有什么意义,只是修改了索引的顺序,我原以为修改的是索引的键名,
在处理时间序列这样的数据时,我们可能会需要在reindex的时候修改值,这时可以使用method
obj = pd.Series(['bule', 'purple', 'yellow'], index=[0, 2, 4])
0 bule
2 purple
4 yellow
dtype: object
obj.reindex(range(6), method='ffill')
0 bule
1 bule
2 purple
3 purple
4 yellow
5 yellow
dtype: object
我完全不懂这个方法的作用是什么
对于DataFrame,reindex也可以修改row,columns的index。
frame.reindex(['a', 'b', 'c', 'd'])
states = ['Texas', 'Utah', 'California']
frame.reindex(column=states)
frame.loc([['a', 'b', 'c', 'd'], states])
2、按轴删除记录
obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
对于series,drop会删除指定的轴的值,并且返回一个删除后的对象
new_obj = obj.drop['c']
new_obj = obj.drop['d', 'c']
对于dataframe,index可以按照行或列来删除
# 删除行,数组中的是两个行名
data.drop(['Colorado', 'Ohio'])
# 删除列,
data.drop('two', axis=1)
data.drop(['two', 'four'], axis='columns')
这里的axis参数,不是很理解具体什么作用
当只有一个值的时候,默认为axis=0,删除的是行,设置为axis=1之后,删除的列,同理,当参数是一个数组的时候,默认是行,添加axis=‘columns’之后,就是删除列。
3、索引,选择,过滤
series中的index相当于numpy中array的index,而且除了整数,还可以使用series的index
obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
obj['b']
obj[1]
obj[2:4]
obj[['b', 'a', 'd']]
obj[[1, 3]]
obj[obj < 2]
值得注意的是,使用series的切片的时候,它是会包含尾节点的,这点在其他很多相同的情况中也要注意尾节点的问题。
# 也可以赋值
obj['b':'c'] = 5
对于DataFrame,index可以通过值或者序列,选中一个以上的列
data = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
data['two']
data[['three', 'one']]
# 还有一些比较特别的
data[:2]
data[data['three'] > 5]
# 下面的会返回一个布尔数组
data > 5
# 筛选并赋值
data[data > 5] = 0
这两个方法可以来选择行或列
# 第一个参数选择行,第二个参数选择列
data.loc['Colorado', ['two', 'three']]
# 同样的效果
data.iloc[2, [3, 0, 1]]
# 选定某一行
data.iloc[2]
data.iloc[[1, 2], [3, 0, 1]]
索引函数也能用于切片
data.loc[:'Utah', 'two']
data.iloc[:, :3][data.three > 5]
4、整数索引
新手使用整数来索引的话,总是出现一些问题,因为这与python的list和tuple的索引不太一样
ser = pd.Series(np.arange(3.))
# 接下来的会报错,注意此时的index是默认的整数型
ser[-1]
ser2 = pd.Series(np.arange(3.), index=['a', 'b', 'c'])
# 接下来的不会报错,而此时的是字符型的index
ser[-1]
为了保持连贯性,如果index中包含整数,那么选择数据的时候,为了更精确的地选择,使用loc或者ilco
# 不包括尾节点
ser[:1]
# 包括尾节点
ser.loc[:1]
# 不包括尾节点
ser.iloc[:1]
5、算术和数据对齐
1、pandas有一个很有用的特点就是,不同index的对象之间的算术运算。如果两个对象相加,但是它们的index并不相同,最终的结果中的index是两个index的合集
s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
s2 = pd.Series([2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])
s1 + s2
跟之前提到过的一样,没有对应的index的话,值会变为NaN,因此引入了很多缺失值。
在DataFrame中,数据对齐同时发生在行和列上
df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'),
index=['Ohio', 'Texas', 'Colorado'])
df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
df1 + df2
如果两个DataFrame相加,而且没有column和row,结果会全是null
df1 = pd.DataFrame({'A': [1, 2]})
df2 = pd.DataFrame({'B': [3, 4]})
df1 - df2
2、带填充值的算术方法
比方说上面的缺失值,我们希望填充0,
填充原本的值不是更好吗?填充0的话,还是会有部分值缺失的吧
df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)),
columns=list('abcd'))
df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)),
columns=list('abcde'))
df2.loc[1, 'b'] = np.nan
df1.add(df2, fill_value=0)
# 使用重新索引的时候也可以
df1.reindex(columns=df2.columns, fill_value=0)
# 等价于 1 / df1
df1.rdiv(1)
3、dataframe和series之间的操作
arr = np.arange(12.).reshape((3, 4))
arr[0]
arr - arr[0]
运算中每一行都减去了arr[0],他说这个叫“broadcasting”,
frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
series = frame.iloc[0]
frame - series
如果一个index不在dataframe的column中,或者不在series的index中,那么结果也是合集,然后部分值为空
刚才是dataframe和行series进行算术操作,如果换做列,必须使用算术方法
series = frame['d']
# 减去的操作
frame.sub(series, axis='index')
6、函数应用和映射
numpy的数组方法也可以用在pandas的对象上
frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
# 变绝对值
np.abs(frame)
另一个常用的操作时把一个用在一维数组上的函数,应用在一行或一列上,要用到dataframe中的apply函数
f = lambda x: x.max() - x.min()
frame.apply(f)
在frame中每一列,这个函数会被调用一次
frame.apply(f, axis='columns')
我已经彻底晕了,不知道axis到底是行还是列
像sum或者mean这样的数组统计方法,dataframe中已经集成了,所以没必要用apply,apply不会返回标量,只会返回一个含有多个值的series
def f(x):
return pd.Series([x.min(), x.max(),index=['min', 'max']])
frame.apply(f)
elemen-wise(点对点)的python函数也能用,比如要格式化frame中的浮点数,变为string,可以使用applymap
format = lambda x: '%.2f' % x
frame = applymap(format)
frame['e'].map[format]
7、排序
可以使用sort_index方法,返回一个新的对象
obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])
# 按照index排序
obj.sort_index()
对于dataframe,可以使用index或者其他axis来排序
frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
index=['three', 'one'],
columns=['d', 'a', 'b', 'c'])
# 按行排序
frame.sort_index()
# 按列排序
frame.sort_index(axis=1)
# 默认为升序,可以设置为降序
frame.sort_index(axis=1, ascending=False)
obj = pd.Series([4, 7, -2, 3])
obj.sort_values()
np.nan指的是缺失值,也就是NaN,也就是空。
缺失值会被排在最后
对于DataFrame,可以把一列或者多列作为sort keys
frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
# 单个列
frame.sort_values(by='b')
# 多个列
frame.sort_values(by=['a', 'b'])
多个值排序的规则跟数据库中的很相似,先排第一个参数的列,然后排第二参数的列。
rank方法可以用于series和dataframe,它会默认给每个group一个平均排名。
懂倒是懂了,但是有什么用处呢?
obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
obj.sort_values()
obj.rank()
# 也可以按照被观测到的顺序来设定
obj.rank(method='first')
# 降序
obj.rank(ascending=False, method='max')
对于dataframe可以根据行或列来计算rank
frame.rank(axis='columns')
8、有重复label的轴索引
之前的例子都是唯一值的索引,一些pandas函数(reindex)需要label是唯一的,但这不是强制的
obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
# 判断是不是唯一值
obj.index.is_unique
# 会返回重名的行
obj['a']
# 对于dataframe是同理的
frame.loc['b']
三、汇总和描述性统计
pandas有很多数学和统计方法,大部分可以归类为降维或汇总统计,可以用来从series中提取单个值(sum和mean),还有一些方法处理缺失值
这里应该是指处理数据,返回单个值,提取好像的感觉是拿出原有数据
# df: dataframe object
# 计算每一列的和
df.sum()
# 计算每一行的和
df.sum(axis='columns')
计算的时候缺失值会被除外,可以使用skipna来跳过
df.mean(axis='columns', skipna=False)
其他方法
# 返回最大值对应的index键
df.idmax()
# 按列去累加
df.cumsum()
# 不知道什么用处
df.describe()
1、相关性和协方差
假设DataFrame时股价和股票数量,用pandas-datareader包能加载,如果没有可以用install下载
2、唯一值、值计数、会员
这里介绍从一维series中提取信息的方法
obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
# 返回唯一值
uniques = obj.unique()
# 值出现的频率
obj.value_counts()
# 或者
pd.value_counts(obj.values, sort=False)
# 检查每一个元素是否在子集中
mask = obj.isin(['b', 'c'])
obj[mask]