Python-Pandas学习

pandas建造在NumPy之上,它使得以NumPy为中心的应用很容易使用。pandas数据结构主要有:Series、DataFrame。首先引入模块:

1
2
import pandas as pd
import numpy as np

Series

Series是一个类似一维数组的对象,包含:

  • values:任何NumPy的数据类型组成的数组
  • index:与数组关联的标签

可以分别的通过它的 values 和 index 属性来获取Series的数组表示和索引对象

创建

创建可以有几种方式:

  • 由数组(list/tuple)创建:
    • 不指定索引:默认索引为整数0到 N-1(N为数组长度)
    • 指定索引:index参数指定索引
  • 由dict创建:key–>index,value–>values
  • 由Series创建:指定index时,只提取原Series的index对应的值,没有的为NAN
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 不指定索引
    obj = pd.Series([4, 7, -5, 3])
    print(obj.values, obj.index, obj, sep='\n')
    # 指定索引
    obj2 = pd.Series((4, 7, -5, 3), index=['d', 'b', 'a', 'c'])
    print(obj2.values, obj2.index, obj2, sep='\n')
    # 字典创建
    sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
    obj3 = pd.Series(sdata)
    # Series创建
    states = ['California', 'Ohio', 'Oregon', 'Texas']
    obj4 = pd.Series(sdata, index=states)
    print(obj3, obj4, sep='\n')

修改

增

与dict新增属性一样

1
2
obj['hehe'] = 110
print(obj)

删

drop 方法将会返回一个新的对象并从坐标轴中删除指定的一个或多个值,inplace参数决定是否输出到原df

1
2
obj.drop('Bob', inplace=True)
print(obj)

改

分为值修改和索引更改

1
2
3
4
5
6
# 索引更改
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
print(obj)
# 值更改
obj['Bob'] = 6
print(obj)

说明:reindex()跟直接修改index属性的对比在重新索引部分会讲到

查询

  • NumPy查询,将会保持索引和值间的关联
    • 下标取数据
    • 布尔数组过滤
    • 纯量乘法
    • 使用数学函数
  • 与NumPy不同的查询,可以使用索引里的值来选择一个单一值或一个值集
    1
    2
    3
    4
    print(obj2['a', 'c'])
    print(obj2[:2])
    print(obj2[obj2 > 0], obj2 * 2, np.exp(obj2))
    print('b' in obj2, 'e' in obj2, sep='\n')

其他

算术运算:会自动对齐不同索引的数据

1
2
print(pd.isnull(obj4), obj4.isnull(), sep='\n')
print(obj3 + obj4)

name属性:Series对象本身和它的索引都有一个name 属性,它和pandas的其它一些关键功能整合在一起

1
2
3
obj4.name = 'population'
obj4.index.name = 'state'
print(obj4)

DataFrame

DataFrame类似于数据库中的表,不过DataFrame不仅仅限制于2维,可以创建多维数据表。DataFrame既有行索引,也有列索引,可以看做是Series组成的字典,每个Series看做DataFrame的一个列。

创建

由字典创建

可选参数:

  • columns:可以决定列的顺序,没有的会以NaN补充
  • index:索引值,默认值为0到N-1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
    'year': [2000, 2001, 2002, 2001, 2002],
    'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
    frame = pd.DataFrame(data)
    print(frame)
    frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop'])
    print(frame2)
    frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'])
    print(frame2)
    frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five'])
    print(frame2)

numpy数组创建

等长的numpy数组

1
2
frame = pd.DataFrame(np.arange(16).reshape((4, 4)), index=['a', 'b', 'c', 'd'], columns=['one', 'two', 'three', 'four'])
print(frame)

嵌套字典的字典

它的外部键会被解释为列索引,内部键会被解释为行索引

