python数据科学包第三天(索引、分组计算、数据聚合、分组运算和转换、载入数据、日期范围、数据可视化)

索引

  • 行索引
  • 列索引
  • 索引的分类
  • 重复索引的处理
s = pd.Series(np.random.rand(5), index=list('abcde'))
s
a    0.566924
b    0.603482
c    0.341639
d    0.164181
e    0.137200
dtype: float64
s.index
Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')
s.index.name = 'alpha'
s
alpha
a    0.566924
b    0.603482
c    0.341639
d    0.164181
e    0.137200
dtype: float64
df = pd.DataFrame(np.random.randn(4, 3), columns=['one', 'two', 'three'])
df
onetwothree
00.1315791.122725-1.920064
10.383557-0.039625-0.716855
2-0.391827-1.886698-1.131089
3-0.1167491.369576-1.314630
df.index
Int64Index([0, 1, 2, 3], dtype='int64')
df.columns
Index([u'one', u'two', u'three'], dtype='object')

通过以下语句,可以查看pandas都有哪些索引

pd.*Index?
pd.CategoricalIndex
pd.DatetimeIndex
pd.Float64Index
pd.Index
pd.Int64Index
pd.IntervalIndex
pd.MultiIndex
pd.PeriodIndex
pd.RangeIndex
pd.TimedeltaIndex
pd.UInt64Index
重复索引
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: int64
s['c']
2
s.index.is_unique
False
s.index.unique()
array(['a', 'b', 'c', 'd'], dtype=object)
s.groupby(s.index).sum()
a    5
b    4
c    2
d    4
dtype: int64

层次化索引

可以使数据在一个轴上有多个索引级别。即可以用二维的数据表达更高维度的数据,使数据组织方式更清晰。它使用 pd.MultiIndex 类来表示。

层次化索引有什么作用?

比如我们在分析股票数据,我们的一级行索引可以是日期;二级行索引可以是股票代码,列索引可以是股票的交易量,开盘价,收盘价等等。这样我们就可以把多个股票放在同一个时间维度下进行考察和分析。

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'])
index
MultiIndex(levels=[[u'a', u'b', u'c'], [1, 2, 3]],
           labels=[[0, 0, 0, 1, 1, 2, 2], [0, 1, 2, 0, 1, 1, 2]],
           names=[u'first', u'second'])
s = pd.Series(np.random.randn(7), index=index)
s
first  second
a      1        -1.192113
       2         0.226627
       3         0.390052
b      1         0.045297
       2         1.552926
c      2         0.014007
       3        -0.257103
