3.机器学习—数据科学包3.3pandas操作

pandas操作

一.pandas索引

1.Series索引index

  1. 更改索引名
    在这里插入图片描述

2.DateFrame行索引index和列索引columns

在这里插入图片描述
更改行索引index和列索引columns的名

3.pandas预置索引的类

  1. 查询pandas预置索引的类
    在这里插入图片描述

4.重复索引

4.1重复索引定义

  1. 索引值有重复的项
    在这里插入图片描述
  2. 判断是否有重复索引
s = pd.Series(np.arange(6),index=list('abcbda'))
s['a']
s['c']
# s的索引是否是唯一值
s.index,is_unique
# s的唯一值索引
s.index.unique()

在这里插入图片描述

4.2重复索引处理groupby()

对重复索引的数据有一些处理,比如要对重复索引数据进行清洗,清洗方法跟业务需求关联,有时候只需要对重复的索引保留第一个,有时候要将重复索引的两个值相加起来,有时候要将重复索引的值求平均值。

# 用groupby()先将数据分组,再用函数处理
s.groupby(s.index).sum() #用s.index分组,再对分组的值求和

5.多级索引pd.MultiIndex

多级索引可以将更高维度的数据用二维数据来表示

比如股票数据,一级行索引用日期,二级行索引用不同股票代码,列索引是开盘价,收盘价,成交量数据。这样就把一个三维数据用二维来表达。可以将不同的几个股票放到同一个时间维度里面来考察。

5.1Series多级索引

5.1.1.新建多级索引
# 用列表生成多级索引
# 生成两个分别包含6个元素的对应列表,将两个对应列表解包,生成6对元组。
a = [['a','a','a','b','b','c','c'],[1,2,3,1,2,2,3]]
# zip函数将这两个列表组装起来。两两组合,生成6个元组。
t = list(zip(*a)) 
t
# 列表包含元组,用来创建多级索引。
# 后面是给索引赋予名字,第一级索引是level,第二级索引是level2
index = pd.MultiIndex.from_tuples(t,names=['level1','level2'])
index
# 创建出来MultiIndex对象
# 用这个对象来创建DataFrame或Series
s = pd.Series(np.random.randn(7),index=index)

在这里插入图片描述

5.2.2.选取元素
# 用第一级索引选取
s['b'] #选出level2为索引的Series
s['b':'c'] 
s[['a','c']]
# 用第二级索引选取
s[:2]

在这里插入图片描述

5.2 DataFrame多级索引

5.2.1新建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']]) 
# index是4个元素。即为四行。columns是3个元素,即为3列。np.random.randint(1,10,(4,3)即为生成4*3的array。
df.index.names = ['row-1','row-2'] 
df.columns.names = ['col-1','col-2']
df

在这里插入图片描述

5.2.2选取元素
df.loc['a'] #选取第一级索引
type(df.loc['a'])
df.loc['a',1] #选取第二级索引
type(df.loc['a',1])
df.loc['a',1].index 

在这里插入图片描述

5.2.3索引交换
df2 = df.swaplevel('row-1', 'row-2') #swap,交换调换交易代替
df2

在这里插入图片描述

5.2.4索引排序
df2.sort_index(0) #默认按照行索引排序。0表示第一层
df2.sort_index(1) #1表示第二层

在这里插入图片描述

5.2.5统计索引
df
df.sum(level=0) #计算第一层
df.sum(level=1) #计算第二层

在这里插入图片描述

5.2.6索引 index和列columns的转换

通常情况下,从外面的data文件中读取出来的dataframe,都是单行,多列的,不便于统计。

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
df.set_index('c') 
# 转换为多级索引
df2 = df.set_index(['c', 'd'])
df2
# 重新将多级索引转换为平面的一级索引
df3 = df2.reset_index()
# 发现df3和原来的df相比,列的顺序发生变化,要将列重新排序
df3 = df2.reset_index().sort_index('columns') 
df3
(df3 == df)

在这里插入图片描述
在这里插入图片描述

二.分组计算

1.原理

在这里插入图片描述

2.对 Series 进行分组

df = pd.DataFrame({'key1': ['a', 'a', 'b', 'b', 'a'],
                  'key2': ['one', 'two', 'one', 'two', 'one'],
                  'data1': np.random.randint(1, 10, 5),
                  'data2': np.random.randint(1, 10, 5)})
df
# 对 Series 进行分组,通过索引对齐关联起来
grouped = df['data1'].groupby(df['key1'])
grouped.mean()
df['data1'].groupby([df['key1'], df['key2']]).mean()

在这里插入图片描述
在这里插入图片描述

3.对Dataframe进行分组

3.1按行分组

3.1.1分组groupby
df.groupby('key1').mean() 
means = df.groupby(['key1', 'key2']).mean()['data1'] #指定两个分组依据,生成多层索引的分组结果
means
means.unstack() #unstack取消堆叠。unstack()转换为dataframe,有行索引和列索引
df.groupby(['key1', 'key2'])['data1'].mean()

在这里插入图片描述

3.1.2groupby()支持迭代
for name,group in df.groupby('key1'):
    print (name)
    print (group)
# 根据key1分组可分为两个分组,a和b。可以直接迭代groupby().
# 由于groupby()支持迭代器协议,可以将其转换为列表/字典
dict(list(df.groupby('key1')))
# 这个字典的元素
dict(list(df.groupby('key1')))['a']

在这里插入图片描述
在这里插入图片描述

3.2按列分组

# 查看每列的数据类型
df.dtypes
# 按列分组,按照数据类型不同分组,object和int32
grouped = df.groupby(df.dtypes, axis=1)
#将其转化为字典
dict(list(grouped))
#分组计算
df.groupby(df.dtypes, axis=1).sum() # object进行字符串加法

在这里插入图片描述

3.2通过字典进行分组