1
2
3
4
pop = {'Nevada': {2001: 2.4, 2002: 2.9},
'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
frame3 = pd.DataFrame(pop)
print(frame3)

其他

由其他df创建:

1
2
3
pdata = {'Ohio': frame3['Ohio'][:-1],
'Nevada': frame3['Nevada'][:2]}
print(pd.DataFrame(pdata))

可能的传递到DataFrame的构造器:

类型 说明
二维ndarray 一个数据矩阵,有可选的行标和列标
数组,列表或元组的字典 每一个序列成为DataFrame中的一列。所有的序列必须有相同的长度。
NumPy的结构/记录数组 和“数组字典”一样处理
Series的字典 每一个值成为一列。如果没有明显的传递索引,将结合每一个Series的索引来形成结果的行索引。
字典的字典 每一个内部的字典成为一列。和“Series的字典”一样,结合键值来形成行索引。
字典或Series的列表 每一项成为DataFrame中的一列。结合字典键或Series索引形成DataFrame的列标。
列表或元组的列表 和“二维ndarray”一样处理
另一个DataFrame DataFrame的索引将被使用,除非传递另外一个
NumPy伪装数组(MaskedArray) 除了蒙蔽值在DataFrame中成为NA/丢失数据之外,其它的和“二维ndarray”一样

修改

增

增加新的一列,跟dict操作一样

1
2
frame2['eastern'] = frame2.state == 'Ohio'
print(frame2)

删

del:删除一列,跟dict一样
dorp():删除行或者列

  • axis:删除轴,跟numpy一样,axis=0表示行,axis=1表示列
  • inplace:是否替换原函数
    1
    2
    3
    4
    del frame2['eastern']
    print(frame2.columns, frame2, sep='\n')
    print(frame2.drop('one', axis=0))
    print(frame2.drop(['year', 'debt'], axis=1))

改

列可以通过赋值来修改

1
2
3
4
frame2['debt'] = 16.5
print(frame2)
frame2['debt'] = np.arange(5.)
print(frame2)

通过列表或数组给一列赋值时,所赋的值的长度必须和DataFrame的长度相匹配。

1
2
3
val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
print(frame2)

选择、查询

查看数据

  • head()、tail(): 查看顶部和底部
  • index、column、values: 显示索引,列,和底层numpy数据
  • describe(): 描述显示数据快速统计摘要,包括count、mean、std、min、25%、50%、75%、max
  • 转置数据:T
  • 按轴排序,按值排序
    1
    2
    3
    4
    5
    6
    dates = pd.date_range('20130101', periods=6)
    df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))
    print(df, df.head(), df.tail(1),
    df.index, df.columns, df.values,
    df.describe(), df.T,
    df.sort_index(axis=1, ascending=False), df.sort(columns='B'), sep='\n-------\n')

选择数据

选择单列:通过字典记法或属性来检索。建议使用列标签[ ]选取方式,‘.’的写法容易与其他预留关键字产生冲突。返回的Series包含和DataFrame相同的索引,并且继承name 属性。

1
print(df['A'], df.A, sep='\n------\n')

选择片段:使用[]

1
print(df[0:3], df['20130102':'20130104'], sep='\n------\n')

使用标签选择

loc(行标签,列标签):

  • 行标签和列标签都可以为切片或者单个值
  • 两者都为单个值时为选择单个数据,等价于at
    1
    2
    3
    print(df.loc[dates[0]], df.loc[:, ['A', 'B']], df.loc['20130102':'20130104', ['A', 'B']], df.loc['20130102', ['A', 'B']], sep='\n------\n')
    print(df.loc[dates[0], 'A'], df.at[dates[0], 'A'], sep='\n------\n')
按位置选择

iloc(行位置,列位置):

  • 行位置和列位置都可以为切片或者单个值
  • 两者都为单个值时为选择单个数据,等价于iat
    1
    2
    3
    4
    # 传递整数选择位置
    print(df.iloc[3], df.iloc[3:5, 0:2], df.iloc[[1, 2, 4], [0, 2]], df.iloc[1:3, :], df.iloc[:, 1:3], sep='\n------\n')
    # 显式获取一个值(两者等价)
    print(df.iloc[1, 1], df.iat[1, 1], sep='\n------\n')
布尔索引

跟Series基本一样

1
print(df[df.A > 0], df[df > 0], sep='\n-------\n')

索引对象

pandas的索引对象用来保存坐标轴标签和其它元数据(如坐标轴名或名称)。

索引对象是不可变的,从上文Series部分可以看出可以通过整个替换index对象。

1
2
3
4
5
6
obj = pd.Series([4, 7, -5, 3])
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
print(obj)
# 索引对象不可变
# index = obj.index
# index[1] = 'hehe'