dtype: float64
s.index
MultiIndex(levels=[[u'a', u'b', u'c'], [1, 2, 3]],
           labels=[[0, 0, 0, 1, 1, 2, 2], [0, 1, 2, 0, 1, 1, 2]],
           names=[u'first', u'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=u'second')
s['b']
second
1    0.045297
2    1.552926
dtype: float64
s['b':'c']
first  second
b      1         0.045297
       2         1.552926
c      2         0.014007
       3        -0.257103
dtype: float64
s[['b', 'a']]
first  second
b      1         0.045297
       2         1.552926
a      1        -1.192113
       2         0.226627
       3         0.390052
dtype: float64
s['b', 1]
0.045297227336673768
s[:, 2]
first
a    0.226627
b    1.552926
c    0.014007
dtype: float64
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
col-1onetwo
col-2blueredblue
row-1row-2
a1767
2159
b1355
2283
df.loc['a']
col-1onetwo
col-2blueredblue
row-2
1767
2159
type(df.loc['a'])
pandas.core.frame.DataFrame
df.loc['a', 1]
col-1  col-2
one    blue     7
       red      6
two    blue     7
Name: (a, 1), dtype: int64
df.loc['a', 1].index
MultiIndex(levels=[[u'one', u'two'], [u'blue', u'red']],
           labels=[[0, 0, 1], [0, 1, 0]],
           names=[u'col-1', u'col-2'])

自动变成了Series对象了

索引交换及排序
df
col-1onetwo
col-2blueredblue
row-1row-2
a1767
2159
b1355
2283
df2 = df.swaplevel('row-1', 'row-2')
df2
col-1onetwo
col-2blueredblue
row-2row-1
1a767
2a159
1b355
2b283

默认交换完成后还是按照以前的排序状态,这里需要重新排序外层

df2.sortlevel(0)
col-1onetwo
col-2blueredblue
row-2row-1
1a767
b355
2a159
b283
按照索引级别进行统计
df
col-1onetwo
col-2blueredblue
row-1row-2
a1767
2159
b1355
2283
df.sum(level=0)
col-1onetwo
col-2blueredblue
row-1
a81116
b5138
df.sum(level=1)
col-1onetwo
col-2blueredblue
row-2
1101112
231312
索引与列的转换
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
abcd
007one0
116one1
225one2
334two0
443two1
552two2
661two3
df.set_index('c')
abd
c
one070
one161
one252
two340
two431
two522
two613
df2 = df.set_index(['c', 'd'])
df2
ab
cd
one007
116
225
two034
143
252
361
df3 = df2.reset_index().sort_index('columns')
df3
abcd
007one0
116one1
225one2
334two0
443two1
552two2
661two3

一次性将之前set_index的内容全部变回去

分组计算

分组计算三步曲:拆分 -> 应用 -> 合并

  • 拆分:根据什么进行分组?
  • 应用:每个分组进行什么样的计算?
  • 合并:把每个分组的计算结果合并起来。
    在这里插入图片描述
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
data1data2key1key2
016aone
159atwo
247bone
337btwo
435aone

对 Series 进行分组

通过索引对齐关联起来

grouped = df['data1'].groupby(df['key1'])
grouped.mean()
key1
a    3.0
b    3.5
Name: data1, dtype: float64
df['data1'].groupby([df['key1'], df['key2']]).mean()
key1  key2
a     one     2
      two     5
b     one     4
      two     3
Name: data1, dtype: int3

也可以自己分组,这时的分组是行的标识

key=[1,2,1,1,2]
df['data1'].groupby(key).mean()
1    6.333333
2    1.500000
Name: data1, dtype: float64

这里就是将第一、三、四行分成一组叫做1,二、五行一组叫做2

对 DataFrame 进行分组

df.groupby('key1').mean()
data1data2
key1
a3.06.666667
b3.57.000000

在运算过程中,如果不是数字就被丢弃了

means = df.groupby(['key1', 'key2']).mean()['data1']
means
key1  key2
a     one     2
      two     5
b     one     4
      two     3
Name: data1, dtype: float64
means.unstack()
key2onetwo
key1
a25
b43
df.groupby(['key1', 'key2'])['data1'].mean()
key1  key2
a     one     2
      two     5
b     one     4
      two     3
Name: data1, dtype: int32

每个分组的元素个数

df.groupby(['key1', 'key2']).size()
key1  key2
a     one     2
      two     1
b     one     1
      two     1
dtype: int64

对分组进行迭代

for name, group in df.groupby('key1'):
    print name
    print group

a
   data1  data2 key1 key2
0      1      6    a  one
1      5      9    a  two
4      3      5    a  one
b
   data1  data2 key1 key2
2      4      7    b  one
3      3      7    b  two
for name, group in df.groupby(['key1', 'key2']):
    print name
    print group
('a', 'one')
   data1  data2 key1 key2
0      1      6    a  one
4      3      5    a  one
('a', 'two')
   data1  data2 key1 key2
1      5      9    a  two
('b', 'one')
   data1  data2 key1 key2
2      4      7    b  one
('b', 'two')
   data1  data2 key1 key2
3      3      7    b  two

转化为字典

d = dict(list(df.groupby('key1')))
d
{'a':    
data1  data2 key1 key2
 0      1      6    a  one
 1      5      9    a  two
 4      3      5    a  one, 
 'b':    
 data1  data2 key1 key2
 2      4      7    b  one
 3      3      7    b  two}
d['a']
data1data2key1key2
016aone
159atwo
435aone

按列分组

df.dtypes
data1     int32
data2     int32
key1     object
key2     object
dtype: object
grouped = df.groupby(df.dtypes, axis=1)
dict(list(grouped))
{dtype('int32'):    
      data1  data2
 0      1      6
 1      5      9
 2      4      7
 3      3      7
 4      3      5, 
 dtype('O'):  
     key1 key2
 0    a  one
 1    a  two
 2    b  one
 3    b  two
 4    a  one}

通过字典进行分组

df = pd.DataFrame(np.random.randint(1, 10, (5, 5)), 
                  columns=['a', 'b', 'c', 'd', 'e'], 
                  index=['Alice', 'Bob', 'Candy', 'Dark', 'Emily'])
df
abcde
Alice72799
Bob87768
Candy42665
Dark63948
Emily84965
df.ix[1, 1:3] = np.NaN
df
abcde
Alice72799
Bob8NaNNaN68
Candy42665
Dark63948
Emily84965
mapping = {'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'orange', 'e': 'blue'}
grouped = df.groupby(mapping, axis=1)
grouped.sum()
blueorangered
Alice1699
Bob868
Candy1166
Dark1749
Emily14612

具体共计某个元素,size是统计有哪些列

grouped.count()
blueorangered
Alice212
Bob111
Candy212
Dark212
Emily212
grouped.size()
blue      2
orange    1
red       2
dtype: int64

通过函数来分组

当函数作为分组依据时,数据表里的每个索引(可以是行索引,也可以是列索引)都会调用一次函数,函数的返回值作为分组的索引,即相同的返回值分在同一组。

df = pd.DataFrame(np.random.randint(1, 10, (5, 5)), 
                  columns=['a', 'b', 'c', 'd', 'e'], 
                  index=['Alice', 'Bob', 'Candy', 'Dark', 'Emily'])
df
abcde
Alice79191
Bob66715
Candy78538
Dark34681
Emily12212
def _dummy_group(idx):
    print idx
    return idx
df.groupby(_dummy_group)
Alice
Bob
Candy
Dark
Emily
<pandas.core.groupby.DataFrameGroupBy object at 0x07525650>
df.groupby(_dummy_group, axis=1)
a
b
c
d
e
<pandas.core.groupby.DataFrameGroupBy object at 0x07525A10>
grouped = df.groupby(len)
grouped.sum()
abcde
366715
434681
5151981311
grouped.size()
3    1
4    1
5    3
dtype: int64
grouped.count()
abcde
311111
411111
533333

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

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
countryChinaUSAChinaUSAChina
indexAABCB
096962
156187
225452
348949
472918
df.groupby(level='country', axis=1).count()
countryChinaUSA
032
132
232
332
432

必须指定axis,否则会报错

df.groupby(level='country', axis=1).sum()
countryChinaUSA
02012
11314
2810
32212
4243
df.groupby(level='index', axis=1).count()
indexABC
0221
1221
2221
3221
4221

数据聚合

分组运算,先根据一定规则拆分后的数据,然后对数据进行聚合运算,如前面见到的 mean(), sum() 等就是聚合的例子。聚合时,拆分后的第一个索引指定的数据都会依次传给聚合函数进行运算。最后再把运算结果合并起来,生成最终结果。

聚合函数除了内置的 sum(), min(), max(), mean() 等等之外,还可以自定义聚合函数。自定义聚合函数时,使用 agg()aggregate() 函数。

count是查看每个元素的个数,size是对聚合的行或列进行统计,describe是应用一些列的聚合函数进行统计

内置聚合函数

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
data1data2key1key2
093aone
138atwo
295bone
385btwo
492aone
df['data1'].groupby(df['key1']).sum()
key1
a    21
b    17
Name: data1, dtype: int32

自定义聚合函数

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)
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
data1data2
key1
a66
b10

应用多个聚合函数

grouped['data1', 'data2'].agg(['mean', 'std', peak])
data1data2
meanstdpeakmeanstdpeak
key1
a7.03.46410264.3333333.214556
b8.50.70710715.0000000.000000
# 给聚合后的列取名
grouped['data1'].agg([('agerage', 'mean'), ('max-range', peak)])
ageragemax-range
key1
a7.06
b8.51

本来是一个列表,如果是起名就是在列表中加入元组

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

使用 dict 作为参数来实现

d = {'data1': ['mean', peak, 'max', 'min'],
     'data2': 'sum'}
grouped.agg(d)
data1data2
meanpeakmaxminsum
key1
a7.069313
b8.519810

自定义函数不需要加引号

重置索引

grouped.agg(d).reset_index()
key1data1data2
meanpeakmaxminsum
0a7.069313
1b8.519810
df.groupby('key1', as_index=False).agg(d)
key1data1data2
meanpeakmaxminsum
0a7.069313
1b8.519810

这个方法默认跟上述方法得到的结果一致as_index=False,表示分组不算索引那一列

分组运算和转换

groupby 是特殊的分组运算。更一般的分组运算包括 “拆分 - 应用 - 合并”。这里介绍 transform()apply() 来实现分组运算。

transform

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
data1data2key1key2
049aone
152atwo
219bone
339btwo
418aone
# 给 df 每行都添加一个以 key1 分组后的平均值
k1_mean = df.groupby('key1').mean().add_prefix('mean_')
k1_mean
mean_data1mean_data2
key1
a3.3333336.333333
b2.0000009.000000
pd.merge(df, k1_mean, left_on='key1', right_index=True)
data1data2key1key2mean_data1mean_data2
049aone3.3333336.333333
152atwo3.3333336.333333
418aone3.3333336.333333
219bone2.0000009.000000
339btwo2.0000009.000000
# 使用 transform 简化处理
k1_mean = df.groupby('key1').transform(np.mean).add_prefix('mean_')
k1_mean
mean_data1mean_data2
03.3333336.333333
13.3333336.333333
22.0000009.000000
32.0000009.000000
43.3333336.333333
df[k1_mean.columns] = k1_mean
df
data1data2key1key2mean_data1mean_data2
049aone3.3333336.333333
152atwo3.3333336.333333
219bone2.0000009.000000
339btwo2.0000009.000000
418aone3.3333336.333333

距平化

与平均值的差异值

df = pd.DataFrame(np.random.randint(1, 10, (5, 5)), 
                  columns=['a', 'b', 'c', 'd', 'e'], 
                  index=['Alice', 'Bob', 'Candy', 'Dark', 'Emily'])
df
abcde
Alice48176
Bob44497
Candy62246
Dark42145
Emily43424
def demean(s):
    return s - s.mean()

key = ['one', 'one', 'two', 'one', 'two']
demeaned = df.groupby(key).transform(demean)
demeaned
abcde
Alice03.333333-10.3333330
Bob0-0.66666722.3333331
Candy1-0.500000-11.0000001
Dark0-2.666667-1-2.666667-1
Emily-10.5000001-1.000000-1
demeaned.groupby(key).mean()
abcde
one0-2.960595e-160-2.960595e-160
two00.000000e+0000.000000e+000

apply 函数

我们介绍过 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
data1data2key1key2
039aone
159atwo
274bone
376btwo
497aone
537aone
633atwo
745bone
882btwo
974aone
# 根据 column 排序,输出其最大的 n 行数据
def top(df, n=2, column='data1'):
    return df.sort_values(by=column, ascending=False)[:n]

top(df, n=5)
data1data2key1key2
497aone
882btwo
274bone
376btwo
974aone
df.groupby('key1').apply(top)
data1data2key1key2
key1
a497aone
974aone
b882btwo
274bone
# 传递参数
df.groupby('key1').apply(top, n=3, column='data2')
data1data2key1key2
key1
a039aone
159atwo
497aone
b376btwo
745bone
274bone
# 禁用分组键
df.groupby('key1', group_keys=False).apply(top)
data1data2key1key2
497aone
974aone
882btwo
274bone

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

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
Ohio          0.479291
New York     -0.301839
Vermont            NaN
Florida       0.476204
Oregon       -0.753084
Nevada             NaN
California   -0.686005
Idaho              NaN
dtype: float64
data.groupby(group_key).mean()
East    0.217885
West   -0.719545
dtype: float64
fill_mean = lambda g: g.fillna(g.mean())

data.groupby(group_key).apply(fill_mean)
Ohio          0.479291
New York     -0.301839
Vermont       0.217885
Florida       0.476204
Oregon       -0.753084
Nevada       -0.719545
California   -0.686005
Idaho        -0.719545
dtype: float64

载入数据到 Pandas

  • 索引:将一个列或多个列读取出来构成 DataFrame,其中涉及是否从文件中读取索引以及列名
  • 类型推断和数据转换:包括用户自定义的转换以及缺失值标记
  • 日期解析
  • 迭代:针对大文件进行逐块迭代。这个是Pandas和Python原生的csv库的最大区别
  • 不规整数据问题:跳过一些行,或注释等等
df = pd.read_csv('data/ex1.csv')
df
abcdmessage
01234hello
15678world
29101112foo

也可以用魔术,命令查看

df = pd.read_csv('data/ex1.csv')
df
df = pd.read_csv('data/ex1.csv', sep=',')
df
abcdmessage
01234hello
15678world
29101112foo

分隔符可以指定为正则表达式

没有列名称的时候

# 列名缺失
pd.read_csv('data/ex2.csv', header=None)
01234
01234hello
15678world
29101112foo
# 指定列名
pd.read_csv('data/ex2.csv', header=None, names=['a', 'b', 'c', 'd', 'msg'])
abcdmsg
01234hello
15678world
29101112foo
# 指定行索引
pd.read_csv('data/ex2.csv', header=None, names=['a', 'b', 'c', 'd', 'msg'], index_col='msg')
abcd
msg
hello1234
world5678
foo9101112
# 多层行索引
pd.read_csv('data/ex2.csv', header=None, names=['a', 'b', 'c', 'd', 'msg'], index_col=['msg', 'a'])
bcd
msga
hello1234
world5678
foo9101112

处理不规则的分隔符

# 正则表达式
pd.read_table('data/ex3.csv', sep='\s+')
# pd.read_table('data/ex3.csv', sep=' ')
# pd.read_csv('data/ex3.csv')
ABC
aaa-0.264438-1.026059-0.619500
bbb0.9272720.302904-0.032399
ccc-0.264273-0.386314-0.217601
ddd-0.871858-0.3483821.100491

当文件中第一行只有3列,而第2行开始就有四列,此时pandas会只能的把第一列作为行索引,第一行作为列索引。

缺失值处理

pd.read_csv('data/ex5.csv')
somethingabcdmessage
0one1234NaN
1two56NaN8world
2three9101112foo

源文件第一行第6列源文件是NA,可以当作字符串处理,也可以当作缺失值处理。这里pandas默认以缺失值处理。

pd.read_csv('data/ex5.csv', na_values=['NA', 'NULL', 'foo'])
somethingabcdmessage
0one1234NaN
1two56NaN8world
2three9101112NaN
na_values是指定哪些值作为缺失值
pd.read_csv('data/ex5.csv', na_values={'message': ['foo', 'NA'], 'something': ['two']})
somethingabcdmessage
0one1234NaN
1NaN56NaN8world
2three9101112NaN

使用字典的形式,指定某一列的哪些值作为缺失值。

逐块读取数据

pd.read_csv('data/ex6.csv', nrows=10)
onetwothreefourkey
00.467976-0.038649-0.295344-1.824726L
1-0.3588931.4044530.704965-0.200638B
2-0.5018400.659254-0.421691-0.057688G
30.2048861.0741341.388361-0.982404R
40.354628-0.1331160.283763-0.837063Q
51.8174800.7422730.419395-2.251035Q
6-0.7767640.935518-0.332872-1.875641U
7-0.9131351.530624-0.5726570.477252K
80.358480-0.497572-0.3670160.507702S
9-1.740877-1.160417-1.6378302.172201G

nrows表示读几行

# 统计每个 key 出现的次数
tr = pd.read_csv('data/ex6.csv', chunksize=1000)

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)
key_count[:10]
E    368
X    364
L    346
O    343
Q    340
M    338
J    337
F    335
K    334
H    330
dtype: float64

chunksize是将原文件分块,返回一个对象,对象类型是pandas.io.parsers.TextFileReader,这个对象是支持python的迭代的,可以使用for循环对没1000行进性迭代。add函数中的fill_value=0表示原Series中如果没有的话以0代替。

保存数据到磁盘

df = pd.read_csv('data/ex5.csv')
df
somethingabcdmessage
0one1234NaN
1two56NaN8world
2three9101112foo
df.to_csv('data/ex5_out.csv')
%more data/ex5_out.csv
df = pd.read_csv('data/ex5_out.csv')
df
Unnamed: 0somethingabcdmessage
00one1234NaN
11two56NaN8world
22three9101112foo

写的时候把索引值写进去。

# 不写索引
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
# 指定分隔符
df = pd.read_csv('data/ex5.csv')
df.to_csv('data/ex5_out.csv', index=False, sep='|')
%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

其他格式

  • HDFS:HDFS是C语言实现的库,可以高效地读取此磁盘上的二进制存储的科学数据
  • Excel文件:pd.read_excel/pd.ExcelFile/pd.ExcelWriter
  • JSON:通过json模块转换为字典,在转换为DataFrame
  • SQL数据库:通过pd.io.sql模块来从数据库读取数据
  • NoSQL(MongoDB)数据库:需要结合相应的数据库模块,如pymongo。再通过游标把数据读出来,转换为DataFrame

时间日期

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

时间日期在 Pandas 里的作用

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

Python datetime

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

from datetime import datetime
from datetime import timedelta
now = datetime.now()
now
datetime.datetime(2016, 4, 28, 14, 49, 51, 307000)
now.year, now.month, now.day
(2016, 4, 28)
date1 = datetime(2016, 3, 20)
date2 = datetime(2016, 3, 16)
delta = date1 - date2
delta
datetime.timedelta(4)
delta.days
4
delta.total_seconds()
345600.0
date2 + delta
datetime.datetime(2016, 3, 20, 0, 0)
date2 + timedelta(4.5)
datetime.datetime(2016, 3, 20, 12, 0)

字符串和 datetime 转换

关于 datetime 格式定义,可以参阅 python 官方文档

date = datetime(2016, 3, 20, 8, 30)
date
datetime.datetime(2016, 3, 20, 8, 30)
str(date)
'2016-03-20 08:30:00'

strftime接受的是一个格式化的样式

date.strftime('%Y-%m-%d %H:%M:%S')
'2016-03-20 08:30:00'
datetime.strptime('2016-03-20 09:30', '%Y-%m-%d %H:%M')
datetime.datetime(2016, 3, 20, 9, 30)

Pandas 里的时间序列

Pandas 里使用 Timestamp 来表达时间

最典型的是用datetime作为序列来创建一个Series。

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
2016-03-01    1.650889
2016-03-02   -0.328463
2016-03-03    1.674872
2016-03-04   -0.310849
dtype: float64
type(s.index)
pandas.tseries.index.DatetimeIndex
type(s.index[0])
pandas.tslib.Timestamp

pandas.tslib.Timestamp表示的是一个时间戳对象

日期范围

生成日期范围

pandas简便的生成时间序列的方法

pd.date_range('20160320', '20160331')
DatetimeIndex(['2016-03-20', '2016-03-21', '2016-03-22', '2016-03-23',
               '2016-03-24', '2016-03-25', '2016-03-26', '2016-03-27',
               '2016-03-28', '2016-03-29', '2016-03-30', '2016-03-31'],
              dtype='datetime64[ns]', freq='D')

如果不用开始结束时间,要明确使用start

pd.date_range(start='20160320', periods=10)
DatetimeIndex(['2016-03-20', '2016-03-21', '2016-03-22', '2016-03-23',
               '2016-03-24', '2016-03-25', '2016-03-26', '2016-03-27',
               '2016-03-28', '2016-03-29'],
              dtype='datetime64[ns]', freq='D')

normalize=True是去除每一个时间的时分秒那部分

## 规则化时间戳
pd.date_range(start='2016-03-20 16:23:32', periods=10, normalize=True)
DatetimeIndex(['2016-03-20', '2016-03-21', '2016-03-22', '2016-03-23',
               '2016-03-24', '2016-03-25', '2016-03-26', '2016-03-27',
               '2016-03-28', '2016-03-29'],
              dtype='datetime64[ns]', freq='D')

时间频率

## 星期
pd.date_range(start='20160320', periods=10, freq='W')
DatetimeIndex(['2016-03-20', '2016-03-27', '2016-04-03', '2016-04-10',
               '2016-04-17', '2016-04-24', '2016-05-01', '2016-05-08',
               '2016-05-15', '2016-05-22'],
              dtype='datetime64[ns]', freq='W-SUN')
# 月
pd.date_range(start='20160320', periods=10, freq='M')
DatetimeIndex(['2016-03-31', '2016-04-30', '2016-05-31', '2016-06-30',
               '2016-07-31', '2016-08-31', '2016-09-30', '2016-10-31',
               '2016-11-30', '2016-12-31'],
              dtype='datetime64[ns]', freq='M')
## 每个月最后一个工作日组成的索引
pd.date_range(start='20160320', periods=10, freq='BM')
DatetimeIndex(['2016-03-31', '2016-04-29', '2016-05-31', '2016-06-30',
               '2016-07-29', '2016-08-31', '2016-09-30', '2016-10-31',
               '2016-11-30', '2016-12-30'],
              dtype='datetime64[ns]', freq='BM')
# 小时
pd.date_range(start='20160320', periods=10, freq='4H')
DatetimeIndex(['2016-03-20 00:00:00', '2016-03-20 04:00:00',
               '2016-03-20 08:00:00', '2016-03-20 12:00:00',
               '2016-03-20 16:00:00', '2016-03-20 20:00:00',
               '2016-03-21 00:00:00', '2016-03-21 04:00:00',
               '2016-03-21 08:00:00', '2016-03-21 12:00:00'],
              dtype='datetime64[ns]', freq='4H')

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

p1 = pd.Period(2010)
p1
Period('2010', 'A-DEC')
p2 = p1 + 2
p2
Period('2012', 'A-DEC')

A-DEC中的A表示年,DEC表示12月分

p2 - p1
2L
p1 = pd.Period(2016, freq='M')
p1
Period('2016-01', 'M')
p1 + 3
Period('2016-04', 'M')

时期序列

pd.period_range(start='2016-01', periods=12, freq='M')
PeriodIndex(['2016-01', '2016-02', '2016-03', '2016-04', '2016-05', '2016-06',
             '2016-07', '2016-08', '2016-09', '2016-10', '2016-11', '2016-12'],
            dtype='int64', freq='M')
pd.period_range(start='2016-01', end='2016-10', freq='M')
PeriodIndex(['2016-01', '2016-02', '2016-03', '2016-04', '2016-05', '2016-06',
             '2016-07', '2016-08', '2016-09', '2016-10'],
            dtype='int64', freq='M')

注意:这里返回的是一个periodindex的日期,不同于DatetimeIndex

# 直接用字符串
index = pd.PeriodIndex(['2016Q1', '2016Q2', '2016Q3'], freq='Q-DEC')
index

Q表示一个季度,freq也可以使用Q

PeriodIndex(['2016Q1', '2016Q2', '2016Q3'], dtype='int64', freq='Q-DEC')

时期的频率转换

  • A-DEC: 以 12 月份作为结束的年时期
  • A-NOV: 以 11 月份作为结束的年时期
  • Q-DEC: 以 12 月份作为结束的季度时期
p = pd.Period('2016', freq='A-DEC')
p
Period('2016', 'A-DEC')
p.asfreq('M', how='start')
Period('2016-01', 'M')
p.asfreq('M', how='end')
Period('2016-12', 'M')

默认的是end,转换成以月为单位的时候会自动生成16年12月

p = pd.Period('2016-04', freq='M')
p
Period('2016-04', 'M')
p.asfreq('A-DEC')
Period('2016', 'A-DEC')
# 以年为周期,以一年中的 3 月份作为年的结束(财年)
p.asfreq('A-MAR')
Period('2017', 'A-MAR')

在这里插入图片描述

Pandas 支持 12 种季度型频率,从 Q-JAN 到 Q-DEC

p = pd.Period('2016Q4', 'Q-JAN')
p
Period('2016Q4', 'Q-JAN')
# 以 1 月份结束的财年中,2016Q4 的时期是指 2015-11-1 到 2016-1-31
p.asfreq('D', how='start'), p.asfreq('D', how='end')
(Period('2015-11-01', 'D'), Period('2016-01-31', 'D'))
# 获取该季度倒数第二个工作日下午4点的时间戳
p4pm = (p.asfreq('B', how='end') - 1).asfreq('T', 'start') + 16 * 60
p4pm
Period('2016-01-28 16:00', 'T')
# 转换为 timestamp
p4pm.to_timestamp()
Timestamp('2016-01-28 16:00:00')

Timestamp 和 Period 相互转换

ts = pd.Series(np.random.randn(5), index = pd.date_range('2016-01-01', periods=5, freq='M'))
ts
2016-01-31   -0.773323
2016-02-29    0.215953
2016-03-31    1.301631
2016-04-30   -0.066134
2016-05-31    1.651792
Freq: M, dtype: float64
ts.to_period()
2016-01   -0.773323
2016-02    0.215953
2016-03    1.301631
2016-04   -0.066134
2016-05    1.651792
Freq: M, dtype: float64

从日为单位转换以月为单位后,会显示当前月分的最后一天,以表示当前月分有多少天

ts = pd.Series(np.random.randn(5), index = pd.date_range('2016-12-29', periods=5, freq='D'))
ts
2016-12-29   -0.110462
2016-12-30   -0.265792
2016-12-31   -0.382456
2017-01-01   -0.036111
2017-01-02   -1.029658
Freq: D, dtype: float64
pts = ts.to_period(freq='M')
pts
2016-12   -0.110462
2016-12   -0.265792
2016-12   -0.382456
2017-01   -0.036111
2017-01   -1.029658
Freq: M, dtype: float64
pts.groupby(level=0).sum()
2016-12   -0.758711
2017-01   -1.065769
Freq: M, dtype: float64
# 转换为时间戳时,细部时间会丢失
pts.to_timestamp(how='end')
2016-12-31   -0.110462
2016-12-31   -0.265792
2016-12-31   -0.382456
2017-01-31   -0.036111
2017-01-31   -1.029658
dtype: float64

这样转会会丢失数据的精度,默认是以起始时间转换成时间戳的,这里是大的往小的转换

重采样

  • 高频率 -> 低频率 -> 降采样:5 分钟股票交易数据转换为日交易数据
  • 低频率 -> 高频率 -> 升采样
  • 其他重采样:每周三 (W-WED) 转换为每周五 (W-FRI)
ts = pd.Series(np.random.randint(0, 50, 60), index=pd.date_range('2016-04-25 09:30', periods=60, freq='T'))
ts
2016-04-25 09:30:00    18
2016-04-25 09:31:00    41
2016-04-25 09:32:00    49
2016-04-25 09:33:00    26
2016-04-25 09:34:00     5
2016-04-25 09:35:00    12
2016-04-25 09:36:00     6
2016-04-25 09:37:00    47
2016-04-25 09:38:00    16
2016-04-25 09:39:00    37
2016-04-25 09:40:00    44
2016-04-25 09:41:00     8
2016-04-25 09:42:00    22
2016-04-25 09:43:00    24
2016-04-25 09:44:00    12
2016-04-25 09:45:00    26
2016-04-25 09:46:00    30
2016-04-25 09:47:00    38
2016-04-25 09:48:00     5
2016-04-25 09:49:00    26
2016-04-25 09:50:00    39
2016-04-25 09:51:00     7
2016-04-25 09:52:00     6
2016-04-25 09:53:00    12
2016-04-25 09:54:00    24
2016-04-25 09:55:00     0
2016-04-25 09:56:00    12
2016-04-25 09:57:00    27
2016-04-25 09:58:00    10
2016-04-25 09:59:00    26
2016-04-25 10:00:00    27
2016-04-25 10:01:00    18
2016-04-25 10:02:00    27
2016-04-25 10:03:00    25
2016-04-25 10:04:00    25
2016-04-25 10:05:00    35
2016-04-25 10:06:00    28
2016-04-25 10:07:00     3
2016-04-25 10:08:00    20
2016-04-25 10:09:00    48
2016-04-25 10:10:00     5
2016-04-25 10:11:00    48
2016-04-25 10:12:00    30
2016-04-25 10:13:00     2
2016-04-25 10:14:00    11
2016-04-25 10:15:00    18
2016-04-25 10:16:00    21
2016-04-25 10:17:00    32
2016-04-25 10:18:00    43
2016-04-25 10:19:00    10
2016-04-25 10:20:00     5
2016-04-25 10:21:00    45
2016-04-25 10:22:00     3
2016-04-25 10:23:00    30
2016-04-25 10:24:00     3
2016-04-25 10:25:00    24
2016-04-25 10:26:00    46
2016-04-25 10:27:00     2
2016-04-25 10:28:00    33
2016-04-25 10:29:00    25
Freq: T, dtype: int32

T表示分钟,因为M与月份冲突

# 0-4 分钟为第一组
ts.resample('5min', how='sum')
2016-04-25 09:30:00    139
2016-04-25 09:35:00    118
2016-04-25 09:40:00    110
2016-04-25 09:45:00    125
2016-04-25 09:50:00     88
2016-04-25 09:55:00     75
2016-04-25 10:00:00    122
2016-04-25 10:05:00    134
2016-04-25 10:10:00     96
2016-04-25 10:15:00    124
2016-04-25 10:20:00     86
2016-04-25 10:25:00    130
Freq: 5T, dtype: int32

数据的聚方式是加和

# 0-4 分钟为第一组
ts.resample('5min', how='sum', label='right')
2016-04-25 09:35:00    139
2016-04-25 09:40:00    118
2016-04-25 09:45:00    110
2016-04-25 09:50:00    125
2016-04-25 09:55:00     88
2016-04-25 10:00:00     75
2016-04-25 10:05:00    122
2016-04-25 10:10:00    134
2016-04-25 10:15:00     96
2016-04-25 10:20:00    124
2016-04-25 10:25:00     86
2016-04-25 10:30:00    130
Freq: 5T, dtype: int32

right表示以结束时间表示5分钟

OHLC 重采样

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

ts.resample('5min', how='ohlc')
openhighlowclose
2016-04-25 09:30:00184955
2016-04-25 09:35:001247637
2016-04-25 09:40:004444812
2016-04-25 09:45:002638526
2016-04-25 09:50:003939624
2016-04-25 09:55:00027026
2016-04-25 10:00:0027271825
2016-04-25 10:05:003548348
2016-04-25 10:10:00548211
2016-04-25 10:15:0018431010
2016-04-25 10:20:0054533
2016-04-25 10:25:002446225
### 通过 groupby 重采样
ts = pd.Series(np.random.randint(0, 50, 100), index=pd.date_range('2016-03-01', periods=100, freq='D'))
ts
2016-03-01    13
2016-03-02    21
2016-03-03    26
2016-03-04     3
2016-03-05    31
2016-03-06    29
2016-03-07    42
2016-03-08    24
2016-03-09    10
2016-03-10    42
2016-03-11    42
2016-03-12     7
2016-03-13    10
2016-03-14    48
2016-03-15    12
2016-03-16    15
2016-03-17    16
2016-03-18    34
2016-03-19    45
2016-03-20    40
2016-03-21    45
2016-03-22    46
2016-03-23    21
2016-03-24    27
2016-03-25    10
2016-03-26    47
2016-03-27     8
2016-03-28     9
2016-03-29     0
2016-03-30    20
              ..
2016-05-10    38
2016-05-11    46
2016-05-12     8
2016-05-13    15
2016-05-14    13
2016-05-15    30
2016-05-16    25
2016-05-17    15
2016-05-18     3
2016-05-19     5
2016-05-20    21
2016-05-21    18
2016-05-22    11
2016-05-23    47
2016-05-24    14
2016-05-25    33
2016-05-26    37
2016-05-27    40
2016-05-28     5
2016-05-29    27
2016-05-30     2
2016-05-31    31
2016-06-01    31
2016-06-02    41
2016-06-03    28
2016-06-04     2
2016-06-05    21
2016-06-06    10
2016-06-07    21
2016-06-08    18
Freq: D, dtype: int32
ts.groupby(lambda x: x.month).sum()
3    759
4    648
5    748
6    172
dtype: int32
ts.groupby(ts.index.to_period('M')).sum()
2016-03    759
2016-04    648
2016-05    748
2016-06    172
Freq: M, dtype: int32

升采样和插值

# 以周为单位,每周五采样
df = pd.DataFrame(np.random.randint(1, 50, 2), index=pd.date_range('2016-04-22', periods=2, freq='W-FRI'))
df
0
2016-04-2210
2016-04-296
df.resample('D')
0
2016-04-2210
2016-04-23NaN
2016-04-24NaN
2016-04-25NaN
2016-04-26NaN
2016-04-27NaN
2016-04-28NaN
2016-04-296
df.resample('D', fill_method='ffill', limit=3)
0
2016-04-2210
2016-04-2310
2016-04-2410
2016-04-2510
2016-04-26NaN
2016-04-27NaN
2016-04-28NaN
2016-04-296
# 以周为单位,每周一采样
df.resample('W-MON', fill_method='ffill')
0
2016-04-2510
2016-05-026

因为22是周五,转换为周一的话,不填充就是nan

时期重采样

df = pd.DataFrame(np.random.randint(2, 30, (24, 4)), 
                  index=pd.period_range('2015-01', '2016-12', freq='M'),
                  columns=list('ABCD'))
df
ABCD
2015-012072218
2015-022282119
2015-031317127
2015-0424172014
2015-0515131520
2015-061928222
2015-07207227
2015-081018216
2015-091724119
2015-102322125
2015-11243198
2015-12716612
2016-011813815
2016-021714221
2016-03176524
2016-0424142214
2016-0516142014
2016-0626291415
2016-07211112
2016-0812111718
2016-091921416
2016-102116117
2016-111623222
2016-122192711
adf = df.resample('A-DEC', how='mean')
adf
ABCD
201516.16666715.00000012.75000016.416667
201617.41666715.08333311.91666714.916667
df.resample('A-MAY', how='mean')
ABCD
201514.80000016.40000018.00000015.60
201617.66666713.25000010.00000017.25
201716.71428617.14285712.28571413.00
# 升采样
adf.resample('Q-DEC')
ABCD
2015Q116.16666715.00000012.75000016.416667
2015Q2NaNNaNNaNNaN
2015Q3NaNNaNNaNNaN
2015Q4NaNNaNNaNNaN
2016Q117.41666715.08333311.91666714.916667
2016Q2NaNNaNNaNNaN
2016Q3NaNNaNNaNNaN
2016Q4NaNNaNNaNNaN
adf.resample('Q-DEC', fill_method='ffill')
ABCD
2015Q116.16666715.00000012.75000016.416667
2015Q216.16666715.00000012.75000016.416667
2015Q316.16666715.00000012.75000016.416667
2015Q416.16666715.00000012.75000016.416667
2016Q117.41666715.08333311.91666714.916667
2016Q217.41666715.08333311.91666714.916667
2016Q317.41666715.08333311.91666714.916667
2016Q417.41666715.08333311.91666714.916667

从文件中读取日期序列

df = pd.read_csv('data/002001.csv', index_col='Date')
df
OpenHighLowCloseVolumeAdj Close
Date
2015-12-2216.8617.1316.4816.951351990016.95
2015-12-2116.3117.0016.2016.851413220016.85
2015-12-1816.5916.7016.2116.311052430016.31
2015-12-1716.2816.7516.1616.601232650016.60
2015-12-1616.2316.4216.0516.28802600016.28
2015-12-1516.0616.3115.9516.18664750016.18
2015-12-1415.6016.0615.4516.06835520016.06
2015-12-1115.5015.8015.4115.62724350015.62
2015-12-1015.9916.0515.5115.56765490015.56
2015-12-0916.0016.1915.8015.83792690015.83
2015-12-0816.5416.5516.0116.05764010016.05
2015-12-0716.5017.0416.4816.631191720016.63
2015-12-0416.1316.8516.0116.621401110016.62
2015-12-0315.9716.3415.8816.21950400016.21
2015-12-0215.8916.0415.5015.881122960015.88
2015-12-0115.6715.9615.5015.85719220015.85
2015-11-3015.5415.9015.0515.701161520015.70
2015-11-2716.6116.9915.1015.541517700015.54
2015-11-2616.9817.2216.6216.781319630016.78
2015-11-2516.1517.0416.0316.941860010016.94
2015-11-2415.9016.2015.7016.15856120016.15
2015-11-2316.0916.3216.0016.05944170016.05
2015-11-2015.9616.1715.8116.08802220016.08
2015-11-1915.7516.0515.7116.02519330016.02
2015-11-1816.2616.3015.7215.75731850015.75
2015-11-1716.4116.4716.1116.221147980016.22
2015-11-1615.7016.2215.6116.21908320016.21
2015-11-1316.3616.4715.9015.951292440015.95
2015-11-1216.2316.9216.0016.591649280016.59
2015-11-1116.1616.2815.8116.221566190016.22
2015-11-1016.2916.6916.0416.152145760016.15
2015-11-0915.7016.2915.5616.022084260016.02
2015-11-0615.5316.0115.4115.861773580015.86
2015-11-0515.3315.7915.2115.521905140015.52
2015-11-0414.6515.3514.6515.331457820015.33
2015-11-0314.8414.9614.4414.62657630014.62
2015-11-0214.9115.1814.7414.74948780014.74
2015-10-3015.2515.5214.8115.221290850015.22
2015-10-2915.0115.3614.9615.301117710015.30
2015-10-2815.1415.5014.9615.021137320015.02
2015-10-2715.1015.1714.5115.151295040015.15
2015-10-2615.4115.5514.8715.181584450015.18
2015-10-2314.8015.2314.7515.201476900015.20
2015-10-2214.2814.8214.2514.731042890014.73
2015-10-2115.2415.7014.0814.262111350014.26
2015-10-2014.9915.2414.8915.221193580015.22
2015-10-1915.2715.3514.8515.031160130015.03
2015-10-1615.2315.3514.8215.251416870015.25
2015-10-1514.7315.1514.6015.121117770015.12
2015-10-1414.9915.1214.7214.731036890014.73
2015-10-1315.0215.1914.8515.071340820015.07
2015-10-1214.6315.4314.4115.302411080015.30
2015-10-0914.5014.7914.1114.622381850014.62
2015-10-0814.7514.7514.6514.751831720014.75
2015-10-0713.4113.4113.4113.41013.41
2015-10-0613.4113.4113.4113.41013.41
2015-10-0513.4113.4113.4113.41013.41
2015-10-0213.4113.4113.4113.41013.41
2015-10-0113.4113.4113.4113.41013.41
df.index
Index([u'2015-12-22', u'2015-12-21', u'2015-12-18', u'2015-12-17',
       u'2015-12-16', u'2015-12-15', u'2015-12-14', u'2015-12-11',
       u'2015-12-10', u'2015-12-09', u'2015-12-08', u'2015-12-07',
       u'2015-12-04', u'2015-12-03', u'2015-12-02', u'2015-12-01',
       u'2015-11-30', u'2015-11-27', u'2015-11-26', u'2015-11-25',
       u'2015-11-24', u'2015-11-23', u'2015-11-20', u'2015-11-19',
       u'2015-11-18', u'2015-11-17', u'2015-11-16', u'2015-11-13',
       u'2015-11-12', u'2015-11-11', u'2015-11-10', u'2015-11-09',
       u'2015-11-06', u'2015-11-05', u'2015-11-04', u'2015-11-03',
       u'2015-11-02', u'2015-10-30', u'2015-10-29', u'2015-10-28',
       u'2015-10-27', u'2015-10-26', u'2015-10-23', u'2015-10-22',
       u'2015-10-21', u'2015-10-20', u'2015-10-19', u'2015-10-16',
       u'2015-10-15', u'2015-10-14', u'2015-10-13', u'2015-10-12',
       u'2015-10-09', u'2015-10-08', u'2015-10-07', u'2015-10-06',
       u'2015-10-05', u'2015-10-02', u'2015-10-01'],
      dtype='object', name=u'Date')
df = pd.read_csv('data/002001.csv', index_col='Date', parse_dates=True)
df.index
DatetimeIndex(['2015-12-22', '2015-12-21', '2015-12-18', '2015-12-17',
               '2015-12-16', '2015-12-15', '2015-12-14', '2015-12-11',
               '2015-12-10', '2015-12-09', '2015-12-08', '2015-12-07',
               '2015-12-04', '2015-12-03', '2015-12-02', '2015-12-01',
               '2015-11-30', '2015-11-27', '2015-11-26', '2015-11-25',
               '2015-11-24', '2015-11-23', '2015-11-20', '2015-11-19',
               '2015-11-18', '2015-11-17', '2015-11-16', '2015-11-13',
               '2015-11-12', '2015-11-11', '2015-11-10', '2015-11-09',
               '2015-11-06', '2015-11-05', '2015-11-04', '2015-11-03',
               '2015-11-02', '2015-10-30', '2015-10-29', '2015-10-28',
               '2015-10-27', '2015-10-26', '2015-10-23', '2015-10-22',
               '2015-10-21', '2015-10-20', '2015-10-19', '2015-10-16',
               '2015-10-15', '2015-10-14', '2015-10-13', '2015-10-12',
               '2015-10-09', '2015-10-08', '2015-10-07', '2015-10-06',
               '2015-10-05', '2015-10-02', '2015-10-01'],
              dtype='datetime64[ns]', name=u'Date', freq=None)

默认他不会去解析这个时间,生成的是一个object这个对象,设置parse_dates这个参数,可以自动解析这个时间对象。
解析这个时间好处就是,可以根据时间,进行升序==重采样

wdf = df['Adj Close'].resample('W-FRI', how='ohlc')
wdf
openhighlowclose
Date
2015-10-0213.4113.4113.4113.41
2015-10-0913.4114.7513.4114.62
2015-10-1615.3015.3014.7315.25
2015-10-2315.0315.2214.2615.20
2015-10-3015.1815.3015.0215.22
2015-11-0614.7415.8614.6215.86
2015-11-1316.0216.5915.9515.95
2015-11-2016.2116.2215.7516.08
2015-11-2716.0516.9415.5415.54
2015-12-0415.7016.6215.7016.62
2015-12-1116.6316.6315.5615.62
2015-12-1816.0616.6016.0616.31
2015-12-2516.8516.9516.8516.95
wdf['Volume'] = df['Volume'].resample('W-FRI', how='sum')
wdf
openhighlowcloseVolume
Date
2015-10-0213.4113.4113.4113.410
2015-10-0913.4114.7513.4114.6242135700
2015-10-1615.3015.3014.7315.2573234300
2015-10-2315.0315.2214.2615.2069848500
2015-10-3015.1815.3015.0215.2264253700
2015-11-0614.7415.8614.6215.8667429500
2015-11-1316.0216.5915.9515.9587379300
2015-11-2016.2116.2215.7516.0841097000
2015-11-2716.0516.9415.5415.5464976300
2015-12-0415.7016.6215.7016.6253552100
2015-12-1116.6316.6315.5615.6242382600
2015-12-1816.0616.6016.0616.3145879500
2015-12-2516.8516.9516.8516.9527652100

数据可视化

Pandas 的数据可视化使用 matplotlib 为基础组件。更基础的信息可参阅 matplotlib 相关内容。本节主要介绍 Pandas 里提供的比 matplotlib 更便捷的数据可视化操作。
如果想要把数据画在jupyter notebook里面,还需要启用%matplotlib inline

线型图

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

ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = ts.cumsum()
ts.describe()
count    1000.000000
mean        3.526470
std        16.243923
min       -20.683881
25%        -9.300320
50%        -1.758149
75%        13.224696
max        42.878495
dtype: float64

加一个;就可以看到图片了

ts.plot();

在这里插入图片描述

# ts.plot? for more help
ts.plot(title='cumsum', style='r-', ylim=[-30, 30], figsize=(4, 3));

title是标题,style是图像的形状,figsize是图像的大小,ylim是纵轴
在这里插入图片描述

df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list('ABCD'))
df = df.cumsum()
df.describe()
ABCD
count1000.0000001000.0000001000.0000001000.000000
mean-9.15245328.7511056.4353064.764281
std19.17714311.0898157.5029155.644176
min-52.401351-2.245964-9.804085-7.966805
25%-22.83117721.594373-0.6344200.299640
50%-3.33317228.5318658.4771884.178048
75%5.85958237.28017712.4335849.672910
max22.48083750.74014721.21548519.161365
# df.plot? for more help
df.plot(title='DataFrame cumsum', figsize=(4, 12), subplots=True, sharex=True, sharey=True);