df = pd.DataFrame(np.random.randint(1, 10, (5, 5)), 
                  columns=['a', 'b', 'c', 'd', 'e'], 
                  index=['Alice', 'Bob', 'Candy', 'Dark', 'Emily'])
df
# 赋值为非数字,观察对非数字的处理
df.iloc[1, 1:3] = np.NaN
df
# 新建映射字典
mapping = {'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'orange', 'e': 'blue'}
# 新建字典,用字典映射分组
grouped = df.groupby(mapping, axis=1) #映射是根据列作的,所以用列分组
# 分组计算
grouped.sum()
grouped.count()
grouped.size()

在这里插入图片描述
在这里插入图片描述

3.3通过函数分组

当函数作为分组依据时,数据表里的每个索引(可以是行索引,也可以是列索引)都会调用一次函数,函数的返回值作为分组的索引,即相同的返回值分在同一组。
df = pd.DataFrame(np.random.randint(1, 10, (5, 5)), 
                  columns=['a', 'b', 'c', 'd', 'e'], 
                  index=['Alice', 'Bob', 'Candy', 'Dark', 'Emily'])
df
# 定义函数
def _dummy_group(idx): #函数的参数就是分组时要计算的分组的名字
    print(idx) #打出索引名
    return idx #返回索引名字
df.groupby(_dummy_group)
df.groupby(_dummy_group).size()
grouped = df.groupby(_dummy_group)
grouped.sum()
grouped.size()
grouped.count()

# 重新定义函数
def _dummy_group(idx): #
    print(idx)
    return len(idx)
df.groupby(_dummy_group,axis=1)
grouped = df.groupby(len)
grouped.sum()
grouped.size()
grouped.count()

# 可以直接按照长度len()来分组
df.groupby(len).size()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3多级索引数据根据索引级别来分组

columns = pd.MultiIndex.from_arrays([['China', 'USA', 'China', 'USA', 'China'],
                                     ['A', 'A', 'B', 'C', 'B']], names=['country', 'index'])
df = pd.DataFrame(np.random.randint(1, 10, (5, 5)), columns=columns)
df
# columns的countyy索引分组
df.groupby(level='country', axis=1).count() #必须指定axis=1按列分组,否则默认按行分组。但是行中无country参数
df.groupby(level='country', axis=1).sum()
# columns的index索引分组
df.groupby(level='index', axis=1).count()

在这里插入图片描述
在这里插入图片描述

三.聚合统计

在这里插入图片描述
分组运算,先根据一定规则拆分后的数据,然后对数据进行聚合运算,如前面见到的 mean(), sum() 等就是聚合的例子。聚合时,拆分后的第一个索引指定的数据都会依次传给聚合函数进行运算。最后再把运算结果合并起来,生成最终结果。
聚合函数除了内置的 sum(), min(), max(), mean() 等等之外,还可以自定义聚合函数。自定义聚合函数时,使用 agg() 或 aggregate() 函数。

1.数据聚合

1.1内置聚合函数

# 用字典生成DataFrame
df = pd.DataFrame({'key1': ['a', 'a', 'b', 'b', 'a'],
                  'key2': ['one', 'two', 'one', 'two', 'one'],
                  'data1': np.random.randint(1, 10, 5),
                  'data2': np.random.randint(1, 10, 5)})
df
df['data1'].groupby(df['key1']).sum()
# pandas内置聚合函数
sum(),mean(),min(),max(),describe()

1.2自定义聚合函数agg()

# 自定义函数。聚合函数中的参数就是逐个索引所对应的记录
def peak_verbose(s):
    print type(s)
    return s.max() - s.min()

def peak(s):
    return s.max() - s.min()

# 分组
grouped = df.groupby('key1')
# 应用自定义函数
grouped.agg(peak_verbose)

在这里插入图片描述

1.3应用多个聚合函数

# 多个聚合函数一起计算。内置函数用字符串,自定义函数就用函数名
grouped['data1', 'data2'].agg(['mean', 'std', peak])
# 给聚合后的列取名,传元组
grouped['data1'].agg([('agerage', 'mean'), ('max-range', peak)])

在这里插入图片描述

1.4给不同的列应用不同的聚合函数

使用 dict 作为参数来实现

d = {'data1': ['mean', peak, 'max', 'min'],
     'data2': 'sum'}
grouped.agg(d)

在这里插入图片描述

1.4重置索引

将key1作为dataframe中的一个column列,而不是index行索引。reset_index()

grouped.agg(d).reset_index()
# 在作聚合运算时就设置好参数,as_index=False,就不会默认把分组时的key1作为index行索引。
df.groupby('key1', as_index=False).agg(d)

在这里插入图片描述

2.分组运算和转换

新建dataframe

df = pd.DataFrame({'key1': ['a', 'a', 'b', 'b', 'a'],
                  'key2': ['one', 'two', 'one', 'two', 'one'],
                  'data1': np.random.randint(1, 10, 5),
                  'data2': np.random.randint(1, 10, 5)})
df

在这里插入图片描述

2.1分组数据变换transform

k1_mean = df.groupby('key1').mean()
k1_mean
k1_mean = df.groupby('key1').mean().add_prefix('mean_') #prefix,前缀,加前缀
k1_mean 
# merge()函数将两个表合并起来。left_on是进行y连接,
pd.merge(df, k1_mean, left_on='key1', right_index=True)

在这里插入图片描述

  1. 使用 transform 简化处理
# transform()函数将数据转换为和元数据一样的dataframe,再将列名重命名
k1_mean = df.groupby('key1').transform(np.mean).add_prefix('mean_')
k1_mean
# 直接往df中新添加两个列,不用merge()函数
df[k1_mean.columns] = k1_mean
df

在这里插入图片描述

  1. 举例说明transform()函数
df = pd.DataFrame(np.random.randint(1, 10, (5, 5)), 
                  columns=['a', 'b', 'c', 'd', 'e'], 
                  index=['Alice', 'Bob', 'Candy', 'Dark', 'Emily'])
df
# 距平化
def demean(s):
    return s - s.mean()

key = ['one', 'one', 'two', 'one', 'two']
demeaned = df.groupby(key).transform(demean)
demeaned
df.groupby(key).mean()
demeaned.groupby(key).mean()

在这里插入图片描述

2.2apply函数

我们介绍过 DataFrame 的 apply 函数是逐行或逐列来处理数据。GroupBy 的 apply 函数对每个分组进行计算。

df = pd.DataFrame({'key1': ['a', 'a', 'b', 'b', 'a', 'a', 'a', 'b', 'b', 'a'],
                  'key2': ['one', 'two', 'one', 'two', 'one', 'one', 'two', 'one', 'two', 'one'],
                  'data1': np.random.randint(1, 10, 10),
                  'data2': np.random.randint(1, 10, 10)})
df
# 根据 column 排序,输出其最大的 n 行数据。排序是从1开始。索引是从0开始。
def top(df, n=2, column='data1'): #参数,给定了默认值
    return df.sort_values(by=column, ascending=False)[:n]
#对比下面函数
#def top(df, n=2, column='data1'):
#   return df.sort_values(by=column, ascending=False) #此处没有定义显示几行
#top(df, n=5)
# 调用top()函数
top(df, n=5)
# 要先分组,再计算。不能再用top()函数调用。
# 使用apply()调用top函数
df.groupby('key1').apply(top)
# 用apply()调用top函数,且传递top()函数中的参数
df.groupby('key1').apply(top, n=3, column='data2')
# 分组后计算,top(),每一组输出规定的几行,因而最后输出n*2行
# 禁用分组键,即不出现分组键
df.groupby('key1', group_keys=False).apply(top)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3apply 应用示例:用不同的分组平均值填充空缺数据

states = ['Ohio', 'New York', 'Vermont', 'Florida',
          'Oregon', 'Nevada', 'California', 'Idaho']
group_key = ['East'] * 4 + ['West'] * 4
data = pd.Series(np.random.randn(8), index=states)
data[['Vermont', 'Nevada', 'Idaho']] = np.nan
data
# 填充Series中的空值。东部州用东部平均值填充,西部州用西部平均值填充。
data.groupby(group_key).mean()
fill_mean = lambda g: g.fillna(g.mean())
  
data.groupby(group_key).apply(fill_mean)
#或者
data.groupby(group_key).apply(lambda g: g.fillna(g.mean()))

在这里插入图片描述
在这里插入图片描述

四.数据导入与导出/数据IO

在这里插入图片描述
数据IO:即可从磁盘中读入数据,也可以将数据保存到磁盘上。

实际工程中的操作步骤:通过爬虫爬取一些数据,对爬取的数据进行解析和清洗,之后将数据保存为csv格式文件,这个文件可能很大,pandas就从这个文件中读取数据出来,进行分析。

pandas在读入数据时会作一些操作
第一,将一个或多个列读出来,构成一个DataFrame,其中包括索引和列名。列名可以从文件中读取,也可以指定。
第二,类型推断和数据转换:包括用户自定义的转换以及缺失值标记。比如说,遇到数字会自动将之转换成int或float,字符串就是str。
第三,日期解析。 数据中包含一些日期,可以将其解析为python中timerange数据类型,且pandas中有其自己定义的数据类型。
第四,迭代:针对大文件进行逐块迭代。这个是Pandas和Python原生的csv库的最大区别。 数据很大,不可能将所有数据都读出来,用迭代,即文件一次读一部分,结合python的迭代或python的生成器算法对python大文件进行处理。
第五,不规整数据问题:跳过一些行,或注释等等。

1.索引及列名

1.1规则分隔符情况

import pandas as pd
import numpy as np

%more ex1.csv #magic命令查看内容
df = pd.read_csv('ex1.csv')
df
df = pd.read_csv('data/ex1.csv', sep=',')
df

#列名缺失
pd.read_csv('data/ex2.csv') #直接读,会把第一行数据当作列名称
pd.read_csv('data/ex2.csv', header=None) # header=None,会自动分配整数作为列名称
#指定列名
pd.read_csv('data/ex2.csv', header=None, names=['a', 'b', 'c', 'd', 'msg']) #没有指定index行索引,自动分配整数作为index
# 指定行索引
pd.read_csv('data/ex2.csv', header=None, names=['a', 'b', 'c', 'd', 'msg'], index_col='msg')
#多层行索引
pd.read_csv('data/ex2.csv', header=None, names=['a', 'b', 'c', 'd', 'msg'], index_col=['msg', 'a'])

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2不规则分隔符情况-正则表达式

直接读取,可以看到不能合理解析数据
在这里插入图片描述
参考python标准文档re模块,详细介绍了正则表达式

# 正则表达式
pd.read_csv('data/ex3.csv', sep='\s+') #因为原文件中字符间的空格可能是一个也可能是多个,\s表示空格,+表示1到多个。
# pd.read_csv('data/ex3.csv')
#这里,数据列标签有三个,数据有4列,pandas会默认将第一列当作index。所以这里没有分配整数作为表的index,而是将数据第一列作为index

在这里插入图片描述

2.缺失值处理

%more data/ex5.csv
pd.read_csv('data/ex5.csv') #自动将空缺部分处理为NaN.将NA作为NaN,而不是字符串。
#缺失值可以指定。列表中的都指定为缺失值
pd.read_csv('data/ex5.csv', na_values=['NA', 'NULL', 'foo']) 
#针对每一列指定不同的缺失值。用字典形式
pd.read_csv('data/ex5.csv', na_values={'message': ['foo', 'NA'], 'something': ['two']})

在这里插入图片描述

3.逐块处理数据

在这里插入图片描述
ex6.csv数据大。
要统计最后一列,key下面的元素出现的次数,然后将出现次数最多的前十个打印出来。
一种实现方法是用pandas将整个文件都读出来,然后用value_count()函数统计出来,再去排序。但是如果数据很大,就不能一次读取出来,就要用到逐快读取数据。

#老式办法,一次性读取
s=pd.read_csv('data/ex6.csv')
s.head()
# value_counts()统计出现次数
b=s['key'].value_counts()
b.head()
#或先分组,再计算每个分组的大小,默认不排序,还需排序。
a=s.groupby('key').size().sort_values(ascending=False)
a.head()

##逐快读取数据。
#先读取前10行
pd.read_csv('data/ex6.csv', nrows=10) #nrows=10,先读10行,看下数据结构
# 指定chunksize,一次读取多少行,先读取1000行。
tr = pd.read_csv('data/ex6.csv', chunksize=1000)
# 返回结果是<pandas.io.parsers.TextFileReader at 0x197f963c400>,TextFileReader是解析器,支持迭代。可用for循环。这个tr整体不是pndas函数可操作对象,因而必须遍历出来。
# 遍历出来tr中的值
key_count = pd.Series([]) 
for pieces in tr:
    key_count = key_count.add(pieces['key'].value_counts(), fill_value=0)
key_count = key_count.sort_values(ascending=False) #pd.Series默认乱序,所以还需排序
key_count[:10]

chunksize,块大小,块尺寸
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.保存数据到磁盘df.to_csv

#读取数据
df = pd.read_csv('data/ex5.csv')
df
#保存数据到磁盘。默认情况下将索引值也写入文件,文件中会多出来一些额外的值。
df.to_csv('data/ex5_out.csv')
%more data/ex5_out.csv
# 验证上面新保存的数据
df = pd.read_csv('data/ex5_out.csv')
df
#保存时不写索引。默认情况下会将索引值也写入data文件,因而data文件会多出来一行/一列值
df = pd.read_csv('data/ex5.csv')
df.to_csv('data/ex5_out.csv', index=False)
%more data/ex5_out.csv
#保存时不写索引
df = pd.read_csv('data/ex5.csv')
df.to_csv('data/ex5_out.csv', index=False, header=None)
%more data/ex5_out.csv
#保存时指定分隔符
%more data/ex5_out.csv
# 保存时只写出一部分列
df = pd.read_csv('data/ex5.csv')
df.to_csv('data/ex5_out.csv', index=False, columns=['a', 'b', 'message'])
%more data/ex5_out.csv

5.二进制数据

二进制的优点是容量小,读取速度快。缺点是可能在不同版本间不兼容。比如 Pandas 版本升级后,早期版本保存的二进制数据可能无法正确地读出来。

  1. 用pickle包实现
  2. HDF5: HDF5是个C语言实现的库,可以高效地读取磁盘上的二进制存储的科学数据
  3. Excel文件: pd.read_excel/pd.ExcelFile/pd.ExcelWriter
  4. JSON: 通过 json 模块转换为字典,再转换为 DataFrame
  5. SQL 数据库:通过 pd.io.sql 模块来从数据库读取数据
  6. NoSQL (MongoDB) 数据库:需要结合相应的数据库模块,如 pymongo 。再通过游标把数据读出来,转换为 DataFrame
    这些具体可以参阅pandas官方文档

用pickle举例说明,pd.to_pickle()

#读取文件
df = pd.read_csv('data/ex1.csv')
df
#将读取出来的数据写入data/ex1_pickle.bin
pd.to_pickle(df, 'data/ex1_pickle.bin')
%ls data
#读取data/ex1_pickle.bin
pd.read_pickle('data/ex1_pickle.bin')
# 读取写入一次性操作
pd.to_pickle(pd.read_csv('data/ex6.csv'), 'data/ex6_pickle.bin')
#%ls data

五.时间序列

在这里插入图片描述
时间日期
stamp,邮票;印记;标志。interval,间隔;间距;幕间休息

时间戳 tiimestamp:固定的时刻 -> pd.Timestamp
固定时期 period:比如 20163月份,再如2015年销售额 -> pd.Period
时间间隔 interval:由起始时间和结束时间来表示,固定时期是时间间隔的一个特殊

时间日期在 Pandas 里的作用

分析金融数据,如股票交易数据
分析服务器日志

1.Python datetime模块

1.1 时间datetime

python 标准库里提供了时间日期的处理。这个是时间日期的基础
timedelta,时间间隔,日期时间间隔对象

from datetime import datetime
from datetime import timedelta

now = datetime.now()
now
now.year, now.month, now.day

在这里插入图片描述

1.2时间差timedelta

date1 = datetime(2016, 3, 20)
date2 = datetime(2016, 3, 16)
delta = date1 - date2
delta
delta.days
delta.total_seconds()
date2 + delta
date2 + timedelta(4.5)

在这里插入图片描述

1.3字符串和 datetime 转换

关于 datetime 格式定义,可以参阅 python 官方文档
在这里插入图片描述

date = datetime(2016, 3, 20, 8, 30)
date
str(date)
date.strftime('%Y-%m-%d %H:%M:%S') #date.strftime格式化样式,后面()中为想要给定的样式
datetime.strptime('2016-03-20 09:30', '%Y-%m-%d %H:%M') #再把时间日期格式转换为python内部格式

2.Pandas 里的时间序列

Pandas 里使用 Timestamp 来表达时间

dates = [datetime(2016, 3, 1), datetime(2016, 3, 2), datetime(2016, 3, 3), datetime(2016, 3, 4)] #时间列表
s = pd.Series(np.random.randn(4), index=dates)
s
type(s.index) #DatetimeIndex数据结构
type(s.index[0]) #Timestamp数据结构

在这里插入图片描述
pandas中提供了更方便的生成时间序列的方法,生成时间戳的时间序列的方法就是pd.date_range

3.日期范围pd.date_range

3.1生成日期范围

pd.date_range('20160320', '20160331') #接收开始时间到结束时间
pd.date_range(start='20160320', periods=10) #开始时间和生成个数
## 规则化时间戳
pd.date_range(start='2016-03-20 16:23:32', periods=10)
pd.date_range(start='2016-03-20 16:23:32', periods=10, normalize=True) #

在这里插入图片描述

3.2生成的时间频率设定,默认是D天

## 星期
pd.date_range(start='20160320', periods=10, freq='W')
# 月
pd.date_range(start='20160320', periods=10, freq='M')
## 每个月最后一个工作日组成的索引
pd.date_range(start='20160320', periods=10, freq='BM')
# 小时
pd.date_range(start='20160320', periods=10, freq='4H')

在这里插入图片描述

4.时间及其算术运算

pd.Period 表示时期,比如几日,月或几个月等。比如用来统计每个月的销售额,就可以用时期作为单位。

4.1生成

在这里插入图片描述
Period(‘2010’, ‘A-DEC’),A表示anual年的,DEC,December十二月,在十二月结束。

4.2时期序列pd.period_range

# 单位是月,即频率
pd.period_range(start='2016-01', periods=12, freq='M')
pd.period_range(start='2016-01', end='2016-10', freq='M')
# 单位是季度
pd.period_range('2016-Q1',periods=10,freq='Q')
# 直接用字符串
index = pd.PeriodIndex(['2016Q1', '2016Q2', '2016Q3'], freq='Q-DEC')
index

在这里插入图片描述
freq='Q-DEC’表示Q季度是以DEC12月结束的单位

4.3时期的频率转换

4.3.1asfreq

sfreq

  • A-DEC: 以 12 月份作为结束的年时期
  • A-NOV: 以 11 月份作为结束的年时期
  • Q-DEC: 以 12 月份作为结束的季度时期
    在这里插入图片描述
# 生成2016年时间段,单位是anual,以December结尾
p = pd.Period('2016', freq='A-DEC')
p
# 转换为月,默认以年的终点作为新的时期
p.asfreq('M') 
# 设定以年的开始作为新的时期
p.asfreq('M', how='start')
# 生成新的月
p = pd.Period('2016-04', freq='M')
p
#将月转换为年,设定频率为A-DEC
p.asfreq('A-DEC')
# 以年为周期,以一年中的3月份作为年的结束(财年),设定为A-MAR
p.asfreq('A-MAR') #那么4月份就是下一年

在这里插入图片描述

4.3.2季度时间频率

Pandas 支持 12 种季度型频率,从 Q-JAN 到 Q-DEC区别是以哪个月作为一年的结束

# 生成2016年第4季度,以1月份结束
p = pd.Period('2016Q4', 'Q-JAN')
p
# 以 1 月份结束的财年中,2016Q4 的时期是指 2015-11-1 到 2016-1-31
p.asfreq('D', how='start'), p.asfreq('D', how='end')

##获取该季度倒数第二个工作日下午4点的时间戳
# 先将原来的时间转换为工作日B,先得出最后一天how='end',倒数第二个工作日,那就再减去1。下午4点,就再转换为分钟T,先得出最开始'start',再加上16 * 60,就得到16点。
p4pm = (p.asfreq('B', how='end') - 1).asfreq('T', 'start') + 16 * 60
p4pm
# 转换为 timestamp
p4pm.to_timestamp()

在这里插入图片描述

4.3.3 Timestamp 和 Period 相互转换

这是重采样的一种

# Timestamp时间戳序列,freq='M'
ts = pd.Series(np.random.randn(5), index = pd.date_range('2016-01-01', periods=5, freq='M'))
ts
# 转换为Period时间段时间序列,freq='M',但是时间变为时间段
ts.to_period()
#Timestamp序列,freq='D'
ts = pd.Series(np.random.randn(5), index = pd.date_range('2016-12-29', periods=5, freq='D'))
ts
#转换为Period时间段时间序列,freq='D',但是时间变为时间段
pts = ts.to_period() #默认直接转换为日时间段
pts
#转换为月时间段时间序列
pts = ts.to_period(freq='M') #月是重复的,把重复的月合并掉就要按月分组
pts
#按月分组
pts.groupby(level=0).sum()
# 转换为时间戳,由月转换回来,会丢失掉具体时间,而只剩下每个月的一天
pts.to_timestamp() #默认转换为每个月的第一天
pts.to_timestamp(how='end') #设定转换为每个月的最后一天

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.时间重采样

  • 高频率 -> 低频率 -> 降采样:5 分钟股票交易数据转换为日交易数据
  • 低频率 -> 高频率 -> 升采样
  • 其他重采样:每周三 (W-WED) 转换为每周五 (W-FRI)

4.1降采样

# 新建一个Series
ts = pd.Series(np.random.randint(0, 50, 60), index=pd.date_range('2016-04-25 09:30', periods=60, freq='T'))
ts
# 按5分钟为一组降采样。计算方法为sum(),默认以起始时间作为行索引。
ts.resample('5min').sum()
# label='right'。设定以结束时间作为行索引
ts.resample('5min',label='right').sum()

在这里插入图片描述
在这里插入图片描述

4.2OHLC 重采样

金融数据专用:Open/High/Low/Close

ts.resample('5min').ohlc()

在这里插入图片描述

4.3groupby()重采样

# 新建时间序列
ts = pd.Series(np.random.randint(0, 50, 100), index=pd.date_range('2016-03-01', periods=100, freq='D'))
ts.head()

在这里插入图片描述
通过月份进行重采样

# 方法1:新建一个lambda函数
ts.groupby(lambda x: x.month).sum() #x就是Series的逐个索引,即日期。x.month,是日期的月份
# 方法2:将时间戳序列转为时期序列ts.index.to_period('M'),时期是以月份为单位
ts.groupby(ts.index.to_period('M')).sum()

在这里插入图片描述

4.4升采样和插值

# 以周为单位,每周五采样
df = pd.DataFrame(np.random.randint(1, 50, 2), index=pd.date_range('2016-04-22', periods=2, freq='W-FRI')) 
#freq='W-FRI',是以周为单位,且以周五为每周的结束
df
# 要将以周为单位的数据转化为以天为单位,这时就要用到插值。22好到29号2之间原本没有值,现在要转换为以天为单位,就要插值。
df.resample('D')
df.resample('D').ffill() 
df.resample('D').ffill(limit=3)
# 将每周五为一周结束的采样周期转换为每周一为一周结束的采样周期
df.resample('W-MON').ffill()

在这里插入图片描述
在这里插入图片描述

4.5时期重采样

# 新建DataFrame,单位为月
df = pd.DataFrame(np.random.randint(2, 30, (24, 4)), 
                  index=pd.period_range('2015-01', '2016-12', freq='M'),
                  columns=list('ABCD'))
df.head(10)
# 重采样为单位为年,以Decemeber为一年的结束
adf = df.resample('A-DEC').mean()
adf
# 重采样为单位为年,以May为一年的结束
df.resample('A-MAY').mean()

##升采样
# 重采样为季度为单位,以December结束
adf.resample('Q-DEC')
adf.resample('Q-DEC').ffill()

在这里插入图片描述

4.6 从文件中解析时间序列

在这里插入图片描述
将上面的文件读取出来,解析为datetime时间序列。

df = pd.read_csv('data/002001.csv'#直接读取,自动给定index为整数
df = pd.read_csv('data/002001.csv', index_col='Date') #设定index为Date
df #结果看着是时间日期,实际上不是,因为不会默认解析为时间日期
df.index # dtype='object', name='Date',不是datetime
df = pd.read_csv('data/002001.csv', index_col='Date', parse_dates=True) #parse_dates=True,解析日期
df.index #dtype='datetime64[ns]', name='Date', freq=None
# 解析出来时间日期有什么好处?要把日交易数据根据赋权后的收盘价转换为周数据
wdf = df['Adj Close'].resample('W-FRI').ohlc()
wdf
# 新添加一列Volume
wdf['Volume'] = df['Volume'].resample('W-FRI').sum()
wdf

parse,解析,理解
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.7自定义时间日期解析函数

def date_parser(s):
    s = '2016/' + s
    d = datetime.strptime(s, '%Y/%m/%d')
    return d
# 这个函数是用来将字符串格式的时间'%Y/%m/%d'转换为dtype='datetime64时间格式

df = pd.read_csv('data/custom_date.csv', parse_dates=True, index_col='Date', date_parser=date_parser)
df
df.index

#datetime.strptime(s, '%Y/%m/%d')函数,将字符串格式的时间'%Y/%m/%d'转换为dtype='datetime64'时间格式

在这里插入图片描述
datetime.strptime()函数,详见https://blog.csdn.net/lengyuezuixue/article/details/87950493

六.数据可视化

Pandas 的数据可视化使用 matplotlib 为基础组件,是python的专门用来实现数据可视化的一个库。更基础的信息可参阅 matplotlib 相关内容。
本节主要介绍 Pandas 里提供的比利用matplotlib 来封装的更便捷的数据可视化操作。
在这里插入图片描述
更多内容可参照网上搜索资料或者官方文档

%matplotlib inline #要把图片直接画到网页中,启用matplotlib inline模式
import pandas as pd
import numpy as np

1.线型图

1.1Series线型图

Series 和 DataFrame 都提供了一个 plot 的函数。可以直接画出线形图。

ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = ts.cumsum() #累加
ts.describe() 
ts.plot()
#<matplotlib.axes._subplots.AxesSubplot at 0x14e84acca20>这个输出不想看到,可以在后面加上分号,就不会出现了
ts.plot(title='cumsum', style='r-', ylim=[-30, 30], figsize=(4, 3))
#style='r-',设置线型图形状,r是red,虚线是--。figs=(4, 3)是图片大小。

在这里插入图片描述
在这里插入图片描述

1.2DataFrame线型图

df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list('ABCD'))
df = df.cumsum() # 默认对每一列累计求和
df.describe() #数据描述
df.plot() #四列四条线画在一起,自动给定一个图例。如果是在matplotlib中,这些x/y轴标签,图例都要自己去画。pandas中更方便。默认将idex作为x轴,也可以指定index

# 二维数组DataFrame画图有自己的特有参数,subplots=True,把每个列单独画在一个子图中;sharex=True,x轴共用,即4个图x轴一样;sharey=True,y轴共用,即4个图,y轴一样。默认将idex作为x轴,也可以指定index
df.plot(title='DataFrame cumsum', figsize=(4, 12), subplots=True, sharex=True, sharey=True);

#指定index
#在原df中新增一个列I
df['I'] = np.arange(len(df))
df.plot(x='I', y=['A', 'C']) #指定x轴和y轴

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.柱状图

在这里插入图片描述

df = pd.DataFrame(np.random.rand(10, 4), columns=['A', 'B', 'C', 'D'])
df
# 指定一行,画图
df.iloc[1].plot(kind='bar')
df.iloc[1].plot.bar()
# 不指定,默认画出所有行的所有列。每个点都是四列。按行定点,每行区分为4列。
df.plot.bar()
# 上面的柱子是独立画的,也可以堆叠起来。stacked=True
df.plot.bar(stacked=True)
#bar后面加上h,表示横向柱状图Horizontal
df.plot.barh(stacked=True) 

stack,一堆,堆叠;Horizontal,横向的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.频率直方图

直方图是一种对值频率进行离散化的柱状图。数据点被分到离散的,间隔均匀的区间中,绘制各个区间中数据点的数据。

df = pd.DataFrame({'a': np.random.randn(1000) + 1, 'b': np.random.randn(1000),
                   'c': np.random.randn(1000) - 1}, columns=['a', 'b', 'c'])
df.head()
# 选择a列画直方图,
df['a'].plot.hist(bins=20)
# 直方图的意思就是将所有值按照从小到大排列起来,按照值,将值以最小和最大为界,分成20等分的大小区间,这些点对应的值落在每个区间中点的个数。x轴是20等分的值大小,y轴是区间中点的个数。比如说,落在值大小1到2区间中点的个数。
#random默认是正态分布,所以图中就是一个类似正态分布的图。中间点数最多,两边点数最少。
df['a'].plot.hist(bins=20) #去掉格网,加上中间的.plot
df.plot.hist(subplots=True, sharex=True, sharey=True)

#画出所有列的直方图
df.plot.hist()
# 三个直方图画在一起被遮挡住,可以调整透明值
df.plot.hist(alpha=0.5) #alpha,透明度
#还是不好看,可以加上stacked,叠加,不需再透明
df.plot.hist(stacked=True)
df.plot.hist(stacked=True, bins=20, grid=True)

# 将每个直方图分开画,subplots=True, sharex=True, sharey=True,且共享x和y轴
df.plot.hist(subplots=True, sharex=True, sharey=True)

hist,频数计算或频数直方图,直方图,统计频数直方图
alpha,透明度,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.概率密度图

表示一个事件发生的可能性,用来衡量一个事件发生的概率大小。

# 新建DataFrame
df = pd.DataFrame({'a': np.random.randn(1000) + 1, 'b': np.random.randn(1000),
                   'c': np.random.randn(1000) - 1}, columns=['a', 'b', 'c'])
df.head()
# plot.kde()绘制概率密度图
df['a'].plot.kde() #结果符合正态分布
df.plot.kde() #三列都画出来,三个概率密度图
# 决定正太密度图倒装形的有两个因素,均值和方差。均值决定概率密度图中心点的位置,概率密度图是窄的还是宽的由方差决定。三列的方差都差不多所以形状类似。
df.mean() #三列均值
df.std() #三列的std

在这里插入图片描述
在这里插入图片描述

5.带密度估计的规格化直方图

# 生成Y轴为对称轴,scale=1,包含200个数字的正态分布一维array
n1 = np.random.normal(0, 1, size=200) 
# N(0, 1)。np.random.normal()的意思是一个正态分布,normal这里是正态的意思
# 生成Y=10为对称轴,scale=2,包含200个数字的正态分布的一维array
n2 = np.random.normal(10, 2, size=200) # N(10, 4)
# np.concatenate([n1, n2]),将两个array组合起来,有两组200个数字组合为一组400个数字,原来的array没变。生成Series
s = pd.Series(np.concatenate([n1, n2])) 
# S,包含两组正态分布数字的Series
s.describe()
np.random.normal()的意思是一个正态分布,normal这里是正态的意思。
numpy.random.normal(loc=0,scale=1e-2,size=shape) ,意义如下: 
参数loc(float):正态分布的均值,对应着这个分布的中心。loc=0说明这一个以Y轴为对称轴的正态分布,
参数scale(float):正态分布的标准差,对应分布的宽度,scale越大,正态分布的曲线越矮胖,scale越小,曲线越高瘦。
参数size(int 或者整数元组):输出的值赋在shape里,默认为None。
concatenate,连接,连结,使连锁
np.concatenate((a1,a2,...), axis=0)),能够一次完成多个数组的拼接。其中a1,a2,...是数组类型的参数。