类型

pandas中的主要索引对象:

分类 解释
Index 最通用的索引对象,使用Python对象的NumPy数组来表示坐标轴标签。
Int64Index 对整形值的特化索引。
MultiIndex “分层”索引对象,表示单个轴的多层次的索引。可以被认为是类似的元组的数组。
DatetimeIndex 存储纳秒时间戳(使用NumPy的datetime64 dtyppe来表示)。
PeriodIndex 对周期数据(时间间隔的)的特化索引。

属性

除了类似于阵列,索引也有类似固定大小集合一样的功能

1
2
print('Ohio' in frame3.columns)
print(2003 in frame3.index)

每个索引都有许多关于集合逻辑的方法和属性:

索引方法和属性 作用
append 链接额外的索引对象,产生一个新的索引
diff 计算索引的差集
intersection 计算交集
union 计算并集
isin 计算出一个布尔数组表示每一个值是否包含在所传递的集合里
delete 计算删除位置i的元素的索引
drop 计算删除所传递的值后的索引
insert 计算在位置i插入元素后的索引
is_monotonic 返回True,如果每一个元素都比它前面的元素大或相等
is_unique 返回True,如果索引没有重复的值
unique 计算索引的唯一值数组

重新索引

reindex:根据新的index来进行排序,使得它符合新的索引,如果那个索引的值不存在就引入缺失数据值。

没有的值填充可选配置:

  • fill_value: 填充单个值,例如填0
  • method: 对时间序列内插或填充
    • ffill或pad: 前向(或进位)填充,例如ffill跟前一位相同
    • bfill或backfill: 后向(或进位)填充
      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'], fill_value=0)
      obj.index = ['a', 'b', 'c', 'd']
      print(obj, obj2, sep='\n------\n')
      obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
      obj4 = obj3.reindex(range(6), method='ffill')
      print(obj4)

reindex与修改index的结果对比:obj vs obj2

1
2
3
4
5
6
7
8
9
10
11
12
13
# 直接通过修改index属性只是把index换掉,并且长度必须一样,没有填NaN一说
a 4.5
b 7.2
c -5.3
d 3.6
dtype: float64
# reindex会根据新的index对以前的进行排序。
a -5.3
b 7.2
c 3.6
d 4.5
e 0
dtype: float64

DataFrame重新索引

reindex 可以改变(行)索引,列或两者:

  • columns:列重新索引
  • index: 行重新索引
  • 只传入一个序列:相当于index,行重新索引
    1
    2
    3
    4
    5
    6
    frame = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'],
    columns=['Ohio', 'Texas', 'California'])
    frame2 = frame.reindex(['a', 'b', 'c', 'd'])
    states = ['Texas', 'Utah', 'California']
    frame3 = frame.reindex(columns=states)
    print(frame, frame2, frame3, sep='\n------\n')

插值只在行侧(0坐标轴)进行

1
frame.reindex(index=['a', 'b', 'c', 'd'], method='ffill', columns=states)

其他

丢失的数据

pandas主要使用np.nan替换丢失的数据. 默认情况下它并不包含在计算中:

  • dropna():删除丢失数据的行,how=’any’表示删除任何
  • fillna():填充丢失数据
  • isnull():获取值是否nan的布尔标记
    1
    2
    3
    4
    df2 = df[df > 0]
    print(df2.dropna(how='any'))
    print(df2.fillna(value=0))
    print(df2.isnull())

运算

算术运算

基本的加减乘除运算:

1
2
df1 + df2
df1 * df2

二元运算

类似于numpy的运算

  • 广播机制
  • 缺失数据的计算
  • 通过axis指定轴

Apply

在数据上使用函数

1
2
print(df.apply(np.cumsum))
print(df.apply(lambda x: x.max() - x.min()))

字符串方法

具体参见官方文档:Working with Text Data

1
2
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
print(s.str.lower())

Merge

pandas提供各种工具以简便合并序列,数据桢,和组合对象, 在连接/合并类型操作中使用多种类型索引和相关数学函数,具体参见官方文档

concat

把pandas对象连接到一起

1
2
3
4
df = pd.DataFrame(np.random.randn(10, 4))
print(df[:3], df[3:7], df[7:], sep='\n-------\n')
pieces = [df[:3], df[3:7], df[7:]]
print(pd.concat(pieces))