在这里插入图片描述
subplots是单独把每一列画在一个图里,sharex是公用X轴,sharey是公用y轴

df['I'] = np.arange(len(df))
df.plot(x='I', y=['A', 'C'])

可以指定X轴和Y轴
在这里插入图片描述

柱状图

df = pd.DataFrame(np.random.rand(10, 4), columns=['A', 'B', 'C', 'D'])
df
ABCD
00.2513220.7104490.6779390.187400
10.0820890.7930910.0218010.287124
20.9112400.8022220.4290640.956067
30.4773700.2343960.3035950.945137
40.4711240.2055070.4991600.887754
50.3893820.0622980.1101570.705081
60.0687190.3257470.9515940.501131
70.3651770.9509950.8987840.822838
80.0228070.7216820.6510130.212020
90.4978620.5967360.4867100.672207
df.ix[1].plot(kind='bar')
<matplotlib.axes._subplots.AxesSubplot at 0x8cb5030>

在这里插入图片描述

选择第二行画柱状图

df.ix[1].plot.bar()
<matplotlib.axes._subplots.AxesSubplot at 0x8cec490>

在这里插入图片描述

df.plot.bar(stacked=True)
<matplotlib.axes._subplots.AxesSubplot at 0x8f2bf70>

在这里插入图片描述