在这里插入图片描述

s.plot.hist(bins=100, alpha=0.5, normed=True)
s.plot.kde(style='r-')

在这里插入图片描述

6.散布图

散布图是把所有的点画在同一个坐标轴上的图像。是观察两个一维数据之间关系的有效的手段。
举例说明一

df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
df
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
df.plot.scatter(x='a', y='b');

在这里插入图片描述
举例说明2

df = pd.DataFrame({'a': np.concatenate([np.random.normal(0, 1, 200), np.random.normal(6, 1, 200)]),
                  'b': np.concatenate([np.random.normal(10, 2, 200), np.random.normal(0, 2, 200)]),
                  'c': np.concatenate([np.random.normal(10, 4, 200), np.random.normal(0, 4, 200)])})
df.describe()
# a、b、c之间有什么关系?通过散布图可以作直观的观察
df.plot.scatter(x='a', y='b')
# 结果,a和b的点明显分为两团,有明显的分界线,这样可以直观看到这些点数据有什么分布规律

在这里插入图片描述

7.饼图

s = pd.Series(3 * np.random.rand(4), index=['a', 'b', 'c', 'd'], name='series')
s
s.plot.pie() #默认饼图是椭圆形
s.plot.pie(figsize=(6,6)) #figsize=(6,6),指定饼图圆的形状
s.plot.pie(labels=['AA', 'BB', 'CC', 'DD'], colors=['r', 'g', 'b', 'c'],autopct='%.2f', fontsize=20, figsize=(6, 6))
# labels=['AA', 'BB', 'CC', 'DD'],指定标签。autopct='%.2f',指定百分比,'%.2f'保留两个小数点。fontsize=20,指定字体。