merge

SQL样式合并:

  • on:merge的列
  • how:选择左连接、右连接、全连接,默认内连接
  • suffixes:重名列后缀
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
    'key2': ['K0', 'K1', 'K0', 'K1'],
    'A': ['A0', 'A1', 'A2', 'A3'],
    'B': ['B0', 'B1', 'B2', 'B3']})
    right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4'],
    'key2': ['K0', 'K0', 'K0', 'K0', 'K0'],
    'C': ['C0', 'C1', 'C2', 'C3', 'C4'],
    'D': ['D0', 'D1', 'D2', 'D3', 'D4']})
    df3 = pd.merge(left, right, on='key', suffixes=('_left', '_right'))
    df4 = pd.merge(left, right, on=['key', 'key2'])
    df5 = pd.merge(left, right, on=['key', 'key2'], how='left')
    df6 = pd.merge(left, right, on=['key', 'key2'], how='right')
    df7 = pd.merge(left, right, on=['key', 'key2'], how='outer')
    print(df3, df4, df5, df6, df7, sep='\n--------\n')

append

添加行到数据增,下例中取第4行,append到df最后一行

1
2
3
df = pd.DataFrame(np.random.randn(8, 4), columns=['A', 'B', 'C', 'D'])
s = df.iloc[3]
print(df.append(s, ignore_index=True))

Group by

对于“group by”指的是以下一个或多个处理:

  • 将数据按某些标准分割为不同的组
  • 在每个独立组上应用函数
  • 组合结果为一个数据结构
    1
    2
    3
    4
    5
    df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'],
    'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
    'C': np.random.randn(8),
    'D': np.random.randn(8)})
    print(df, df.groupby('A').sum(), df.groupby(['A', 'B']).sum(), sep='\n------\n')

Pivot talbe(数据透视表)

我们可以从此数据非常容易的产生数据透视表:

  • values: 聚合列
  • index: group列
  • columns: 新df的索引列
  • aggfunc:聚合函数
    1
    2
    3
    4
    5
    6
    7
    df = pd.DataFrame({'A': ['one', 'one', 'two', 'three'] * 3,
    'B': ['A', 'B', 'C'] * 4,
    'C': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
    'D': np.random.randn(12),
    'E': np.random.randn(12)})
    df_pivot = pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'])
    print(df, df_pivot, sep='\n-----pivot-----\n')

参考

Python for Data Analysis
【pandas】[1] Series 入门(创建和增删改查)
【pandas】[2] DataFrame 基础,创建DataFrame和增删改查基本操作(1)
十分钟搞定pandas
官方文档:Indexing and Selecting Data

文章目录
  1. 1. Series
    1. 1.1. 创建
    2. 1.2. 修改
      1. 1.2.1. 增
      2. 1.2.2. 删
      3. 1.2.3. 改
    3. 1.3. 查询
    4. 1.4. 其他
  2. 2. DataFrame
    1. 2.1. 创建
      1. 2.1.1. 由字典创建
      2. 2.1.2. numpy数组创建
      3. 2.1.3. 嵌套字典的字典
      4. 2.1.4. 其他
    2. 2.2. 修改
      1. 2.2.1. 增
      2. 2.2.2. 删
      3. 2.2.3. 改
    3. 2.3. 选择、查询
      1. 2.3.1. 查看数据
      2. 2.3.2. 选择数据
        1. 2.3.2.1. 使用标签选择
        2. 2.3.2.2. 按位置选择
        3. 2.3.2.3. 布尔索引
  3. 3. 索引对象
    1. 3.1. 类型
    2. 3.2. 属性
    3. 3.3. 重新索引
      1. 3.3.1. DataFrame重新索引
  4. 4. 其他
    1. 4.1. 丢失的数据
    2. 4.2. 运算
      1. 4.2.1. 算术运算
      2. 4.2.2. 二元运算
      3. 4.2.3. Apply
      4. 4.2.4. 字符串方法
    3. 4.3. Merge
      1. 4.3.1. concat
      2. 4.3.2. merge
      3. 4.3.3. append
    4. 4.4. Group by
    5. 4.5. Pivot talbe(数据透视表)
  5. 5. 参考
|