DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • 理论基础

  • Py数据分析包

    • numpy
    • pandas基本操作
      • 总结
      • Series
        • 创建方式
        • 显式和隐式索引
        • 索引和切片
        • 常用属性
        • 常用方法
        • 运算法则
      • DataFrame - 基本
        • 创建方式
        • 常用属性
        • 数据查看
        • 数据保存与加载
        • CSV
        • Excel
      • DataFrame - 切片和索引
        • ※ iloc - 结果类型
        • iloc里有两元素
        • iloc里只有一个元素
        • ※ iloc - 实用性需求
        • 取多行多列
        • 取某一行某一列
        • 取单个成员
        • 取多个成员
        • 取一个区域
        • 当有显式索引时
      • 股票分析案例
        • 准备工作
        • 收益率和波动率
        • 最大和最小
        • 开盘和收盘
        • 算收益
        • 计算均线
        • ★ 案例知识点汇总
    • pandas数据清洗
    • pandas数据集成
    • pandas高级操作
    • pandas时间序列
    • pandas样式制定
    • pandas绘图
    • 商场销售数据分析
    • 美妆数据分析
    • 连锁超市数据分析
    • 财务经营分析
    • 拍拍贷数据分析
    • ★一切从简
    • 一些杂乱的思考
  • 机器学习

  • 深度学习

  • 华中科大的网课

  • AI
  • Py数据分析包
DC
2024-07-26
目录

pandas基本操作

在前面我们学习了numpy的使用, 意犹未尽.
今天我们来学习一个数据分析领域更强大的一个库, pandas, 它具有怎样的特性, 跟numpy有何不同呢?
请听我娓娓道来.

Pandas用来处理表格型或异质型数据; Numpy则相反,更适合处理同质型的数值类数组数据.

库 功能 数据类型
numpy 处理一维多维的数值型数据 ndarray
pandas 处理各种类型(数值、文本、时间序列等)的数据 Series(类似一维数组结构)
DataFrame(类似二维数组结构)

PS: 一些简单理解: 二维数据结构 - 数据库表、excel表; 多个一维组成一个二维.

★ 注意一点, 在前面numpy的通用函数小节, 所涉及到的知识点, pandas中也能使用!!

pandas基础


# 总结

Series

■ 三部分组成: index、value、dtype
■ pd.Series(data=xxx,index=yyy)
  - data参数值可以是列表、numpy数组、字典
  - index参数值用于指明显式索引.
    1> 使用列表和numpy数组构建Serise,其默认索引是 0,1,2,3.
    2> 使用字典构建Series,其默认索引是 字典的keys().
       我们可以通过index参数让字典键按照我们想要的顺序传递给构造函数.
  >>> pd.Series(data={'name':'bobo','age':20},index=["age","hight"])
      age       20
      hight    NaN
      dtype: object
■ 可以简单的将Serise看作是一维的Numpy数组
  ★ 像Numpy数组的 数组运算、bool数组充当索引、调用数学函数等用法、切片后被赋值会改变原数组. Serise对象都适用!!
  s1*2   s1[s1>3]   s1.mean()   s1[:3]=5
■ 索引和切片
  s4['语文']  s4[0]  s4[[True,False,True]]  切片跟列表切片一样的
■ 查看Series对象
  s4.shape  s4.size  s4.index  s4.values
  s4.head(2)
  s4.tail(2)
  s4.unique()	      返回去重后的结果, 并将值放到了一个numpy对象中
  s4.nunique()	    返回去重后元素的个数
  s4.value_counts()	返回元素出现的次数
  s4.isnull()	      会对series对象中的每个成员都进行空值判定
  s4.notnull()
  >> s3[s3.notnull()] 过滤空值
  >> s3[s3.isnull()]  保留空值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

DataFrame

■ DataFrame的组成: 行索引 index + 列索引 columns + 值 values.
■ ★★★ DataFrame可以看作是由多个共享相同索引的Serise对象构成的!!
      某种意义上,你可以把DataFrame看作是一个字典.因为它的很多操作跟字典是相似的.
  >>> # 字典的键作为列,内部字典的键作为行索引.  
  >>> # {列索引: 内部kv就是Series对象,k是Serise对象的索引,此处充当DataFrame的行索引}
  >>> dic = {'张三':{"语文":90,"数学":88,"英语":61,"理综":50},"李四":{"语文":92,"数学":83,"英语":66,"理综":70}}
  >>> pd.DataFrame(data=dic)
      张三  李四
  语文  90  92
  数学  88  83
  英语  61  66
  理综  50  70