在这里插入图片描述
在这里插入图片描述
DataFrame画图

df = pd.DataFrame(3 * np.random.rand(4, 2), index=['a', 'b', 'c', 'd'], columns=['x', 'y'])
df
df.plot.pie(subplots=True, figsize=(9, 4))

在这里插入图片描述

8.高级绘图

高级绘图函数在 pandas.plotting 包里。
定制化的绘图需要学习matplotlib包的用法

8.1举例说明scatter_matrix,散点图矩阵图

scatter_matrix,scatter分散散点图散射。matrix, 矩阵;模型
散点图矩阵图,可以发现两两特征之间的联系

scatter_matrix(frame, alpha=0.5, c,figsize=None, ax=None, diagonal='hist', marker='.', density_kwds=None,hist_kwds=None, range_padding=0.05, **kwds)

1。frame,pandas dataframe对象
2。alpha, 图像透明度,一般取(0,1]
3。figsize,以英寸为单位的图像大小,一般以元组 (width, height) 形式设置
4。ax,可选一般为none
5。diagonal,必须且只能在{‘hist’, ‘kde’}中选择1个,’hist’表示直方图(Histogram plot),’kde’表示核密度估计(Kernel Density Estimation);该参数是scatter_matrix函数的关键参数
6。marker。Matplotlib可用的标记类型,如’.’,’,’,’o’等
7。density_kwds。(other plotting keyword arguments,可选),与kde相关的字典参数
8。hist_kwds。与hist相关的字典参数
9。range_padding。(float, 可选),图像在x轴、y轴原点附近的留白(padding),该值越大,留白距离越大,图像远离坐标原点
10。kwds。与scatter_matrix函数本身相关的字典参数
11。c。颜色
from pandas.plotting import scatter_matrix 
df = pd.DataFrame(np.random.randn(1000, 4), columns=['a', 'b', 'c', 'd'])
scatter_matrix(df, alpha=0.2, figsize=(6, 6), diagonal='kde');