df.plot.barh(stacked=True)
<matplotlib.axes._subplots.AxesSubplot at 0x9676070>

在这里插入图片描述

直方图

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

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['a'].plot.hist(bins=10)

在这里插入图片描述
直方图是根据最大值和最小值生成10等份,统计了每个区间里面点的个数

df.plot.hist(subplots=True, sharex=True, sharey=True)
array([<matplotlib.axes._subplots.AxesSubplot object at 0x087FF030>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x0878F5B0>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x086AFFB0>], dtype=object)

在这里插入图片描述
alpha是透明值,否则这个就重叠了

df.plot.hist(alpha=0.5)
<matplotlib.axes._subplots.AxesSubplot at 0x85ed350>

在这里插入图片描述

stacked是叠加,grid图片加入网格

df.plot.hist(stacked=True, bins=20, grid=True)

<matplotlib.axes._subplots.AxesSubplot at 0x9712bb0>
在这里插入图片描述

密度图

正态分布(高斯分布)就是一种自然界中广泛存在密度图。比如我们的身高,我们的财富,我们的智商都符合高斯分布。

绘制概率密度

df['a'].plot.kde()

在这里插入图片描述

df.plot.kde()

在这里插入图片描述

df.mean()
a    0.947151
b   -0.026500
c   -1.039657
dtype: float64
df.std()
a    1.014101
b    1.028685
c    1.030285
dtype: float64

散布图

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

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

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200416203953372.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x5Y2tpZA==,size_16,color_FFFFFF,t_70)


```python
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()
abc
count400.000000400.000000400.000000
mean2.9743665.0352675.011259
std3.1584285.4920176.572784
min-3.149143-5.022496-13.671181
25%0.079920-0.130532-0.128582
50%2.8003265.5877174.901682
75%5.92373110.13978110.002299
max8.68823416.23351619.855104
df.plot.scatter(x='a', y='b')

在这里插入图片描述

饼图

s = pd.Series(3 * np.random.rand(4), index=['a', 'b', 'c', 'd'], name='series')
s
a    0.505096
b    0.295620
c    2.855217
d    2.716670
Name: series, dtype: float64
s.plot.pie(figsize=(6,6))

在这里插入图片描述
autopct 显示百分比的保留位数,fontsize是修改字体大小

s.plot.pie(labels=['AA', 'BB', 'CC', 'DD'], colors=['r', 'g', 'b', 'c'],
           autopct='%.2f', fontsize=20, figsize=(6, 6))

在这里插入图片描述

高级绘图

高级绘图函数在 pandas.tools.plotting 包里。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值