■ 和Series对象一样, 有三种创建方式: 列表 、numpy数组 、字典
  - pd.DataFrame(data=[[1,2],[3,4]],index=('A','B'),columns=['a','b'])
  - pd.DataFrame(data=dic,columns=['李四','张三'])
    通过columns参数指定了列的顺序,DataFrame的列会按照指定顺序排列.
■ 你将DataFrame对象看作是一个字典.那么!!
  - df1['debt'] 就是取debt这一列 -- 就像字典取值一样,只不过这里取的值是Serise对象,是一列
  - 给一列赋值,该列存在则修改.不存在则给DataFrame对象新增一列.
    df1['debt'] = 16.5  # 标量会自动向量化. 不管是新增还是修改.
    df1['debt'] = np.arange(6)
    df1['debt'] = pd.Series([1,2,3],index=['a','b','d'] # f1有行索引'a','b','c' 那么,d被舍弃,c处以Nan值填充.
    df1['debt'] = df1['score'] > 80
  - 从DataFrame中选取的列是数据的视图,而不是拷贝.因此,对Serise的修改会映射到DataFrame中!!
■ 查看DataFrame对象 
  df1.values  df1.columns  df1.index  df1.shape  df1.size
  df1.head(2)
  df1.tail(2)
  df.info()  # 可以通过它判定某列有没有空值
  df.describe()
■ Bool值充当索引 -- 用法跟numpy二维数组一模一样!!
  data[data['three']>5]  里面是一维的,取符合条件的行
  data[data<5] = 0 里面是二维的,修改值       
■ DataFrame对象的索引和切片iloc、loc的用法跟二维的numpy对象差不多. (索引列表的情况有些许区别.
  DataFrame中所说的降维是得到一个Serise对象.
  iloc适配下标索引,loc适配显式索引,并且loc中使用显式索引切片是包含最后一个的!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# Series

Series是一种类似与一维数组的对象, 由三个部分组成: values 和 index 和 dtype.
-1- values: 一组数据.
-2- index: 相关的数据的 索引/标签
-3- dtype: 值的类型

# 创建方式

有三种创建方式: 列表 、numpy数组 、字典

image-20240805180114532

注意点1: series里的成员的类型会自动统一. 注 - 下方示例中, 此处的object指代的是字符串. 但并不是说 object就只能是字符串哦!

>>> import pandas as pd
>>> pd.Series(data=[1,2,'three',4])
0        1
1        2
2    three
3        4
dtype: object
>>> pd.Series(data=['hello','world'])
0    hello
1    world
dtype: object
1
2
3
4
5
6
7
8
9
10
11

注意点2: 不可以将二维的数据源存放在series这个一维的数据结构中. 会报错!

>>> import pandas as pd
>>> pd.Series(data=[[1,2,3],[4,5,6]])
0    [1, 2, 3]
1    [4, 5, 6]
dtype: object
>>> pd.Series(data=np.random.randint(0,100,size=(2,3)))
ValueError: Data must be 1-dimensional, got ndarray of shape (2, 3) instead  # 报错啦!!
1
2
3
4
5
6
7

# 显式和隐式索引

隐式索引- 默认形式的索引 (0, 1, 2....) 显式索引有两种方式实现 - data数据源传字典 、通过index参数设置

显示索引的作用: 增加了数据的可读性

>>> import pandas as pd
>>> pd.Series(data={'name':'bobo','age':20})
name    bobo
age       20
dtype: object
>>> pd.Series(data=['bobo',20],index=['name','age'])
name    bobo
age       20
dtype: object
>>> pd.Series(data=['bobo',20])
0    bobo
1      20
dtype: object
1
2
3
4
5
6
7
8
9
10
11
12
13

# 索引和切片

-1- 隐式索引一直存在, 显式索引不会覆盖它.
-2- [只有] 显示索引的方式 才能使用 "." 点机制.
-3- Series的切片和列表的切片一样. 😃

-4- 可以使用布尔值充当Series的索引来使用

>>> import pandas as pd
>>> s4 = pd.Series(data=[97,80,90],index=['语文','数学','英语'])
>>> s4
语文    97
数学    80
英语    90
dtype: int64
>>> s4[1:]
数学    80
英语    90
dtype: int64
>>> s4['语文']
np.int64(97)
>>> s4[0]
np.int64(97)
>>> s4.语文
np.int64(97)
>>>
>>>
>>> s4[[True,False,True]]
语文    97
英语    90
dtype: int64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 常用属性

属性 含义
s4.shape Series对象的形状
s4.size Series对象的长度
s4.index Series对象的索引 (优先显示显式索引,没有则显示隐式索引)
s4.values Series对象的数据值

测试一下下:

>>> import pandas as pd
>>> s4 = pd.Series(data=[97,80,90],index=['语文','数学','英语'])
>>> s4.shape
(3,)
>>> s4.size
3
>>> s4.index
Index(['语文', '数学', '英语'], dtype='object')
>>> s4.values
array([97, 80, 90])
>>>
>>>
>>> s1 = pd.Series(data=[[1,2,3],[4,5,6]])
>>> s1
0    [1, 2, 3]
1    [4, 5, 6]
dtype: object
>>> s1.shape
(2,)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 常用方法

方法 含义
s4.head(2) 查看前n个元素 (默认前5)
s4.tail(2) 查看后n个元素 (默认后5)
s4.unique() 返回去重后的结果, 并将值放到了一个numpy对象中
s4.nunique() 返回去重后元素的个数
s4.value_counts() 返回元素出现的次数
s4.isnull() 会对series对象中的每个成员都进行空值判定
s4.notnull() 会对series对象中的每个成员都进行非空判定
add() sub() mul() div() 加减乘除, 作用于每一个成员, 返回的是新的, 不影响原series对象

测试一下下:

>>> import pandas as pd
>>> s4 = pd.Series(data=np.random.randint(90,100,size=(6,)))
>>> s4
0    93
1    97
2    96
3    90
4    97
5    93
dtype: int64
>>> s4.head(2)
0    93
1    97
dtype: int64
>>> s4.tail(2)
4    97
5    93
dtype: int64
>>> s4.unique()
array([93, 97, 96, 90])
>>> s4.nunique()
4
>>> s4.value_counts()
93    2
97    2
96    1
90    1
Name: count, dtype: int64
>>> s4.add(2)  # 等同于 s4 + 2
0    95
1    99
2    98
3    92
4    99
5    95
dtype: int64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 运算法则

★运算法则: 两个Series对象进行算数运算时, 只有索引一致的元素可以进行算数运算, 否则补空.
(´・Д・)」 NaN 表示为空.

>>> s1 = pd.Series(data=[1,2,3],index=['a','b','c'])
>>> s2 = pd.Series(data=[1,2,3],index=['a','d','c'])
>>> s3 = s1 + s2
>>> s3
a    2.0
b    NaN
c    6.0
d    NaN
dtype: float64
>>>
>>>
>>> # Q:若一个Series对象有几万个成员,为了过滤空值,手写几万个True和False?
>>> # A:NO!解决方案 - 布尔值充当Series的索引 + isnull方法
>>> s3.isnull()
a    False
b     True
c    False
d     True
dtype: bool
>>> s3.notnull()
a     True
b    False
c     True
d    False
dtype: bool
>>> s3[s3.notnull()]  # 成功过滤空值
a    2.0
c    6.0
dtype: float64
>>> s3[s3.isnull()]  # 成功保留空值 Hhh
b   NaN
d   NaN
dtype: float64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# DataFrame - 基本

DataFrame是一个 [表格型] 的数据结构.
DataFrame由按一定顺序排列的多列数据组成. 设计初衷是将Series的使用场景从一维拓展到多维.
DataFrame由三部分组成 行索引 index + 列索引 columns + 值 values.

# 创建方式

和Series对象一样, 有三种创建方式: 列表 、numpy数组 、字典

image-20240805210031699

一点小补充:

>>> dic = {'张三':{"语文":90,"数学":88,"英语":61,"理综":50},"李四":{"语文":92,"数学":83,"英语":66,"理综":70}}
>>> pd.DataFrame(data=dic)
    张三  李四
语文  90  92
数学  88  83
英语  61  66
理综  50  70
1
2
3
4
5
6
7

# 常用属性

常用的有五个 values、columns、index、shape、size

>>> import pandas as pd
>>> df1 = pd.DataFrame(data=[[1,2],[3,4]],index=('A','B'),columns=['a','b'])
>>> df1
   a  b
A  1  2
B  3  4
>>> df1.values
array([[1, 2],
       [3, 4]])
>>> df1.columns
Index(['a', 'b'], dtype='object')  # 这里的object表明列索引是字符串类型
>>> df1.index
Index(['A', 'B'], dtype='object')
>>> df1.shape
(2, 2)
>>> df1.size
4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 数据查看

查看DataFrame的概览和统计信息

>>> import numpy as np
>>> import pandas as pd
>>> # 创建 shape(150,3)的二维标签数组结构DataFrame
>>> df = pd.DataFrame(data = np.random.randint(
             0,151,
             size = (150,3)),
             index = None,  # 行索引默认
             columns=['Python','Math','En'])
>>> df.head(2)  # 显示头部2行,默认5个
   Python  Math   En
0      77    78  115
1       6    10   20
>>> df.tail(2)  # 显示末尾2行,默认5个
     Python  Math   En
140     101   117  141
141     132    44   12
>>> df.info()  # 查看列索引、数据类型、非空计数和内存信息
<class 'pandas.core.frame.DataFrame'>  # 数据表格的数据结构
RangeIndex: 150 entries, 0 to 149      # 行信息 150行 行索引0-149
Data columns (total 3 columns):        # 列信息 一共有3列
 #   Column  Non-Null Count  Dtype     # 列具体信息 non-null表示每一列非空元素的个数
---  ------  --------------  -----     # ★ 若该列的non-null个数等于行数,那么该列就没有空值!
 0   Python  150 non-null    int64
 1   Math    150 non-null    int64
 2   En      150 non-null    int64
dtypes: int64(3)                       # 3列数据的数据类型都是int64
memory usage: 3.6 KB                   # 所占空间大小
>>> # 若是数值型列,它返回的统计指标 - 计数、平均值、标准差、最小值、四分位数、最大值
>>> df.describe()  
           Python        Math          En
count  150.000000  150.000000  150.000000
mean    79.086667   74.760000   68.753333
std     42.817380   43.259119   43.206999
min      1.000000    0.000000    0.000000
25%     43.000000   38.250000   30.750000
50%     80.000000   75.500000   69.000000
75%    111.750000  114.750000  102.750000
max    148.000000  148.000000  148.000000
>>> # 若是非数值型列,它返回统计指标 - count非空元素个数;unique元素去重后的个数;top出现频率最高的元素;freq最大频率
>>> df = pd.DataFrame(data=[['a','b','c','d'],['小米','oppo','华为','华为']]).T
>>> df
   0     1
0  a    小米
1  b    oppo
2  c    华为
3  d    华为
>>> df.describe()
        0   1
count   4   4
unique  4   3
top     a  华为
freq    1   2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 数据保存与加载

此处先简单讲解csv、excel的使用, sql、hdf5 暂略.

# CSV

image-20240806151852116

测试代码如下:

import numpy as np
import pandas as pd

df = pd.DataFrame(
    data=np.random.randint(0, 50, size=(3, 5)),  # 薪资情况
    columns=['IT', '化工', '生物', '教师', '士兵']
)
print(df)

df.to_csv('./salary.csv',
          sep=';',  # 文本分隔符,默认是逗号
          header=True,  # 是否保存列索引
          index=True)  # 是否保存行索引

res = pd.read_csv('./salary.csv', sep=';')
print(res)

res = pd.read_csv('./salary.csv', sep=';', header=[0], index_col=0)
print(res)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Excel

准备工作,安装几个python库:
pip install xlrd -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple

image-20240806153822637

测试代码如下:

import numpy as np
import pandas as pd

df1 = pd.DataFrame(
    data=np.random.randint(0, 50, size=(3, 5)),
    columns=['IT', '化工', '生物', '教师', '士兵']
)
print(df1)

df1.to_excel('./salary.xlsx',
             sheet_name='salary',  # Excel中工作表的名字
             header=True,  # 是否保存列索引
             index=False)  # 是否保存行索引

res = pd.read_excel('./salary.xlsx',
                    sheet_name=0,  # 读取哪一个Excel中工作表,默认第一个
                    header=0)  # 使用第一行数据作为列索引,默认就是第一行
print(res)

res = pd.read_excel('./salary.xlsx',
                    sheet_name=0,
                    header=0,
                    names=list('ABCDE'))  # 替换列索引
print(res)

res = pd.read_excel('./salary.xlsx',
                    sheet_name=0,
                    header=0,
                    names=list('ABC'))
print(res)

res = pd.read_excel('./salary.xlsx',
                    sheet_name=0,
                    header=0,
                    names=list('ABCD'),
                    index_col=1)  # 指定行索引
print(res)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# DataFrame - 切片和索引

DataFrame的索引和切片,你我都可能会感觉到别扭,那没办法,开发者就是这样设定的. (・_・;

>>> df1 = pd.DataFrame(data=np.random.randint(0,100,size=(5,4)),
                       index=['a','b','c','d','e'],columns=['A','B','C','D'])
1
2

image-20240805220527476

PS: 切记 - df['A'] 、df[0] 若df表格中存在显式的列索引, 那么就无法使用隐式列索引进行取值.

# ※ iloc - 结果类型

# iloc里有两元素

★ iloc的使用, 它是有规律可寻的.

iloc里可有两个元素, df1.iloc[元素1,元素2], 第一个元素行相关, 第二个元素列相关.
而元素的呈现形式可有三种, 其1是列表,列表里写索引、其2是 切片、其3是 单个索引.
这三种呈现形式可以 混用 (比如元素1我使用列表索引, 元素2我使用切片.. ), 不同的搭配, 混用的结果是不同的:

这三种形式两两组合,以及各自于各自组合,共6种情况:

结果的数据类型格式 举例
列表索引&切片 DataFrame df1.iloc[[1,3],:2]
列表索引&单个索引 Series df1.iloc[[1,2,3],1]
切片&单个索引 Series df1.iloc[1:-1,1]
列表索引&列表索引 DataFrame df1.iloc[[1,3],[0,1]]
切片&切片 DataFrame df1.iloc[:2,:-2]
单个索引&单个索引 单个值 df1.iloc[2,3]

Ps: df1.iloc[[1,3],[0,1]] 这跟numpy那,arr2d[np.ix_([0,2],[1,4])]取一个方形区域交点的元素一样的道理

根据上方的表格, 我们可以简单总结出: (单个索引&单个索引的组合除外)
■ 只要元素的形式不含单个元素, 那么结果就是DataFrame对象
■ 只要有一个元素的形式是单个索引, 那么结果就是Series对象
是不是很有意思amazing啊. (*≧ω≦)

# iloc里只有一个元素

iloc中只有一个元素时, 相当于列全选.. 该元素代表的是行,同样的,有三种形式 列表索引、切片、单个索引

df1.iloc[[2,3]] 、df1.iloc[:2] -- 结果的数据类型是DataFrame
df1.iloc[2] -- 结果的数据类型是 Series

# ※ iloc - 实用性需求

前面我们是根据结果的数据结构类型进行的思考, 现在我们要根据实用性需求的角度进行思考.
首先, 明确 iloc里元素的三种形式 列表索引、切片、单个索引.

# 取多行多列

思考 - 取行, 列拉满 ; 取行, 列拉满 ; 取连续的多行或多列可用切片、取不连续的多行或多列可用列表索引

>>> df1.iloc[:3,:]  # 取连续的多行 ★可简写成df1.iloc[:3]
    A   B   C   D
a  75  80  98  56
b  10  69  78  48
c  42  52  51  52
>>> df1.iloc[:,:3]  # 取连续的多列
    A   B   C
a  75  80  98
b  10  69  78
c  42  52  51
d  63  95  58
e   7  69  87
>>> df1.iloc[[1,3],:]  # 取不连续的多行  ★可简写成df1.iloc[[1,3]]
    A   B   C   D
b  10  69  78  48
d  63  95  58  67
>>> df1.iloc[:,[1,3]]  # 取不连续的多列
    B   D
a  80  56
b  69  48
c  52  52
d  95  67
e  69  91
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 取某一行某一列
>>> df1.iloc[[1],:]  # 取第2行,结果为DataFrame  ★可简写成df1.iloc[[1]]
    A   B   C   D
b  10  69  78  48
>>> df1.iloc[1,:]  # 取第2行,结果为Serise  ★可简写为df1.iloc[1]
A    10
B    69
C    78
D    48
Name: b, dtype: int64
>>> df1.iloc[:,[1]]  # 取第2列,结果为DataFrame
    B
a  80
b  69
c  52
d  95
e  69
>>> df1.iloc[:,1]  # 取第2列,结果为Serise
a    80
b    69
c    52
d    95
e    69
Name: B, dtype: int64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 取单个成员
>>> df1.iloc[2,3]
np.int64(52)
1
2
# 取多个成员
>>> df1.iloc[[1,3],[0,1]]  # 取一个方形区域交点的元素,原理跟numpy那,arr2d[np.ix_([0,2],[1,4])]一样
    A   C
b  10  78
d  63  58
>>> df1.iloc[[1,2,3],[2]]  # 取第3列的2,3,4位置的成员 - 结果为DataFrame
    C
b  78
c  51
d  58
>>> df1.iloc[[1,2,3],2]  # 取第3列的2,3,4位置的成员 - 结果为Serise
b    78
c    51
d    58
Name: C, dtype: int64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 取一个区域
>>> df1.iloc[1:-1,1:-1]  # 取一个区域里所有的成员
    B   C
b  69  78
c  52  51
d  95  58
1
2
3
4
5

# 当有显式索引时

当有显示索引时, 还可以通过显式索引取值! 举几个例子: (规律啥的不想总结了,看例子悟吧,累了)

>>> df1['A']  # 取单列
a    75
b    10
c    42
d    63
e     7
Name: A, dtype: int64
>>> df1[['A','C']]  # 取多列
    A   C
a  75  98
b  10  78
c  42  51
d  63  58
e   7  87
>>> df1.loc['a']  # 取单行
A    75
B    80
C    98
D    56
Name: a, dtype: int64
>>> df1.loc[['a','c']]  # 取多行
    A   B   C   D
a  75  80  98  56
c  42  52  51  52
>>> df1.loc['a','C']  # 取单个成员
np.int64(98)
>>> df1.loc['b',['A','B','C']]  # 取多个成员
A    10
B    69
C    78
Name: b, dtype: int64
>>> df1.loc[:,'A':'C']  # 切列
    A   B   C
a  75  80  98
b  10  69  78
c  42  52  51
d  63  95  58
e   7  69  87
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 股票分析案例

环境: python3.9.8 ; numpy 1.26.4 ; pandas 1.5.3 ; tushare 1.4.7

# 准备工作

1> 从接口获取股票数据,并以csv形式保存到本地.

import ssl

import pandas as pd
import tushare as ts

ssl._create_default_https_context = ssl._create_unverified_context

stock_code = '000001'  # 股票代码:平安银行
start_date = '2021-01-01'  # 开始日期
end_date = '2023-2-12'  # 结束日期

# 获取股票历史交易数据
df = ts.get_k_data(code=stock_code, start=start_date, end=end_date)
print(df)

df.to_csv('./gupiao.csv')  # 默认是保存行索引和列索引的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

2> 对数据进行一点处理

import pandas as pd

""" 等同于效果index_col=0
df = pd.read_csv('./gupiao.csv')
df.drop(labels='Unnamed: 0', axis=1, inplace=True)  # axis=0表示的行 1表示的是列
"""
# type(df['date']) --> Series ; df['date'].dtypes --> object
df = pd.read_csv('./gupiao.csv', index_col=0)
# 转换后 df['date'].dtypes --> datetime64[ns]
df['date'] = pd.to_datetime(df['date'])  # 将日期列转换为日期类型,便于时间类型数据的运算
df.set_index('date', inplace=True)  # 将date列作为原数据的行索引,不用默认的0 1 2.
print(df)
1
2
3
4
5
6
7
8
9
10
11
12

至此,我们得到的数据长这样:

              open   close    high     low     volume  code
date                                                       
2021-01-04  17.688  17.188  17.688  17.028  1554216.0     1
2021-01-05  16.988  16.758  17.068  16.388  1821352.0     1
2021-01-06  16.668  18.148  18.148  16.588  1934945.0     1
2021-01-07  18.108  18.488  18.568  17.818  1584185.0     1
2021-01-08  18.488  18.438  18.688  17.898  1195473.0     1
...            ...     ...     ...     ...        ...   ...
2023-12-25   8.461   8.471   8.481   8.421   413971.0     1
2023-12-26   8.471   8.381   8.481   8.351   541896.0     1
2023-12-27   8.381   8.401   8.411   8.301   641534.0     1
2023-12-28   8.391   8.731   8.751   8.361  1661592.0     1
2023-12-29   8.701   8.671   8.761   8.631   853853.0     1

[727 rows x 6 columns]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 收益率和波动率

Q: 计算股票的每日收益率和7日波动率: 通过计算收益率和波动率, 我们可以评估股票的风险和收益情况.

每日收益率: (当日收盘价 - 前一日的收盘价) / 前一日的收盘价.
7日波动率: 对 每日收益率 数据进行每7日滚动的方差计算

image-20240806175205887

代码如下:

# (df['close'] - df['close'].shift(1)) / df['close'].shift(1) * 100
return_rate = df['close'].pct_change() * 100  # 收益率
volatility_rate = return_rate.rolling(window=7).std()  # 波动率
print(volatility_rate.head(10))
1
2
3
4

# 最大和最小

Q: 查找股票的市值最大和最小日

# 市值 = 收盘价 * 成交量
market_value = df['close'] * df['volume']  # type(market_value) --> Series
# 找出市值数据中最大最小值下标(市值最大和最小日期)max()求的是最大值,idxmax求的是最大值的索引/下标
max_market_value_day = market_value.idxmax()
min_market_value_day = market_value.idxmin()

print(max_market_value_day)
print(min_market_value_day)
1
2
3
4
5
6
7
8

# 开盘和收盘

Q1: 输出该股票所有收盘比开盘上涨3%以上的日期

方案一

ex = ((df['close'] - df['open']) / df['open'])  > 0.03
print(ex)
print(ex[ex].index)  # ★ ps:ex[~ex] 取false

"""
date
2021-01-04    False
2021-01-05    False
2021-01-06     True
2021-01-07    False
2021-01-08    False
              ...  
2023-12-25    False
2023-12-26    False
2023-12-27    False
2023-12-28     True
2023-12-29    False
Length: 727, dtype: bool
"""
"""
DatetimeIndex(['2021-01-06', '2021-01-12', '2021-01-18', '2021-01-25',
               '2021-01-27', '2021-02-01', '2021-02-03', '2021-03-03',
               '2021-03-11', '2021-03-22', '2021-04-19', '2021-04-20',
               '2021-04-21', '2021-05-25', '2021-07-06', '2021-07-15',
               '2021-08-09', '2021-08-10', '2021-08-18', '2021-09-06',
               '2021-09-07', '2021-09-10', '2021-09-28', '2021-10-15',
               '2021-11-11', '2022-01-05', '2022-01-20', '2022-02-08',
               '2022-03-10', '2022-03-11', '2022-03-16', '2022-03-22',
               '2022-04-06', '2022-04-15', '2022-04-27', '2022-06-14',
               '2022-06-15', '2022-08-31', '2022-11-01', '2022-11-04',
               '2022-11-22', '2022-11-25', '2022-11-29', '2022-12-05',
               '2023-01-03', '2023-01-04', '2023-02-20', '2023-05-08',
               '2023-07-28', '2023-08-03', '2023-12-28'],
              dtype='datetime64[ns]', name='date', freq=None)
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

方案二

# 获取了True对应的行数据: 就是满足需求的行数据
df.loc[((df['close'] - df['open']) / df['open'])  > 0.03]
# 基于index获取满足需求行数据的行索引
df.loc[((df['close'] - df['open']) / df['open'])  > 0.03].index
1
2
3
4

Q2: 输出该股票所有开盘比前日收盘跌幅超过2%的日期

"""方案一"""
ex = ((df['open']-df['close'].shift(1))/df['close'].shift(1)) < -0.02
ex[ex].index

"""方案二"""
((df['open']-df['close'].shift(1))/df['close'].shift(1)) < -0.02  #(开盘-前日收盘)/前日收盘 < -0.02
df.loc[((df['open']-df['close'].shift(1))/df['close'].shift(1)) < -0.02].index
1
2
3
4
5
6
7

# 算收益

Q: 假如张三从2021年1月1日开始, 每月第一个交易日买入1手股票, 每年最后一个交易日卖出所有股票, 到2023-2-12, 收益如何?
分析: 1手股票等于100只股票,一个完整年要买12手,那就是1200只股票.
最后一年2023就是一个特殊的年, 因为每年的最后一天才卖, 但最后一年所买所花费的钱是需要计算到总收益中。

# print(df['2021':'2023'])
cost = df.resample('M').first()['open'].sum() * 100
print(cost)  # 51961.399999999994
recv = df.resample('A').last()[:-1]['open'].sum()*1200
print(recv)  # 33196.8
1
2
3
4
5

解释:

df是DataFrame的表格型数据. 该df的行索引是日期类型!!
首先我们可以通过df.resample('M')进行分组, (H小时、W星期、M月、A年等)
.first取出每组的第一行数据; .last取出每组的最后一行数据.
So, df.resample('M').first() 还是DataFrame对象
接着,df.resample('M').first()['open']取出open这一列,得到的是一个Series对象. 最后,进行sum运算.

df.resample('A').last()[:-1] 进行[:-1]操作,最后一行不要!!

PS: 因为该df的行索引是日期类型,所以还可以根据年来进行切片. 
    df['2021':'2023'] 整个数据集就只包含2021年到2023年的,所以切了个寂寞.
1
2
3
4
5
6
7
8
9
10

# 计算均线

Q: 计算该股票历史数据的5日均线和30日均线

对于每一个交易日, 都可以计算出前N天的移动平均值, 然后把这些移动平均值连起来, 成为一条线就叫做N日移动平均线.
移动平均线常用线有5天、10天、30天、60天、120天和240天的指标.
-1- 5天和10天的是短线操作的参照指标, 称做日均线指标;
-2- 30天和60天的是中期均线指标, 称做季均线指标;
-3- 120天和240天的是长期均线指标, 称做年均线指标.

ma5 = df['close'].rolling(5).mean()
ma30 = df['close'].rolling(30).mean()

# 将均线两列添加到原始数据中
df['ma5'] = ma5
df['ma30'] = ma30

# info看ma30、和ma5列有多少行的Nan值,然后将这些包含Nan值的行剔除掉!
print(df.info())
print(df.iloc[29:])

# To do: 利用matplotlib.pyplot画均值曲线,暂略.
1
2
3
4
5
6
7
8
9
10
11
12

# ★ 案例知识点汇总

★★★ 学会的新知识点:
■
df.to_csv('./gupiao.csv')  # 默认是保存行索引和列索引的
■
df = pd.read_csv('./gupiao.csv', index_col=0)
的平替
df = pd.read_csv('./gupiao.csv')
★★★ df.drop(labels='Unnamed: 0', axis=1, inplace=True)
■
df['date'] = pd.to_datetime(df['date'])  # 将日期列转换为日期类型,便于时间类型数据的运算
df.set_index('date', inplace=True)  # 将date列作为原数据的行索引,不用默认的0 1 2.
■
(df['close'] - df['close'].shift(1)) / df['close'].shift(1)
等同于
df['close'].pct_change()
■
Serise对象.shift(1)
Serise对象.rolling(window=7)
Serise对象.std()
Serise对象 * Serise对象
Serise对象.max()
Serise对象.min()
Serise对象.idxmax()
Serise对象.idxmin()
Serise对象 > 0.03  # 结果是包含True、False的Serise对象
S4[S4 > 0.03 ]
S4[~(S4 > 0.03)]

df.loc[((df['close'] - df['open']) / df['open'])  > 0.03]  # 获取了True对应的行数据: 就是满足需求的行数据
--> ★★★ 解释下: df.loc[True和False组成的Serise对象] -- 保留True值对应的行!
    其实可以直接 df[((df['close'] - df['open']) / df['open'])  > 0.03] 一样的效果.
df.resample('A').last()[:-1]  # 前提:dataframe的行索引是时间类型

df1.iloc[[True,True,False,False,True]]
df1.loc[[True,True,False,False,True]]
df1[[True,True,False,False,True]]
这三者是一样的效果.
注意: 
  iloc接受有返回值的函数作为参数,但要保证函数返回的是整数/整数list,布尔值/布尔list.
  So,若是bool值的Serise对象,iloc不行,loc可以.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

numpy
pandas数据清洗

← numpy pandas数据清洗→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式