Pandas之一

NumPy
pandas <<=
数据可视化

Pandas是基于NumPy数组构建的,特别是基于数组的函数和不适用for循环的数据处理,二者最大的不同是,Pandas是专门为处理表格和混杂数据设计的,而NumPy更适合处理统一的数值数组的数据。
Pandas是个比较的库了,第二版里边大约是根据ETL的方式在组织着,并且举了更多的例子,由于篇幅太大,很适用。这里将Pandas分成2篇,一篇基础,包括数据类型、索引、存储与加载,另外一篇是进阶,包括清理、转换、聚合

pandas的数据结构

Series

  • 基本属性与创建

    Series 是一维带标记的数组结构,可以存储任意类型的数据(整数,浮点数,字符串,Python 对象等等)。
    Series有2个属性,一是数据的values,它是一维的数组;二是数据的index,它代表着数据的索引

    1
    2
    3
    obj = pd.Series([4, 7, -3, 6])
    obj.values # array([4, 7, -3, 6])
    obj.index # RangeIndex(start=0, stop=4, step=1)

    创建时,可以通过index指明索引:

    1
    2
    obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
    obj2.index # Index(['d', 'b', 'a', 'c'], dtype='object')

    如果 data 是个 ndarray,那么 index 的长度必须跟 data 一致
    如果 index 为空,那么 index 会使用 [0, …, len(data) - 1]:

    除了通过列表创建,Series还可以通过字典创建。如果 data 是个 dict,如果不给定 index,那么 index 将使用 dict 的 key 排序之后的结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}

    obj3 = pd.Series(sdata)
    obj3
    # Ohio 35000
    # Oregon 16000
    # Texas 71000
    # Utah 5000

    states = ['California', 'Ohio', 'Oregon', 'Texas']
    obj4 = pd.Series(sdata, index=states)
    obj4
    # California NaN
    # Ohio 35000
    # Oregon 16000
    # Texas 71000

    Series对象本身以及index都有一个name属性,如

    1
    2
    obj4.name = 'population'
    obj4.index.name = 'state'

    Series的索引可以通过赋值的方式就地修改

    1
    obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
  • 基本使用

    Series跟NumPy的array的使用方式有些类似

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    obj2['a']   # -5

    obj2['d'] = 6

    obj2[['c','a','d']]
    # c 3
    # a -5
    # d 6

    obj2[obj2 > 0]
    # d 6
    # b 7
    # c 3

    obj2*2
    # d 12
    # b 14
    # a -10
    # c 6

    np.exp(obj2)

    'b' in obj2
    #True

    Seriesd对于缺省数据,可以通过isnull和notnull进行检查

    1
    2
    pd.isnull(obj4)
    pd.notnull(obj4)

    与np的array不同,Series进行计算时,会根据索引标签自动对齐数据,这一点类似于sql的join功能

    1
    2
    3
    4
    5
    6
    7
    obj3+obj4  

    # California NaN
    # Ohio 70000.0
    # Oregon 32000.0
    # Texas 142000.0
    # Utah NaN

DataFrame

DataFrame是Pandas的灵魂,如果把Series看成一维的,那它就是二维的,对照Series,它有3个基本属性:数据的values,数据的行索引index,数据的列索引column。可以通过frame.columns、frame.index等访问

  • 创建
    DataFrame(data, index, columns) 中的 data 可以接受很多数据类型,如Numpy数组组成的字典、2维ndarray、另外一个DataFrame

    从 ndarray 或者 list 字典中构造

    1
    2
    3
    4
    5
    data = {'state': ['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, index=['one', 'two', 'three', 'four', 'five', 'six'])

    二维数据

    1
    2
    arrData = np.random.randn(2,3)
    df = pd.DataFrame(arrData, index=['a','b'], columns=['job','position'])
  • 基本使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    frame.head()            # 对于特别大的DataFrame,head方法会取前5行

    frame['state'] # 这种取法,是取的'state'列与index
    frame.state # 同上

    frame.loc['one'] # 这种取法,取的是'one'这一行以及column
    frame.iloc[0] # 这是是通过下标进行获取的
    frame.loc['one', 'state'] # loc可以放行列2个值

    frame['debt'] = np.arange(6) # 这样是增加一个'debt'列,并赋值
    frame['eastern'] = fram.state == 'Ohio' # 增加一个'eastern'列, 当'state' 为'Ohio'是True,否则为False
    del frame['eastern'] # 删除该列

基本功能

reindex

它的作用是创建一个新对象,数据符合新的索引,若没有,则用NaN填充。对Series与DataFrame都适用。
别被它的名字所骗,它本质上是一个复制操作

1
2
3
4
5
6
7
8
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d','b','a','c'])

obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
# a -5.3
# b 7.2
# c 3.6
# d 4.5
# e NaN

对于时间序列这样的有序数据,reindex时候,可以做一些插值处理。

1
2
obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj3.reindex(range(6), method='ffill')

注意:无序数据是不能用ffill的

对于DataFrame,reindex既可以修改index,也可以修改column

1
2
3
4
frame = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])