在这里插入图片描述

8.2lag_plot

from pandas.plotting import lag_plot

s = pd.Series(0.1 * np.random.rand(1000) + 0.9 * np.sin(np.linspace(-99 * np.pi, 99 * np.pi, num=1000)))
lag_plot(s);

在这里插入图片描述

8.3autocorrelation_plot

from pandas.plotting import autocorrelation_plot

s = pd.Series(0.7 * np.random.rand(1000) + 0.3 * np.sin(np.linspace(-9 * np.pi, 9 * np.pi, num=1000)))
autocorrelation_plot(s);

在这里插入图片描述

七.实例:股票数据分析

这部分以后再写

https://github.com/kamidox/stock-analysis
stock,股份,股票;库存
在这里插入图片描述

1.股票数据获取

爬虫,如何写一个爬虫来获取股票数据

单个下载一个数据,数据来源:

打开 money.163.com,搜索你想要的股票,找到历史交易数据,找到下载数据的链接,即可下载想要的数据。

根据选择的字段,最终的下载链接大概是这样的:http://quotes.money.163.com/service/chddata.html?code=0600690&start=19931119&end=20180706&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;PCHG;TURNOVER;VOTURNOVER;VATURNOVER

把 code, start, end 字段修改一下即可下载其他股票在指定时间的交易数据。需要注意,股票代码前面的那个数字表示的是交易所,0 表示上海证券交易所,1 表示深圳证券交易所。