frame2 = frame.reindex(['a', 'b', 'c', 'd'])
frame3 = frame.reindex(columns=['Texas', 'Utah', 'California'])

drop

删除指定轴上的一个或多项,它返回的是一个删除之后的新对象

1
2
frame2.drop(['a', 'b'])      # 删除,a,b两行
frame2.drop(['Texas', 'Utah'], axis=1) # 删除Texas,Utah两列

fill_value

在进行算术运算时候,如果reindx不匹配,就会出现NaN,这时候可以通过传入fill_value参数,来对NaN进行填充

1
2
3
4
5
df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))
df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))

df1 + df2
df1.add(df2, fill_value=0) # 这是,e就会有值,先对NaN填充成0,然后再计算

算术方法包括:

方法 说明
add、radd 加法
sub、rsub 减法
div、rdiv 除法
mul、rmul 乘法
pow、rpow 指数

注意:r代表着参数反转

apply与applymap

NumPy的ufuncs也适用于操作pandas对象

1
2
frame = pd.DataFrame(np.random.randn(4, 3))
np.abs(frame)

另外将函数应用到由某行或者某列所形成的一维数组上,使用apply方法

1
2
3
f = lambda x: x.max() - x.min()
frame.apply(f) # 对每列执行(沿着axis=0)
frame.apply(f, axis='columns') # 对每行执行,或者是axis=1

对多常见的数组统计功能,都被实现成了DataFrame的方法,如sum、mean,无需使用apply。

元素级的函数也可以用在DataFrame中,使用applymap方法

1
2
format = lambda x: '%.2f' % x
frame.applymap(format)

sort与rank

sort有2种:sort_index与sort_value

1
2
3
4
5
6
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, ascending=False) # 以columns来排序,降序

frame.sort_value(by='b') # 按b列的值进行排序

rank是为每组分配一个平均排名的方式

1
2
obj = pd.Series([7, -5, 6])
obj.rank() # 它给出的每个value的一种排名

汇总

与Numpy相同,Pandas也集成了一组常用的数据和统计方法。与Numpy不同的是,他们都是基于没有缺失数据的假设而创建的。

这些方法包括:

方法 说明
count 非NA值的数量
describe 汇总统计
min、max 最值
argmin、argmax 最值的索引位置
quantile 计算样本的分位数(0-1)
sum 求和
mean 平均
median 中位数
var 方差
std 标准差
skew 样本的偏度(三阶矩)
kurt 样本的峰度(四阶矩)
cumsum 累计和
cumprod 累计积
diff 一阶差分
pct_change 百分数变化
corr 相关系数
cov 协方差矩阵

数据加载与存储

与Numpy相比,pandas对数据的输入输出更看重一些,也增加了对数据库的支持
这里介绍几个常用的:

函数 说明
read_csv 从csv中读取
read_excel 从excel中读取
read_json 从json中读取
read_sql 读取SQL查询结果

read_csv

1
2
3
4
5
6
7
! cat example.csv
a,b,c,d,message
1,2,3,4,hello
5,6,7,8,world

df = pd.read_csv('example.csv') # 这时候首行被认为是column,可以通过制定header =None来取消默认
df = pd.read_csv('example.csv', header=None)

通过to_csv方法,可以将数据导出到csv文件中

1
data.to_csv('data.csv')

大文件的处理

对于很大的文件,可以只读取几行数据,通过指定nrows即可

1
df = pd.read_csv('example.csv', nrows=5)      # 只读取5行

也可以逐块读取文件,通过指定chunksize

1
2
3
4
5
6
7
chunker = pd.read_csv('example.csv', chunksize=1000)    # 这时候返回的是TextParse对象,可以迭代

tot = pd.Series([])
for piece in chunker:
tot = tot.add(piece['key'].value_counts(), fill_value=0) # value_counts就是每个value出现的count

tot =tot.sort_values()

read_json

1
2
3
4
5
6
7
!cat example.json
[{"a": 1, "b": 2, "c": 3},
{"a": 4, "b": 5, "c": 6},
{"a": 7, "b": 8, "c": 9}]

data = pd.read_json('example.json')
print(data.to_json()) # 与csv相同可以通过to_json()输出

read_excel

1
2
3
4
5
6
xlsx = pd.ExcelFile('ex1.xlsx')
data = pd.read_excel(xlsx, 'sheet1')

writer = pd.ExcelWriter('ex2.xlsx')
data.to_excel(writer, 'sheet1')
writer.save

read_sql

可以通过python读数据库的操作,将数据读取到,然后创建成DataFrame 。对这种方式不作介绍了

python sql项目SQLAlchemy可以对sql数据进行抽象,然后通过read_sql可以直接操作

1
2
3
4
import sqlalchemy as sqla
db = sqla.create_engine("sqlite://mydata.sqlite") # 这里数据库用的sqlite,其他数据库类似

data = pd.read_sql("select * from test", db)