示例数据如下

日期,股票代码,名称,收盘价,最高价,最低价,开盘价,前收盘,涨跌幅,换手率,成交量,成交金额
2018-07-06,'600690,青岛海尔,18.22,18.64,17.51,18.24,18.21,0.0549,0.7088,43215639,780514355
2018-07-05,'600690,青岛海尔,18.21,18.85,18.05,18.42,18.18,0.165,0.6093,37150823,685499190
2018-07-04,'600690,青岛海尔,18.18,18.86,17.98,18.43,18.43,-1.3565,0.5812,35436927,653393994
2018-07-03,'600690,青岛海尔,18.43,18.96,17.82,18.72,18.77,-1.8114,0.7425,45274004,824268443

2.股票波动幅度分析

八.实例:时间事件日志

https://github.com/kamidox/utils

九.课程小结

1.课程回顾

  1. 介绍了Ipython:数据分析和科学计算领域的IDE。
    功能多且方便,可以直接将数据可视化在当前网页下。
  2. pandas快速入门:
    了解pandas在数据处理方面的基础接口。
    Movielens数据分析:电影的评分数据,这个数据经常用来作机器学习的推荐算法。用pandas作统计分析。
  3. pandas基础
    pandas核心数据结构
    基础运算:映射,排序
    索引:行索引,列索引,多层索引,重复索引
  4. pandas的分组和聚合运算
  5. 数据IO:从文件里导入数据及数据导出
    对磁盘的操作:用pandas从文件中读取数据,将数据保存到文件中
    对数据库操作:panda对接数据库,从数据库中提取数据
  6. 时间序列
    重采样,
  7. 数据可视化
    深入内容要看matplotlib,可以按照要求画出来数据。定制的美观的
    pandas的数据可视化提供便捷快速的数据可视化功能
  8. 实例:股票数据分析
  9. 实例:时间事件日志
  10. 课程代码:https://github.com/kamidox/pandas_tutor
    (https://github.com/kamidox/pandas_tutor)

2.课程展望

从更大维度看pandas:pandas在整个数据分析领域中处于哪一个环节。

  • 数据收集:爬虫技术
  • 数据清洗:pandas:过滤数据,保留有价值的数据。作NaN数据的处理。
  • 数据挖掘:pandas。初步分析数据,发现数据中的价值。
  • 数据建模:Scikit—及其学习的库,对数据进行训练。训练出一个模型,最后将这个模型发布成一个web应用。比如下面的Ternado, Django。
  • 数据应用:Ternado, Django etc。外部框架,发布成一个数据API。

pandas只是工具,最重要的还是数据思维
用excel都可以做出来价值连城的数据分析。在高手眼里,一片树叶都可以是武器,其威力丝毫不比刀剑差

推荐知乎用户:何明科—数据冰山
https://www.zhihu.com/people/he-ming-ke (https://www.zhihu.com/people/he-ming-ke)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值