从头到尾都是手码的,文中的所有示例也都是在Pycharm中运行过的,自己整理笔记的最大好处在于可以按照自己的思路来构建框架,等到将来在需要的时候能够以最快的速度看懂并应用=_=

注:为方便表述,本章设s为pandas.core.series.Series的一个实例化对象,设df为pandas.core.frame.DataFrame的一个实例化对象

1. Pandas简介

Pandas是基于NumPy的python数据分析库,最初被作为金融数据分析工具而开发出来,因此Pandas为时间序列分析提供了很好的支持。 Pandas的名称来自于面板数据(panel data)和python数据分析(data analysis)。panel data是经济学中关于多维数据集的一个术语,在Pandas中也提供了Panel的数据类型(注:在最新版本的Pandas中已将该数据类型删除)。

官网:https://pandas.pydata.org/

Pandas是构建在Numpy的基础上的,所以我们在加载pandas之前,最好先把Numpy也加载进来:

  1. import numpy as np
  2. import pandas as pd

2. Pandas中的三大数据类型

在Pandas中有下面三种数据结构:Series、DataFrame、Panel。

数据结构 维数 说明
Series 1
Dataframe 2 是Series的容器
Panel 3 是Dataframe的容器(注:在最新版本的Pandas中已将Panel数据类型删除)

3. Series

Series具有一维的数据结构,它拥有一列index和一列values,每个Series都是pandas.core.series.Series的一个实例化对象。

本节仅讨论具有一维index结构的Series,关于具有多维index结构的Series,见本章“13.层次化索引”

(1)创建Series

语法:pd.Series(data=None, index=None, dtype=None, name=None)

参数:

  • data:数据,它可以是一维list、dict、range()或一维numpy.ndarray。data的默认值为None,此时会创建一个空的Series([])

  • index:索引,默认值为None(当data为非dict类型时,默认索引为0、1、2……;当data为dict类型时,默认索引为dict的键)

    可以使用一个list、tuple、range()或numpy.ndarray自定义索引。注意:

    ① index长度必须与data长度相等,否则报错;

    ② 当data为dict类型时,不可以再使用自定义index,否则自定义index不仅会覆盖掉字典的键,还会让Series的所有值变为NaN

    ③ 默认的index(0、1、2……)称为position(位置),自定义的index称为label(标签)。未定义index时,只能通过position取值;定义index后,既可以通过position取值,也可以通过label取值。

    ④ 本节仅讨论具有一维index结构的Series,关于具有多维index结构的Series,见本章“13.层次化索引”

  • dtype:数据类型

  • name:Series的名字

注意:和DataFrame不同,Series没有columns参数!

  1. # 通过list和numpy.ndarray创建Series
  2. import numpy as np
  3. import pandas as pd
  4. s1 = pd.Series([1,2,3])
  5. s2 = pd.Series(np.array([1,2,3]), index=['a','b','c'], name='MySeries')
  6. print(s1); print('===========')
  7. print(type(s1)); print('===========')
  8. print(s2); print('===========')
  9. print(type(s2))
  10. 执行结果:
  11. 0 1
  12. 1 2
  13. 2 3
  14. dtype: int64
  15. ===========
  16. <class 'pandas.core.series.Series'>
  17. ===========
  18. a 1
  19. b 2
  20. c 3
  21. Name: MySeries, dtype: int32
  22. ===========
  23. <class 'pandas.core.series.Series'>
  1. # 通过dict创建Series
  2. import numpy as np
  3. import pandas as pd
  4. s1 = pd.Series({'a':1,'b':2,'c':3})
  5. s2 = pd.Series({'a':1,'b':2,'c':3}, index=['A','B','C']) # 错误的定义方式
  6. print(s1); print('===========')
  7. print(type(s1)); print('===========')
  8. print(s2); print('===========')
  9. print(type(s2))
  10. 执行结果:
  11. a 1
  12. b 2
  13. c 3
  14. dtype: int64
  15. ===========
  16. <class 'pandas.core.series.Series'>
  17. ===========
  18. A NaN
  19. B NaN
  20. C NaN
  21. dtype: float64
  22. ===========
  23. <class 'pandas.core.series.Series'>

(2)Series的向量化和广播

① 向量化: Series与一维对象进行计算

这个计算有个前提,即一维对象的长度等于Series的长度,该一维对象可以是list, numpy.ndarray……在满足这个前提的情况下(不满足则报错),会进行元素级操作,相同位置的元素按照某种运算规则进行运算,并返回一个与原Series索引相同、相同长度的Series

  1. import numpy as np
  2. import pandas as pd
  3. s = pd.Series([10,11,12],index=['a','b','c'])
  4. arr = np.array([9,11,13])
  5. print(s + arr)
  6. print('===========')
  7. print(s > arr)
  8. 执行结果:
  9. a 19
  10. b 22
  11. c 25
  12. dtype: int64
  13. ===========
  14. a True
  15. b False
  16. c False
  17. dtype: bool

② 广播:Series与数字进行计算

对于Series与数字进行的+、-、*、/、**、//、%、>、<、>=、<=、==、!=等运算,会将这个Series中的每一个值均与这个数字进行计算,并用这些结果组成一个与原Series结构相同的Series

  1. import numpy as np
  2. import pandas as pd
  3. s = pd.Series([10,11,12],index=['a','b','c'])
  4. print(s+2)
  5. print('===========')
  6. print(s>11)
  7. 执行结果:
  8. a 12
  9. b 13
  10. c 14
  11. dtype: int64
  12. ===========
  13. a False
  14. b False
  15. c True
  16. dtype: bool

③ Series与多维对象进行计算(不支持)

Series不支持与多维对象进行计算,即一个多维numpy.ndarray不支持Series对其进行广播

  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[9,11,13],[8,15,10],[7,6,16]])
  4. s = pd.Series([10,11,12])
  5. print(arr + s)
  6. print(arr > s)
  7. 执行结果:报错

(3)Series的索引和切片

s[0]:基于position(位置)的索引

s['a']:基于label(标签)的索引

s[1:3]:基于position的切片,顾前不顾后

s['b':'d']:基于label的切片,前后都包含

s[s>5]:先通过广播获得值为bool的Series,然后再筛选其中值为True的项构建新的Series(类似布尔值索引)

s[[3,1,2]]、s[['e','b','d']]:通过list实现不连续索引(类似花式索引)

s.loc[]:与df.loc[]用法相似

s.iloc[]:与df.iloc[]用法相似

  1. import numpy as np
  2. import pandas as pd
  3. s = pd.Series(range(10,15),index=['a','b','c','d','e'])
  4. print(s); print('===========')
  5. print(s[2]); print('===========')
  6. print(s['c']); print('===========')
  7. print(s[1:3]); print('===========') # 顾前不顾后
  8. print(s['b':'d']); print('===========') # 前后都包含
  9. print(s[s>12]); print('===========')
  10. print(s[[3,1,2]]); print('===========')
  11. print(s[['e','b','d']])
  12. 执行结果:
  13. a 10
  14. b 11
  15. c 12
  16. d 13
  17. e 14
  18. dtype: int64
  19. ===========
  20. 12
  21. ===========
  22. 12
  23. ===========
  24. b 11
  25. c 12
  26. dtype: int64
  27. ===========
  28. b 11
  29. c 12
  30. d 13
  31. dtype: int64
  32. ===========
  33. d 13
  34. e 14
  35. dtype: int64
  36. ===========
  37. d 13
  38. b 11
  39. c 12
  40. dtype: int64
  41. ===========
  42. e 14
  43. b 11
  44. d 13
  45. dtype: int64

(4)Series的常用属性

注意:Series没有columns属性!

s.values:返回Series的所有值,数据类型为numpy.ndarray

s.index:返回Series的所有索引,数据类型为pandas.core.indexes.base.Index

s.name:Series的名字(可以赋值修改)

s.index.name:索引的名字(可以赋值修改)

(5)Series的常用方法

s.__len__()len(s):返回s的长度(int类型)

s.apply(func)s.map(func):将s中的每个元素分别传递给func作为其参数并执行func(),并将每次func()的返回值组成一个结构相同的新的Series,作为s.apply()或s.map()整体的返回值。代码示例见下面例2。所有apply()、applymap()、map()的对比见本章“二、Pandas模块 - 10. DataFrame对象的方法和Pandas模块的方法 - (5)其他重要方法 - ② df.applymap()

s1.corr(s2):计算两个Series的Pearson相关系数,返回一个float

s1.cov(s2):计算两个Series的协方差,返回一个float

s.dropna():删除s中的NaN

s.head(n):返回s的至多前n项索引与值组成的Series,n默认为5。此方法用于快速预览,不会修改s本身

s.idxmin()s.idxmax():反查s中最小值(最大值)所对应的索引。注意:s.argmin()和s.argmax()两个方法已弃用

s.isin(list):判断s中的每个元素是否在list中,返回一个与s结构相同但是由布尔值组成的Series

s.isna()s.isnull():与df.isna()和df.isnull()类似

s.notna():与df.notna()类似

s.ptp():计算s的极差(最大值减最小值),返回float(注意:DataFrame无此方法!)

s.replace('替换前的值','替换后的值',inplace=False):将s中的值进行替换,当同时进行多个替换时,可以使用字典将替换前的值、替换后的值组成键值对,即s.replace({'旧1':'新1','旧2':'新2'...},inplace=False)

s.sort_values():按值进行排序,类比df.sort_values(),由于Series只有一列,所以不用输入by=

s.str.字符串方法():将s中的每个字符串按照指定的方法进行处理并组成一个新的Series,代码示例见下面例3

s.tail(n):返回s的至多后n项索引与值组成的Series,n默认为5。此方法用于快速预览,不会修改s本身

s.tolist():将s转换为list格式(不直接修改s,须定义一个变量来接收)(注意:DataFrame无此方法!)

s.unstack():对层次化索引的Series进行变形(行标签与列标签的转换),详见本章“13.层次化索引 - (3)使用unstack()和stack()和DataFrame对层次化索引的Series进行变形(行标签与列标签的转换)”

s.value_counts():统计s中的每个值出现的次数,返回一个Series(注意:numpy.ndarray和DataFrame都无此方法!)

s.var():计算Series的方差,返回一个float

  1. # 例1
  2. import numpy as np
  3. import pandas as pd
  4. s = pd.Series([10,12,11,11,12],index=['a','b','c','d','e'],name='旧名字')
  5. s.name='新名字'
  6. s.index.name = '索引'
  7. print(s); print('===========')
  8. print(s.values,type(s.values)); print('===========')
  9. print(s.index,type(s.index)); print('===========')
  10. print(s.name); print('===========')
  11. print(s.index.name); print('===========')
  12. print(s.head(2)); print('===========')
  13. print(s.tail(2)); print('===========')
  14. print(s.__len__(),len(s),type(len(s))); print('===========')
  15. print(s.tolist(),type(s.tolist())); print('===========')
  16. print(s.value_counts(),type(s.value_counts())); print('===========')
  17. print(s.isin([5,6,7,11,15,16,17]),type(s.isin([5,6,7,11,15,16,17]))); print('===========')
  18. print(s.ptp())
  19. 执行结果:
  20. 索引
  21. a 10
  22. b 12
  23. c 11
  24. d 11
  25. e 12
  26. Name: 新名字, dtype: int64
  27. ===========
  28. [10 12 11 11 12] <class 'numpy.ndarray'>
  29. ===========
  30. Index(['a', 'b', 'c', 'd', 'e'], dtype='object', name='索引') <class 'pandas.core.indexes.base.Index'>
  31. ===========
  32. 新名字
  33. ===========
  34. 索引
  35. ===========
  36. 索引
  37. a 10
  38. b 12
  39. Name: 新名字, dtype: int64
  40. ===========
  41. 索引
  42. d 11
  43. e 12
  44. Name: 新名字, dtype: int64
  45. ===========
  46. 5 5 <class 'int'>
  47. ===========
  48. [10, 12, 11, 11, 12] <class 'list'>
  49. ===========
  50. 12 2
  51. 11 2
  52. 10 1
  53. Name: 新名字, dtype: int64 <class 'pandas.core.series.Series'>
  54. ===========
  55. 索引
  56. a False
  57. b False
  58. c True
  59. d True
  60. e False
  61. Name: 新名字, dtype: bool <class 'pandas.core.series.Series'>
  62. ===========
  63. 2
  1. # 例2:Series.apply(func)和Series.map(func)
  2. import numpy as np
  3. import pandas as pd
  4. s1 = pd.Series([10,20,30], index=['t1','t2','t3'])
  5. s2 = s1.apply(lambda x:x+1)
  6. s3 = s1.map(lambda x:x+2)
  7. print(s1); print('===========')
  8. print(s2); print('===========')
  9. print(s3)
  10. 执行结果:
  11. t1 10
  12. t2 20
  13. t3 30
  14. dtype: int64
  15. ===========
  16. t1 11
  17. t2 21
  18. t3 31
  19. dtype: int64
  20. ===========
  21. t1 12
  22. t2 22
  23. t3 32
  24. dtype: int64
  1. # 例3:s.str.字符串方法()
  2. import numpy as np
  3. import pandas as pd
  4. s1 = pd.Series(['a_b','c_d'],index=['t1','t2'])
  5. s2 = s1.str.replace('_','')
  6. s3 = s1.str.startswith('a')
  7. print(s1); print('===========')
  8. print(s2); print('===========')
  9. print(s3)
  10. 执行结果:
  11. t1 a_b
  12. t2 c_d
  13. dtype: object
  14. ===========
  15. t1 ab
  16. t2 cd
  17. dtype: object
  18. ===========
  19. t1 True
  20. t2 False
  21. dtype: bool

4. DataFrame的创建

DataFrame具有二维的数据结构,它拥有一列index和若干列values,每个DataFrame都是pandas.core.frame.DataFrame的一个实例化对象。

本节仅讨论具有一维index结构的DataFrame,关于具有多维index结构的DataFrame,见本章“13.层次化索引”

语法:pd.DataFrame(data=None, index=None, columns=None, dtype=None)

参数:

  • data:数据,它可以是dict、一维或二维list、一维或二维numpy.ndarray。当data是一维list或一维numpy.ndarray时,pd.DataFrame()会将其变为一个2行1列的列向量(可参见本章“DataFrame对象的常用属性和方法部分的(4)df.shape中的例子”)。data的默认值为None,此时会创建一个空的DataFrame

  • index:行索引,默认值为None(默认行索引为0、1、2……)

    可以使用list自定义行索引,注意:

    ① index长度必须与data的行数相等,否则报错;

    ② 当data为dict类型时,不可以在pd.DataFrame()括号里自定义index,否则会让所有数据类型为Series的列的值都变为NaN。正确的方式有两种:一是在df定义完成后另写一行df.index=[...];二是在定义字典时值都用Series类型,并给每个Series都单独定义index=[...]

    ③ 默认的index(0、1、2……)称为position(位置),自定义的index称为label(标签)。未定义index时,只能通过position取值;定义index后,既可以通过position取值,也可以通过label取值。

    ④ 本节仅讨论具有一维index结构的DataFrame,关于具有多维index结构的DataFrame,见本章“13.层次化索引”

  • columns:列索引,默认值为None(当data为非dict类型时,默认列索引为0、1、2……;当data为dict类型时,默认列索引为dict的键)

    可以使用list自定义列索引,注意:

    ① columns长度必须与data的列数相等,否则报错;

    ② 当data为dict类型时,不可以在pd.DataFrame()括号里自定义columns,否则会清空整个DataFrame(见下面的错误演示)。由于dict的键已经作为columns了,因此不能再自定义columns。

    ③ 默认的columns(0、1、2……)称为position(位置),自定义的columns称为label(标签)。未定义columns时,只能通过position取值;定义columns后,既可以通过position取值,也可以通过label取值。

  • dtype:数据类型,值为'f'时表示float,值为'i'时表示int

注意:和Series不同,DataFrame没有name参数!

  1. # 通过list和numpy.ndarray创建DataFrame
  2. import numpy as np
  3. import pandas as pd
  4. li = [[44, 55, 66],[77, 88, 99]]
  5. df1 = pd.DataFrame(li,columns=['c1','c2','c3'],index=['t1','t2'])
  6. arr = np.array([[44, 55, 66],[77, 88, 99]])
  7. df2 = pd.DataFrame(arr,columns=['c1','c2','c3'],index = ['t1','t2'])
  8. print(df1); print('===========')
  9. print(df2); print('==========='); print(type(df2))
  10. 执行结果:
  11. c1 c2 c3
  12. t1 44 55 66
  13. t2 77 88 99
  14. ===========
  15. c1 c2 c3
  16. t1 44 55 66
  17. t2 77 88 99
  18. ===========
  19. <class 'pandas.core.frame.DataFrame'>
  1. # 通过dict创建DataFrame
  2. import numpy as np
  3. import pandas as pd
  4. dic1 = {
  5. 'A': [30,32],
  6. 'B': np.array([42,38]),
  7. 'C': pd.Series([55,56]),
  8. }
  9. dic2 = {
  10. 'A': pd.Series([30,32], index=['t1','t2']),
  11. 'B': pd.Series([42,38], index=['t1','t2']),
  12. 'C': pd.Series([55,56], index=['t1','t2']),
  13. }
  14. # 正确的创建方式一
  15. df1 = pd.DataFrame(dic1)
  16. df1.index=['t1','t2']
  17. # 正确的创建方式二
  18. df2 = pd.DataFrame(dic2)
  19. # 错误的创建方式三
  20. df3 = pd.DataFrame(dic1,index=['t1','t2'])
  21. # 错误的创建方式四
  22. df4 = pd.DataFrame(dic1,columns=['c1','c2'])
  23. print('正确的创建方式一\n',df1); print('===========')
  24. print('正确的创建方式二\n',df2); print('===========')
  25. print('错误的创建方式三\n',df3); print('===========')
  26. print('错误的创建方式四\n',df4)
  27. 执行结果:
  28. 正确的创建方式一
  29. A B C
  30. t1 30 42 55
  31. t2 32 38 56
  32. ===========
  33. 正确的创建方式二
  34. A B C
  35. t1 30 42 55
  36. t2 32 38 56
  37. ===========
  38. 错误的创建方式三
  39. A B C
  40. t1 30 42 NaN
  41. t2 32 38 NaN
  42. ===========
  43. 错误的创建方式四
  44. Empty DataFrame
  45. Columns: [c1, c2]
  46. Index: []

5. DataFrame对象的属性

(1)df.columns

返回df的列索引:

  • 如果未自定义过df.columns,则返回的数据类型为pandas.core.indexes.range.RangeIndex
  • 如果已自定义过df.columns,则返回的数据类型为pandas.core.indexes.base.Index

df.columns支持索引和切片:

  • 当对df.columns里面的单一元素进行索引时(即df.columns[]的中括号里无冒号):

    • 若此时未自定义过df.columns,则返回int类型的位置索引
    • 若此时已自定义过df.columns,则返回str类型(或其他类型)的标签索引
  • 当对df.columns切片时(即df.columns[]的中括号里有冒号,不论切片的长度是多少,哪怕切片里只有一项):
    • 若此时未自定义过df.columns,则返回pandas.core.indexes.range.RangeIndex类型的位置索引
    • 若此时已自定义过df.columns,则返回pandas.core.indexes.base.Index类型的标签索引

df.columns支持对其整体进行重新赋值,但不支持对其中的元素进行修改(会报错)

  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
  4. df = pd.DataFrame(arr,index=['t1','t2','t3','t4']) # 定义df时未定义columns
  5. print('df\n',df); print('===========')
  6. print('df.columns\n',df.columns,'\n',type(df.columns)); print('===========')
  7. print('df.columns[2]\n',df.columns[2],'\n',type(df.columns[2])); print('===========')
  8. print('df.columns[2:3]\n',df.columns[2:3],'\n',type(df.columns[2:3])); print('===========')
  9. # 可以对df.columns整体进行重新赋值
  10. df.columns=['c1','c2','c3','c4']
  11. print('df\n',df,'\n',type(df)); print('===========')
  12. print('df.columns\n',df.columns,'\n',type(df.columns)); print('===========')
  13. print('df.columns[2]\n',df.columns[2],'\n',type(df.columns[2])); print('===========')
  14. print('df.columns[2:3]\n',df.columns[2:3],'\n',type(df.columns[2:3])); print('===========')
  15. # 不可以对df.columns中的元素进行修改(会报错)
  16. df.columns[1]='New'
  17. print(df)
  18. 执行结果:
  19. df
  20. 0 1 2 3
  21. t1 1 2 3 4
  22. t2 5 6 7 8
  23. t3 9 10 11 12
  24. t4 13 14 15 16
  25. ===========
  26. df.columns
  27. RangeIndex(start=0, stop=4, step=1)
  28. <class 'pandas.core.indexes.range.RangeIndex'>
  29. ===========
  30. df.columns[2]
  31. 2
  32. <class 'int'>
  33. ===========
  34. df.columns[2:3]
  35. RangeIndex(start=2, stop=3, step=1)
  36. <class 'pandas.core.indexes.range.RangeIndex'>
  37. ===========
  38. df
  39. c1 c2 c3 c4
  40. t1 1 2 3 4
  41. t2 5 6 7 8
  42. t3 9 10 11 12
  43. t4 13 14 15 16
  44. <class 'pandas.core.frame.DataFrame'>
  45. ===========
  46. df.columns
  47. Index(['c1', 'c2', 'c3', 'c4'], dtype='object')
  48. <class 'pandas.core.indexes.base.Index'>
  49. ===========
  50. df.columns[2]
  51. c3
  52. <class 'str'>
  53. ===========
  54. df.columns[2:3]
  55. Index(['c3'], dtype='object')
  56. <class 'pandas.core.indexes.base.Index'>
  57. ===========
  58. 报错(TypeError: Index does not support mutable operations

(2)df.index

返回df的行索引:

  • 如果未自定义过df.index,则返回的数据类型为pandas.core.indexes.range.RangeIndex
  • 如果已自定义过df.index,则返回的数据类型为pandas.core.indexes.base.Index

df.index支持索引和切片:

  • 当对df.index里面的单一元素进行索引时(即df.index[]的中括号里无冒号):

    • 若此时未自定义过df.index,则返回int类型的位置索引
    • 若此时已自定义过df.index,则返回str类型(或其他类型)的标签索引
  • 当对df.index切片时(即df.index[]的中括号里有冒号,不论切片的长度是多少,哪怕切片里只有一项):
    • 若此时未自定义过df.index,则返回pandas.core.indexes.range.RangeIndex类型的位置索引
    • 若此时已自定义过df.index,则返回pandas.core.indexes.base.Index类型的标签索引

df.index支持对其整体进行重新赋值,但不支持对其中的元素进行修改(会报错)

  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
  4. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4']) # 定义df时未定义index
  5. print('df\n',df); print('===========')
  6. print('df.index\n',df.index,'\n',type(df.index)); print('===========')
  7. print('df.index[2]\n',df.index[2],'\n',type(df.index[2])); print('===========')
  8. print('df.index[2:3]\n',df.index[2:3],'\n',type(df.index[2:3])); print('===========')
  9. # 可以对df.index整体进行重新赋值
  10. df.index=['t1','t2','t3','t4']
  11. print('df\n',df,'\n',type(df)); print('===========')
  12. print('df.index\n',df.index,'\n',type(df.index)); print('===========')
  13. print('df.index[2]\n',df.index[2],'\n',type(df.index[2])); print('===========')
  14. print('df.index[2:3]\n',df.index[2:3],'\n',type(df.index[2:3])); print('===========')
  15. # 不可以对df.index中的元素进行修改(会报错)
  16. df.index[2]='New'
  17. print(df)
  18. 执行结果:
  19. df
  20. c1 c2 c3 c4
  21. 0 1 2 3 4
  22. 1 5 6 7 8
  23. 2 9 10 11 12
  24. 3 13 14 15 16
  25. ===========
  26. df.index
  27. RangeIndex(start=0, stop=4, step=1)
  28. <class 'pandas.core.indexes.range.RangeIndex'>
  29. ===========
  30. df.index[2]
  31. 2
  32. <class 'int'>
  33. ===========
  34. df.index[2:3]
  35. RangeIndex(start=2, stop=3, step=1)
  36. <class 'pandas.core.indexes.range.RangeIndex'>
  37. ===========
  38. df
  39. c1 c2 c3 c4
  40. t1 1 2 3 4
  41. t2 5 6 7 8
  42. t3 9 10 11 12
  43. t4 13 14 15 16
  44. <class 'pandas.core.frame.DataFrame'>
  45. ===========
  46. df.index
  47. Index(['t1', 't2', 't3', 't4'], dtype='object')
  48. <class 'pandas.core.indexes.base.Index'>
  49. ===========
  50. df.index[2]
  51. t3
  52. <class 'str'>
  53. ===========
  54. df.index[2:3]
  55. Index(['t3'], dtype='object')
  56. <class 'pandas.core.indexes.base.Index'>
  57. ===========
  58. 报错(TypeError: Index does not support mutable operations

(3)df.index.name和df.index.names

对于单一索引的df来说,df.index.name和df.index.names是同一个东西,对其中一个赋值会覆盖另一个的值,示例代码见例1、例2

对于层次化索引的df来说,df.index.name是一个标量(整个层次化索引的名字),而df.index.names是一个矢量(每一列层次化索引的单独的列名),示例代码见例3

  1. # 例1:单一索引的df.index.names覆盖df.index.name
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([1,2,3])
  5. df.columns = ['c1']
  6. df.index = ['t1','t2','t3']
  7. df.index.name = 'my_index'
  8. df.index.names = ['t'] # 将前面的df.index.name覆盖掉了
  9. print(df); print('===========')
  10. print(df.index); print('===========')
  11. print(df.index.name); print('===========')
  12. print(df.index.names)
  13. 执行结果:
  14. c1
  15. t
  16. t1 1
  17. t2 2
  18. t3 3
  19. ===========
  20. Index(['t1', 't2', 't3'], dtype='object', name='t')
  21. ===========
  22. t
  23. ===========
  24. ['t']
  1. # 例2:单一索引的df.index.name覆盖df.index.names
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([1,2,3])
  5. df.columns = ['c1']
  6. df.index = ['t1','t2','t3']
  7. df.index.names = ['t']
  8. df.index.name = 'my_index' # 将前面的df.index.names覆盖掉了
  9. print(df); print('===========')
  10. print(df.index); print('===========')
  11. print(df.index.name); print('===========')
  12. print(df.index.names)
  13. 执行结果:
  14. c1
  15. my_index
  16. t1 1
  17. t2 2
  18. t3 3
  19. ===========
  20. Index(['t1', 't2', 't3'], dtype='object', name='my_index')
  21. ===========
  22. my_index
  23. ===========
  24. ['my_index']
  1. # 例3:层次化索引的df.index.name和df.index.names是互相互独立的
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([1,2,3,4,5,6,7,8])
  5. df.columns = ['c1']
  6. df.index = [['A','A','B','B','C','C','D','D'],
  7. ['e','f','e','g','f','h','g','h']]
  8. df.index.name = 'my_multi_index'
  9. df.index.names = ['i1','i2']
  10. print(df); print('===========')
  11. print(df.index); print('===========')
  12. print(df.index.name); print('===========')
  13. print(df.index.names)
  14. 执行结果:
  15. c1
  16. i1 i2
  17. A e 1
  18. f 2
  19. B e 3
  20. g 4
  21. C f 5
  22. h 6
  23. D g 7
  24. h 8
  25. ===========
  26. MultiIndex([('A', 'e'),
  27. ('A', 'f'),
  28. ('B', 'e'),
  29. ('B', 'g'),
  30. ('C', 'f'),
  31. ('C', 'h'),
  32. ('D', 'g'),
  33. ('D', 'h')],
  34. name='my_multi_index')
  35. ===========
  36. my_multi_index
  37. ===========
  38. ['i1', 'i2']

(4)df.index.levels

以list形式返回df的各级层次化索引

注意:未设定行索引时df.index是pandas.core.indexes.range.RangeIndex的实例化对象,设定单一层次化索引时df.index是pandas.core.indexes.base.Index的实例化对象,这两种情况下执行df.index.levels都会报错,因为它们没有这个属性。仅两层或更多层的索引(pandas.core.indexes.multi.MultiIndex的实例化对象)才有levels属性。

  1. # 一层index
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([1,2,3])
  5. df.columns = ['c1']
  6. df.index = ['t1','t2','t3']
  7. print(type(df.index))
  8. print(df.index.levels)
  9. 执行结果:
  10. <class 'pandas.core.indexes.base.Index'>
  11. 报错
  1. # 两层index
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([1,2,3])
  5. df.columns = ['c1']
  6. df.index = [['A','B','C'],['t1','t2','t3']]
  7. print(type(df.index))
  8. print(df.index.levels)
  9. 执行结果:
  10. <class 'pandas.core.indexes.multi.MultiIndex'>
  11. [['A', 'B', 'C'], ['t1', 't2', 't3']]
  1. # 三层index
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([1,2,3])
  5. df.columns = ['c1']
  6. df.index = [[10,20,30],['A','B','C'],['t1','t2','t3']]
  7. print(type(df.index))
  8. print(df.index.levels)
  9. 执行结果:
  10. <class 'pandas.core.indexes.multi.MultiIndex'>
  11. [[10, 20, 30], ['A', 'B', 'C'], ['t1', 't2', 't3']]

(5)df.dtypes

返回每列的数据类型,即返回df中每列Series的dtype

返回值整体是一个Series

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,'a',3+4j],[2,'b',5+6j]],columns=['c1','c2','c3'],index=['t1','t2'])
  4. print(df.dtypes)
  5. print('==============')
  6. print(type(df.dtypes))
  7. 执行结果:
  8. c1 int64
  9. c2 object
  10. c3 complex128
  11. dtype: object
  12. ==============
  13. <class 'pandas.core.series.Series'>

(6)df.shape

返回一个元组,元组中的两项分别是df的行数和列数

  1. import numpy as np
  2. import pandas as pd
  3. df1 = pd.DataFrame()
  4. df2 = pd.DataFrame([10,11]) # pd.DataFrame()将一维列表变为了列向量
  5. df3 = pd.DataFrame(np.array([10,11])) # pd.DataFrame()将一维numpy.ndarray变为了列向量
  6. df4 = pd.DataFrame([[10,11]])
  7. df5 = pd.DataFrame([[10],[11]])
  8. df6 = pd.DataFrame([[10,11],[12,13]])
  9. print(df1.shape,type(df1.shape))
  10. print(df2.shape,type(df2.shape))
  11. print(df3.shape,type(df3.shape))
  12. print(df4.shape,type(df4.shape))
  13. print(df5.shape,type(df5.shape))
  14. print(df6.shape,type(df6.shape))
  15. 执行结果:
  16. (0, 0) <class 'tuple'>
  17. (2, 1) <class 'tuple'>
  18. (2, 1) <class 'tuple'>
  19. (1, 2) <class 'tuple'>
  20. (2, 1) <class 'tuple'>
  21. (2, 2) <class 'tuple'>

(7)df.values

获取df的所有值,不含行索引、列索引,返回numpy.ndarray类型。示例代码见“6.DataFrame的数据选择 - (5)使用df的属性和方法进行数据选择”

(8)df.列标签

获取df的某一列,返回Series类型,注意df.列标签是不加引号的。示例代码见“6.DataFrame的数据选择 - (5)使用df的属性和方法进行数据选择”

(9)df.empty

判断df是否为空,返回bool。当df=pd.DataFrame()时,df为空,返回True;只要df中有数据,哪怕这些数据本身都为空,df也不为空(返回False)。

6. DataFrame的数据选择

(1)使用df[]进行选择

df[]支持的操作有:

  • 使用 df['列标签'] 获取某一列(Series类型)
  • 使用 df[['列标签','列标签']] 获取不连续的一列或多列(花式索引)(DataFrame类型)
  • 使用 df['行标签':'行标签']、df[:'行标签']、df['行标签':] 获取连续的一行或多行(DataFrame类型)
  • 使用 df[行索引号:行索引号]、df[:行索引号]、df[行索引号:] 获取连续的一行或多行(DataFrame类型)
  • 当df行索引为pandas.core.indexes.datetimes.DatetimeIndex或pandas.core.indexes.period.PeriodIndex类型时,还可以使用df['年-月']、df['年.月']、df['年']等模糊索引方式获取满足条件的若干行(DataFrame类型),详见本章“14. Pandas中的时间相关格式及方法-(1)Pandas中的时间格式及特殊索引、切片方法”

df[]不支持的操作包括但不限于:

  • 对连续的列进行切片
  • 对不连续的行进行切片
  1. # 例1:前四种索引方式
  2. import numpy as np
  3. import pandas as pd
  4. arr=np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
  5. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4'],index=['t1','t2','t3','t4'])
  6. print("查看df\n",df); print('===========')
  7. # 使用 df['列标签'] 获取某一列(Series类型)
  8. print("获取'c3'列\n",df['c3'],'\n',type(df['c3'])); print('===========')
  9. # 使用 df[['列标签','列标签']] 获取不连续的若干列(花式索引)(DataFrame类型)
  10. print("获取'c3','c1'列\n",df[['c3','c1']],'\n',type(df[['c3','c1']])); print('===========')
  11. # 使用 df['行标签':'行标签']、df[:'行标签']、df['行标签':] 获取连续的一行或多行(DataFrame类型)
  12. print("获取't3'行\n",df['t3':'t3'],'\n',type(df['t3':'t3'])); print('===========')
  13. print("获取第一行到't3'行\n",df[:'t3'],'\n',type(df['t3':'t3'])); print('===========')
  14. # 使用 df[行索引号:行索引号]、df[:行索引号]、df[行索引号:] 获取连续的一行或多行(DataFrame类型)
  15. print("获取第三行\n",df[2:3],'\n',type(df[2:3])); print('===========')
  16. print("获取第一行到第三行\n",df[:3],'\n',type(df[:3]))
  17. 执行结果:
  18. 查看df
  19. c1 c2 c3 c4
  20. t1 1 2 3 4
  21. t2 5 6 7 8
  22. t3 9 10 11 12
  23. t4 13 14 15 16
  24. ===========
  25. 获取'c3'
  26. t1 3
  27. t2 7
  28. t3 11
  29. t4 15
  30. Name: c3, dtype: int32
  31. <class 'pandas.core.series.Series'>
  32. ===========
  33. 获取'c3','c1'
  34. c3 c1
  35. t1 3 1
  36. t2 7 5
  37. t3 11 9
  38. t4 15 13
  39. <class 'pandas.core.frame.DataFrame'>
  40. ===========
  41. 获取't3'
  42. c1 c2 c3 c4
  43. t3 9 10 11 12
  44. <class 'pandas.core.frame.DataFrame'>
  45. ===========
  46. 获取第一行到't3'
  47. c1 c2 c3 c4
  48. t1 1 2 3 4
  49. t2 5 6 7 8
  50. t3 9 10 11 12
  51. <class 'pandas.core.frame.DataFrame'>
  52. ===========
  53. 获取第三行
  54. c1 c2 c3 c4
  55. t3 9 10 11 12
  56. <class 'pandas.core.frame.DataFrame'>
  57. ===========
  58. 获取第一行到第三行
  59. c1 c2 c3 c4
  60. t1 1 2 3 4
  61. t2 5 6 7 8
  62. t3 9 10 11 12
  63. <class 'pandas.core.frame.DataFrame'>

(2)使用基于标签索引的df.loc[]

loc是location的简写

df.loc[]支持的索引类型如下:

df有列标签索引 df无列标签索引
df有行标签索引 支持行标签索引、列标签索引
不支持行位置索引、列位置索引
支持行标签索引、列位置索引
不支持行位置索引、列标签索引
df无行标签索引 支持行位置索引、列标签索引
不支持行标签索引、列位置索引
支持行位置索引、列位置索引
不支持行标签索引、列标签索引

总结一句话:有标签索引时只能用标签索引,没有标签索引时才能用位置索引

注意标签索引使用冒号:切片时是前后都包含的,而位置索引使用冒号:切片时是顾前不顾后的,此外还要注意位置索引是从0开始的

可以通过df.loc[]选取任意行、任意列。若选取的行数、列数都为1,则返回该位置元素本身的数据类型;若行数、列数只有一个为1,则返回Series类型;若行数、列数都不为1,则返回DataFrame类型

关于pd.date_range()的标签索引方式,详见本章“10.DataFrame对象的方法和Pandas模块的方法 - (4)时间相关方法 - ①pd.date_range()”

  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
  4. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4'],index=['t1','t2','t3','t4'])
  5. print("查看df\n",df); print('===========')
  6. # 使用 df.loc['行标签'] 获取某一行(Series类型)
  7. print("获取't1'行\n",df.loc['t2'],'\n',type(df.loc['t2'])); print('===========')
  8. # 使用 df.loc['行标签':'行标签'] 获取连续的若干行(前后都包含)(DataFrame类型)
  9. print("获取't2'至't3'行(前后都包含)\n",df.loc['t2':'t3'],'\n',type(df.loc['t2':'t3'])); print('===========')
  10. # 使用 df.loc[['行标签','行标签']] 获取不连续的若干行(花式索引)(DataFrame类型)
  11. print("获取't3'和't1'行\n",df.loc[['t3','t1']],'\n',type(df.loc[['t3','t1']])); print('===========')
  12. # 使用 df.loc[:,'列标签'] 获取某一列(Series类型)
  13. print("获取'c2'列\n",df.loc[:,'c2'],'\n',type(df.loc[:,'c2'])); print('===========')
  14. # 使用 df.loc[:,'列标签':'列标签'] 获取连续的若干列(前后都包含)(DataFrame类型)
  15. print("获取'c2'至'c3'列(前后都包含)\n",df.loc[:,'c2':'c3'],'\n',type(df.loc[:,'c2':'c3'])); print('===========')
  16. # 使用 df.loc[:,['行标签','行标签']] 获取不连续的若干列(花式索引)(DataFrame类型)
  17. print("获取'c3'和'c1'列\n",df.loc[:,['c3','c1']],'\n',type(df.loc[:,['c3','c1']])); print('===========')
  18. # 使用 df.loc['行标签','列标签'] 获取某一个元素(该位置元素本身的数据类型)
  19. print("获取't4'行,'c4'列位置的元素\n",df.loc['t4','c4'],'\n',type(df.loc['t4','c4'])); print('===========')
  20. # 使用上述方法的各种组合获取某几行、某几列(若选取的行数、列数都为1,则返回该位置元素本身的数据类型;若行数、列数只有一个为1,则返回Series类型;若行数、列数都不为1,则返回DataFrame类型)
  21. print("获取't2'至't3'行,'c2'至'c3'列\n",df.loc['t2':'t3','c2':'c3'],'\n',type(df.loc['t2':'t3','c2':'c3'])); print('===========')
  22. print("获取't4'行,'c4'和'c1'列\n",df.loc['t4',['c4','c1']],'\n',type(df.loc['t4',['c4','c1']]))
  23. 执行结果:
  24. 查看df
  25. c1 c2 c3 c4
  26. t1 1 2 3 4
  27. t2 5 6 7 8
  28. t3 9 10 11 12
  29. t4 13 14 15 16
  30. ===========
  31. 获取't1'
  32. c1 5
  33. c2 6
  34. c3 7
  35. c4 8
  36. Name: t2, dtype: int32
  37. <class 'pandas.core.series.Series'>
  38. ===========
  39. 获取't2''t3'行(前后都包含)
  40. c1 c2 c3 c4
  41. t2 5 6 7 8
  42. t3 9 10 11 12
  43. <class 'pandas.core.frame.DataFrame'>
  44. ===========
  45. 获取't3''t1'
  46. c1 c2 c3 c4
  47. t3 9 10 11 12
  48. t1 1 2 3 4
  49. <class 'pandas.core.frame.DataFrame'>
  50. ===========
  51. 获取'c2'
  52. t1 2
  53. t2 6
  54. t3 10
  55. t4 14
  56. Name: c2, dtype: int32
  57. <class 'pandas.core.series.Series'>
  58. ===========
  59. 获取'c2''c3'列(前后都包含)
  60. c2 c3
  61. t1 2 3
  62. t2 6 7
  63. t3 10 11
  64. t4 14 15
  65. <class 'pandas.core.frame.DataFrame'>
  66. ===========
  67. 获取'c3''c1'
  68. c3 c1
  69. t1 3 1
  70. t2 7 5
  71. t3 11 9
  72. t4 15 13
  73. <class 'pandas.core.frame.DataFrame'>
  74. ===========
  75. 获取't4'行,'c4'列位置的元素
  76. 16
  77. <class 'numpy.int32'>
  78. ===========
  79. 获取't2''t3'行,'c2''c3'
  80. c2 c3
  81. t2 6 7
  82. t3 10 11
  83. <class 'pandas.core.frame.DataFrame'>
  84. ===========
  85. 获取't4'行,'c4''c1'
  86. c4 16
  87. c1 13
  88. Name: t4, dtype: int32
  89. <class 'pandas.core.series.Series'>

(3)使用基于位置索引的df.iloc[]

iloc是index location的简写

即使DataFrame已自定义了columns和index,仍然可以使用位置索引通过df.iloc[]进行选择

和df.loc[]不同,不论df有没有行标签、列标签,df.iloc[]都只支持位置索引(position index),位置索引使用冒号:切片时是顾前不顾后的,此外还要注意位置索引是从0开始的

可以通过df.iloc[]选取任意行、任意列。若选取的行数、列数都为1,则返回该位置元素本身的数据类型;若行数、列数只有一个为1,则返回Series类型;若行数、列数都不为1,则返回DataFrame类型

特别地,使用df.iloc[]可以实现倒序排列:

  • df.iloc[::-1,:]:倒序排所有行
  • df.iloc[:,::-1]:倒序排所有列
  • df.iloc[::-1,::-1]:倒序排所有行、所有列
  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
  4. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4'],index=['t1','t2','t3','t4'])
  5. print("查看df\n",df); print('===========')
  6. # 使用 df.iloc[行索引] 获取某一行(Series类型)
  7. print("获取最后一行\n",df.iloc[-1],'\n',type(df.iloc[-1])); print('===========')
  8. # 使用 df.iloc[行索引:行索引] 获取连续的若干行(顾前不顾后)(DataFrame类型)
  9. print("获取第二行至倒数第二行\n",df.iloc[1:-1],'\n',type(df.iloc[1:-1])); print('===========')
  10. # 使用 df.iloc[[行索引,行索引]] 获取不连续的若干行(花式索引)(DataFrame类型)
  11. print("获取倒数第二行和第一行\n",df.iloc[[-2,0]],'\n',type(df.iloc[[-2,0]])); print('===========')
  12. # 使用 df.iloc[:,列索引] 获取某一列(Series类型)
  13. print("获取最后一列\n",df.iloc[:,-1],'\n',type(df.iloc[:,-1])); print('===========')
  14. # 使用 df.iloc[:,列索引:列索引] 获取连续的若干列(顾前不顾后)(DataFrame类型)
  15. print("获取第二列至倒数第二列\n",df.iloc[:,1:-1],'\n',type(df.iloc[:,1:-1])); print('===========')
  16. # 使用 df.iloc[:,[列索引,列索引]] 获取不连续的若干列(花式索引)(DataFrame类型)
  17. print("获取倒数第二列和第一列\n",df.iloc[:,[-2,0]],'\n',type(df.iloc[:,[-2,0]])); print('===========')
  18. # 使用 df.iloc[行索引,列索引] 获取某一个元素(该位置元素本身的数据类型)
  19. print("获取最后一行,最后一列的元素\n",df.iloc[-1,-1],'\n',type(df.iloc[-1,-1])); print('===========')
  20. # 使用上述方法的各种组合获取某几行、某几列(若选取的行数、列数都为1,则返回该位置元素本身的数据类型;若行数、列数只有一个为1,则返回Series类型;若行数、列数都不为1,则返回DataFrame类型)
  21. print("获取第一行至倒数第二行,第三列至最后一列\n",df.iloc[:-1,2:],'\n',type(df.iloc[:-1,2:])); print('===========')
  22. print("获取第四行,最后一列和倒数第三列\n",df.iloc[3,[-1,-3]],'\n',type(df.iloc[3,[-1,-3]])); print('===========')
  23. # 使用df.iloc[]实现倒序排
  24. print("倒序排所有行\n",df.iloc[::-1,:]); print('===========')
  25. print("倒序排所有列\n",df.iloc[:,::-1]); print('===========')
  26. print("倒序排所有行和所有列\n",df.iloc[::-1,::-1])
  27. 执行结果:
  28. 查看df
  29. c1 c2 c3 c4
  30. t1 1 2 3 4
  31. t2 5 6 7 8
  32. t3 9 10 11 12
  33. t4 13 14 15 16
  34. ===========
  35. 获取最后一行
  36. c1 13
  37. c2 14
  38. c3 15
  39. c4 16
  40. Name: t4, dtype: int32
  41. <class 'pandas.core.series.Series'>
  42. ===========
  43. 获取第二行至倒数第二行
  44. c1 c2 c3 c4
  45. t2 5 6 7 8
  46. t3 9 10 11 12
  47. <class 'pandas.core.frame.DataFrame'>
  48. ===========
  49. 获取倒数第二行和第一行
  50. c1 c2 c3 c4
  51. t3 9 10 11 12
  52. t1 1 2 3 4
  53. <class 'pandas.core.frame.DataFrame'>
  54. ===========
  55. 获取最后一列
  56. t1 4
  57. t2 8
  58. t3 12
  59. t4 16
  60. Name: c4, dtype: int32
  61. <class 'pandas.core.series.Series'>
  62. ===========
  63. 获取第二列至倒数第二列
  64. c2 c3
  65. t1 2 3
  66. t2 6 7
  67. t3 10 11
  68. t4 14 15
  69. <class 'pandas.core.frame.DataFrame'>
  70. ===========
  71. 获取倒数第二列和第一列
  72. c3 c1
  73. t1 3 1
  74. t2 7 5
  75. t3 11 9
  76. t4 15 13
  77. <class 'pandas.core.frame.DataFrame'>
  78. ===========
  79. 获取最后一行,最后一列的元素
  80. 16
  81. <class 'numpy.int32'>
  82. ===========
  83. 获取第一行至倒数第二行,第三列至最后一列
  84. c3 c4
  85. t1 3 4
  86. t2 7 8
  87. t3 11 12
  88. <class 'pandas.core.frame.DataFrame'>
  89. ===========
  90. 获取第四行,最后一列和倒数第三列
  91. c4 16
  92. c2 14
  93. Name: t4, dtype: int32
  94. <class 'pandas.core.series.Series'>
  95. ===========
  96. 倒序排所有行
  97. c1 c2 c3 c4
  98. t4 13 14 15 16
  99. t3 9 10 11 12
  100. t2 5 6 7 8
  101. t1 1 2 3 4
  102. ===========
  103. 倒序排所有列
  104. c4 c3 c2 c1
  105. t1 4 3 2 1
  106. t2 8 7 6 5
  107. t3 12 11 10 9
  108. t4 16 15 14 13
  109. ===========
  110. 倒序排所有行和所有列
  111. c4 c3 c2 c1
  112. t4 16 15 14 13
  113. t3 12 11 10 9
  114. t2 8 7 6 5
  115. t1 4 3 2 1

(4)使用基于混合索引的df.ix[](新版Pandas即将取消该功能)

df.ix[]既支持位置索引(position index),也支持标签索引(label index),位置索引使用冒号:切片时是顾前不顾后的,标签索引使用冒号:切片时是前后都包含

可以通过df.ix[]选取任意行、任意列。若选取的行数、列数都为1,则返回该位置元素本身的数据类型;若行数、列数只有一个为1,则返回Series类型;若行数、列数都不为1,则返回DataFrame类型

关于pd.date_range()的标签索引方式,详见本章“10.DataFrame对象的方法和Pandas模块的方法 - (4)时间相关方法 - ①pd.date_range()”

注意事项:

  • df.ix[]的中括号里没有逗号时,自动视为行索引或行标签
  • df.ix[,]中,可以对行使用一种索引方法,对列使用另一种索引方法
  • 不可以在冒号:两边分别使用位置索引和标签索引
  • 不可以在花式索引列表[]中同时出现位置索引和标签索引
  • 使用df.ix[]会有warning警告,因为新版Pandas即将取消该功能
  1. import numpy as np
  2. import pandas as pd
  3. import warnings; warnings.simplefilter('ignore') # 忽略可能会出现的警告信息;警告并不是错误,可以忽略;可能出现警告的场景包括:df.ix[]、pd.concat()
  4. arr = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
  5. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4'],index=['t1','t2','t3','t4'])
  6. print("查看df\n",df); print('===========')
  7. # 正确的示例
  8. print("获取最后一行\n",df.ix[-1]); print('===========')
  9. print("获取第一行至't3'行\n",df.ix[:'t3']); print('===========')
  10. print("获取第一行至倒数第三行,'c4'列和'c3'列\n",df.ix[:-2, ['c4','c3']])
  11. # 错误的示例
  12. # print("不可以在冒号:两边分别使用位置索引和标签索引,会报错\n",df.ix[1:'t1', 2])
  13. # print("不可以在花式索引列表[]中同时出现位置索引和标签索引,会报错\n",df.ix[1:, [1,'c3']])
  14. 执行结果:
  15. 查看df
  16. c1 c2 c3 c4
  17. t1 1 2 3 4
  18. t2 5 6 7 8
  19. t3 9 10 11 12
  20. t4 13 14 15 16
  21. ===========
  22. 获取最后一行
  23. c1 13
  24. c2 14
  25. c3 15
  26. c4 16
  27. Name: t4, dtype: int32
  28. ===========
  29. 获取第一行至't3'
  30. c1 c2 c3 c4
  31. t1 1 2 3 4
  32. t2 5 6 7 8
  33. t3 9 10 11 12
  34. ===========
  35. 获取第一行至倒数第三行,'c4'列和'c3'
  36. c4 c3
  37. t1 4 3
  38. t2 8 7

(5)使用df的属性和方法进行选择

具体包括下面几种属性和方法:

  • df.列标签:获取某一列,返回Series类型,注意df.列标签是不加引号的
  • df.values:获取所有值,不含行索引、列索引,返回numpy.ndarray类型
  • df.head(n=5):获取前n行,n的默认值为5,返回DataFrame类型
  • df.tail(n=5):获取后n行,n的默认值为5,返回DataFrame类型
  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
  4. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4'],index=['t1','t2','t3','t4'])
  5. print("查看df\n",df); print('===========')
  6. # 使用 df.列标签 获取某一列(Series类型)
  7. print("获取'c3'列\n",df.c3,'\n',type(df.c3)); print('===========')
  8. # 无法使用 df.列索引号 获取某一列
  9. # 无法使用 df.行标签 获取某一行
  10. # 无法使用 df.行索引号 获取某一行
  11. # 使用 df.values 获取所有值,不含行索引、列索引(numpy.ndarray类型)
  12. print("获取df所有值\n",df.values,'\n',type(df.values))
  13. # 使用 df.head(n) 获取前n行(DataFrame类型)
  14. print("获取前2行\n",df.head(2),'\n',type(df.head(2))); print('===========')
  15. # 使用 df.tail(n) 获取后n行(DataFrame类型)
  16. print("获取后2行\n",df.tail(2),'\n',type(df.tail(2)))
  17. 执行结果:
  18. 查看df
  19. c1 c2 c3 c4
  20. t1 1 2 3 4
  21. t2 5 6 7 8
  22. t3 9 10 11 12
  23. t4 13 14 15 16
  24. ===========
  25. 获取'c3'
  26. t1 3
  27. t2 7
  28. t3 11
  29. t4 15
  30. Name: c3, dtype: int32
  31. <class 'pandas.core.series.Series'>
  32. ===========
  33. 获取df所有值
  34. [[ 1 2 3 4]
  35. [ 5 6 7 8]
  36. [ 9 10 11 12]
  37. [13 14 15 16]]
  38. <class 'numpy.ndarray'>
  39. 获取前2
  40. c1 c2 c3 c4
  41. t1 1 2 3 4
  42. t2 5 6 7 8
  43. <class 'pandas.core.frame.DataFrame'>
  44. ===========
  45. 获取后2
  46. c1 c2 c3 c4
  47. t3 9 10 11 12
  48. t4 13 14 15 16
  49. <class 'pandas.core.frame.DataFrame'>

(6)使用布尔值索引筛选满足条件的行

如果需要根据某列的值是否满足给定的条件,筛选出满足条件的整行数据(或这些行指定字段的数据),可以使用下面的方法:

  1. # 用于筛选满足条件的行
  2. df[由布尔值组成的list]
  3. df[由“df.列标签”组成的条件]
  4. df[由“df['列标签']”组成的条件]
  5. df.loc[由“df.列标签”组成的条件, :]
  6. df.loc[由“df['列标签']”组成的条件, :]
  7. # 用于筛选满足条件的行、列
  8. df.loc[由“df.列标签”组成的条件, 由“df.列标签”组成的条件]
  9. df.loc[由“df['列标签']”组成的条件, 由“df['列标签']”组成的条件]

条件之间的逻辑运算符有|、&、~、np.logical_or()、np.logical_and()、np.logical_not(),每个运算符的详细介绍见“第五章 Python编程进阶 - 一、NumPy模块 - 8. ndarray对象的方法和NumPy模块的方法 - (2)二元通用函数 - ③ 基本逻辑运算

可以根据布尔值的特性(True=1,False=0),把条件*1并用+连接,以便对满足条件的数量进行筛选

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[10,8,6],[8,15,13],[13,7,14],[9,9,11]],columns=['c1','c2','c3'],index=['t1','t2','t3','t4'])
  4. print(df); print('===========')
  5. print(df.c1>9); print('===========') # 写成df['c1']>9也行
  6. print(df[df.c1>9]); print('===========') # 写成df[df['c1']>9]也行
  7. print(df[(df.c1>9) & (df.c3>9)]); print('===========') # 筛选两个条件都满足的(且)
  8. print(df[(df.c1>9) | (df.c3>9)]); print('===========') # 筛选满足任意一个条件的(或)
  9. print(df[(df.c1>9)*1 + (df.c2>9)*1 + (df.c3>9)*1 >=2 ]) # 筛选三个条件中至少满足两个的(布尔值特性)
  10. print('===========')
  11. print(df.loc[df.c1.isin([8,9,22,33]),['c2','c3']]) # 筛选'c1'列的值在给定列表里的行的'c2'和'c3'列
  12. 执行结果:
  13. c1 c2 c3
  14. t1 10 8 6
  15. t2 8 15 13
  16. t3 13 7 14
  17. t4 9 9 11
  18. ===========
  19. t1 True
  20. t2 False
  21. t3 True
  22. t4 False
  23. Name: c1, dtype: bool
  24. ===========
  25. c1 c2 c3
  26. t1 10 8 6
  27. t3 13 7 14
  28. ===========
  29. c1 c2 c3
  30. t3 13 7 14
  31. ===========
  32. c1 c2 c3
  33. t1 10 8 6
  34. t2 8 15 13
  35. t3 13 7 14
  36. t4 9 9 11
  37. ===========
  38. c1 c2 c3
  39. t2 8 15 13
  40. t3 13 7 14
  41. ===========
  42. c2 c3
  43. t2 15 13
  44. t4 9 11

(7)使用df.query()筛选满足条件的行

语法:df.query('列标签组成的str格式表达式',inplace=False)

通过列标签组成的str格式表达式筛选满足条件的行,返回DataFrame格式的筛选结果,注意:

  • 当表达式中含有变量时,需要在变量名称前加@符号

  • 当表达式中含有带空格的列标签时,需要在此列标签的两侧加`符号

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[10,8,6],[8,15,13],[13,7,14],[9,9,11]],
  4. columns=['c1','c2','c 3'],
  5. index=['t1','t2','t3','t4'])
  6. var = 9
  7. print(df); print('===========')
  8. print(df.query('c1 > 9')); print('===========')
  9. print(df.query('c1 > @var')); print('===========')
  10. # print(df.query('c1 > c 3')); print('===========') # 报错
  11. print(df.query('c1 > `c 3`'))
  12. 执行结果:
  13. c1 c2 c 3
  14. t1 10 8 6
  15. t2 8 15 13
  16. t3 13 7 14
  17. t4 9 9 11
  18. ===========
  19. c1 c2 c 3
  20. t1 10 8 6
  21. t3 13 7 14
  22. ===========
  23. c1 c2 c 3
  24. t1 10 8 6
  25. t3 13 7 14
  26. ===========
  27. c1 c2 c 3
  28. t1 10 8 6

(8)循环遍历df每一行数据

可以使用df.iterrows()返回的生成器实现,见本章“10. DataFrame对象的方法和Pandas模块的方法 - (5)其他重要方法 - ② df.iterrows()

7. DataFrame的向量化、对齐和广播

(1)向量化和对齐

DataFrame的向量化是一种比numpy.ndarray和Series更为广义的向量化:

  • 算数运算(+、-、*、/、**、//、%)

    • 当两个DataFrame的shape、行标签、列标签都完全相同时,它们的算数运算就是对应项的运算,结果也是一个shape相同的DataFrame
    • 当两个DataFrame的shape、行标签、列标签不完全相同时,它们之间也可以进行算数运算,此时行标签、列标签都相同的项才会执行元素级别的计算,不同的项则返回NaN。最终得到的DataFrame的shape会大于两个参与运算的DataFrame,因为前者的行标签是后两者行标签的并集,前者的列标签也是后两者列标签的并集。上述规则称为DataFrame的对齐
    • DataFrame可以和一个shape相同的二维numpy.ndarray进行算数运算,返回一个shape、行标签、列标签都相同的DataFrame
    • DataFrame不能和一个shape不同的二维numpy.ndarray进行算数运算,也不能和任何二维list进行算数运算(哪怕二者shape相同)(报错)
  • 比较运算(><、>=、<=、==、!=)
    • 当两个DataFrame的shape、行标签、列标签都完全相同时,它们之间可以执行比较运算,返回一个shape相同的DataFrame,值为True或False
    • 当两个DataFrame的shape、行标签、列标签不完全相同时,它们之间不能执行比较运算(报错),即此时DataFrame无法对齐
    • DataFrame可以和一个shape相同的二维numpy.ndarray进行比较运算,返回一个shape、行标签、列标签都相同的DataFrame,值为True或False
    • DataFrame不能和一个shape不同的二维numpy.ndarray进行比较运算,也不能和任何二维list进行比较运算(哪怕二者shape相同)(报错)

关于对齐的总结:如果两个DataFrame的shape、行标签、列标签不完全相同,进行算数运算时可以实现对齐,进行比较运算时无法实现对齐(只能报错)

关于对齐产生的NaN的后续处理:详见本章 “ 7.DataFrame的修改 - 对NaN进行替换 “

上面两类运算均未提到DataFrame和Series之间的计算,因为DataFrame必然是二维的,Series必然是一维的,因此它们二者之间只能是广播的关系,不属于向量化的范畴,其规则详见本章“广播”部分

  1. # DataFrame的对齐
  2. import numpy as np
  3. import pandas as pd
  4. df1 = pd.DataFrame([[10,20,30,40],[50,60,70,80]],columns=['c1','c2','c3','c4'],index=['t1','t2'])
  5. df2 = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]],columns=['c0','c3','c1'],index=['t0','t2','t1'])
  6. print('df1\n',df1); print('===========')
  7. print('df2\n',df2); print('===========')
  8. print('df1 + df2\n',df1 + df2); print('===========')
  9. print('df1 // df2\n',df1 // df2); print('===========')
  10. print('df1 > df2\n',df1 > df2)
  11. 执行结果:
  12. df1
  13. c1 c2 c3 c4
  14. t1 10 20 30 40
  15. t2 50 60 70 80
  16. ===========
  17. df2
  18. c0 c3 c1
  19. t0 1 2 3
  20. t2 4 5 6
  21. t1 7 8 9
  22. ===========
  23. df1 + df2
  24. c0 c1 c2 c3 c4
  25. t0 NaN NaN NaN NaN NaN
  26. t1 NaN 19.0 NaN 38.0 NaN
  27. t2 NaN 56.0 NaN 75.0 NaN
  28. ===========
  29. df1 // df2
  30. c0 c1 c2 c3 c4
  31. t0 NaN NaN NaN NaN NaN
  32. t1 NaN 1.0 NaN 3.0 NaN
  33. t2 NaN 8.0 NaN 14.0 NaN
  34. ===========
  35. 报错(ValueError: Can only compare identically-labeled DataFrame objects
  1. # 仅当两个DataFrame的shape、行标签、列标签都完全相同时,它们之间才能执行><、>=、<=、==、!=的比较运算
  2. import numpy as np
  3. import pandas as pd
  4. df1 = pd.DataFrame([[3,4],[5,6]],columns=['c1','c2'],index=['t1','t2'])
  5. df2 = pd.DataFrame([[1,2],[7,8]],columns=['c1','c2'],index=['t1','t2'])
  6. print('df1\n',df1); print('===========')
  7. print('df2\n',df2); print('===========')
  8. print('df1 < df2\n',df1 < df2)
  9. 执行结果:
  10. df1
  11. c1 c2
  12. t1 3 4
  13. t2 5 6
  14. ===========
  15. df2
  16. c1 c2
  17. t1 1 2
  18. t2 7 8
  19. ===========
  20. df1 < df2
  21. c1 c2
  22. t1 False False
  23. t2 True True

(2)广播

① DataFrame与数字进行计算

对于DataFrame与数字进行的+、-、*、/、**、//、%、>、<、>=、<=、==、!=等运算,会将这个DataFrame中的每一个元素均与这个数字进行计算,并用这些结果组成一个与原DataFrame结构、行标签、列标签都相同的DataFrame

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2],[3,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('===========')
  5. print(df // 2); print('===========')
  6. print(df < 2)
  7. 执行结果:
  8. c1 c2
  9. t1 1 2
  10. t2 3 4
  11. ===========
  12. c1 c2
  13. t1 0 1
  14. t2 1 2
  15. ===========
  16. c1 c2
  17. t1 True False
  18. t2 False False

② DataFrame与一维对象进行计算

DataFrame和DataFrame:

DataFrame和DataFrame之间不存在广播的概念,因为DataFrame本身是二维的,因此无论是几行几列,两个DataFrame之间的计算都属于向量化的范畴,详见本章的“向量化与对齐”的部分

DataFrame和一维list:

DataFrame和一维list之间可以广播的前提:DataFrame的列数等于一维list的长度。广播时,按行广播。

DataFrame和一维numpy.ndarray:

DataFrame和一维numpy.ndarray之间可以广播的前提:DataFrame的列数等于一维numpy.ndarray的长度。广播时,按行广播。

DataFrame和Series:

DataFrame和Series之间可以广播的前提:DataFrame的列数等于Series的长度,且Series的index与DataFrame的columns一一对应(顺序可以不同)。广播时,按行广播,标签相同的项执行对应的计算。

  1. # DataFrame 与 一维list 的广播示例
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([[10,20,30,40],[50,60,70,80]],columns=['c1','c2','c3','c4'],index=['t1','t2'])
  5. li= [1,2,100,100] #可以结果正确
  6. print('查看df\n',df); print('===========')
  7. print('查看li\n',li); print('===========')
  8. print('df + li\n',df + li); print('===========')
  9. print('df > li\n',df > li)
  10. 执行结果:
  11. 查看df
  12. c1 c2 c3 c4
  13. t1 10 20 30 40
  14. t2 50 60 70 80
  15. ===========
  16. 查看li
  17. [1, 2, 100, 100]
  18. ===========
  19. df + li
  20. c1 c2 c3 c4
  21. t1 11 22 130 140
  22. t2 51 62 170 180
  23. ===========
  24. df > li
  25. c1 c2 c3 c4
  26. t1 True True False False
  27. t2 True True False False
  1. # DataFrame 与 一维numpy.ndarray 的广播示例
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([[10,20,30,40],[50,60,70,80]],columns=['c1','c2','c3','c4'],index=['t1','t2'])
  5. arr = np.array([1,2,100,100]) #可以结果正确
  6. print('查看df\n',df); print('===========')
  7. print('查看arr\n',arr); print('===========')
  8. print('df + arr\n',df + arr); print('===========')
  9. print('df > arr\n',df > arr)
  10. 执行结果:
  11. 查看df
  12. c1 c2 c3 c4
  13. t1 10 20 30 40
  14. t2 50 60 70 80
  15. ===========
  16. 查看arr
  17. [ 1 2 100 100]
  18. ===========
  19. df + arr
  20. c1 c2 c3 c4
  21. t1 11 22 130 140
  22. t2 51 62 170 180
  23. ===========
  24. df > arr
  25. c1 c2 c3 c4
  26. t1 True True False False
  27. t2 True True False False
  1. # DataFrame 与 Series 的广播示例
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([[10,20,30,40],[50,60,70,80]],columns=['c1','c2','c3','c4'],index=['t1','t2'])
  5. s1 = pd.Series([1,2,100,100]) # 未定义符合条件的index,结果错误
  6. s2 = pd.Series([100, 100, 1, 2], index=['c3','c4','c1','c2']) # 顺序可以不同,结果依然正确
  7. print('查看df\n',df); print('===========')
  8. print('查看s1\n',s1); print('===========')
  9. print('df + s1(结果错误)\n',df + s1); print('===========')
  10. print('df > s1(结果错误)\n',df > s1); print('===========')
  11. print('查看df\n',df); print('===========')
  12. print('查看s2\n',s2); print('===========')
  13. print('df + s2(结果正确)\n',df + s2); print('===========')
  14. print('df > s2(结果正确)\n',df > s2)
  15. 执行结果:
  16. 查看df
  17. c1 c2 c3 c4
  18. t1 10 20 30 40
  19. t2 50 60 70 80
  20. ===========
  21. 查看s1
  22. 0 1
  23. 1 2
  24. 2 100
  25. 3 100
  26. dtype: int64
  27. ===========
  28. df + s1(结果错误)
  29. c1 c2 c3 c4 0 1 2 3
  30. t1 NaN NaN NaN NaN NaN NaN NaN NaN
  31. t2 NaN NaN NaN NaN NaN NaN NaN NaN
  32. ===========
  33. df > s1(结果错误)
  34. c1 c2 c3 c4 0 1 2 3
  35. t1 False False False False False False False False
  36. t2 False False False False False False False False
  37. ===========
  38. 查看df
  39. c1 c2 c3 c4
  40. t1 10 20 30 40
  41. t2 50 60 70 80
  42. ===========
  43. 查看s2
  44. c3 100
  45. c4 100
  46. c1 1
  47. c2 2
  48. dtype: int64
  49. ===========
  50. df + s2(结果正确)
  51. c1 c2 c3 c4
  52. t1 11 22 130 140
  53. t2 51 62 170 180
  54. ===========
  55. df > s2(结果正确)
  56. c1 c2 c3 c4
  57. t1 True True False False
  58. t2 True True False False

8. DataFrame的修改、变形、转换

(1)增加一行、增加一列

① 基于df.loc[]增加一行、增加一列

语法:

  1. df.loc['新行标签'] = data # 增加一行
  2. df.loc[:,'新列标签'] = data # 增加一列
  3. df.loc['新行标签','旧列标签'] = data # 增加一行(仅对部分元素赋值,未赋值元素的是NaN)
  4. df.loc['旧行标签','新列标签'] = data # 增加一列(仅对部分元素赋值,未赋值元素的是NaN)
  5. df.loc['新行标签','新列标签'] = data # 增加一行和一列(仅对部分元素赋值,未赋值元素的是NaN)

代码示例:

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2],[3,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('==============')
  5. df.loc['t3'] = [5, 6]
  6. print(df); print('==============')
  7. df.loc[:,'c3'] = [7, 8, 9]
  8. print(df); print('==============')
  9. df.loc['t4','c2'] = 10
  10. print(df); print('==============')
  11. df.loc['t2','c4'] = 11
  12. print(df); print('==============')
  13. df.loc['t5','c5'] = 12
  14. print(df); print('==============')
  15. print(df)
  16. 执行结果:
  17. c1 c2
  18. t1 1 2
  19. t2 3 4
  20. ==============
  21. c1 c2
  22. t1 1 2
  23. t2 3 4
  24. t3 5 6
  25. ==============
  26. c1 c2 c3
  27. t1 1 2 7
  28. t2 3 4 8
  29. t3 5 6 9
  30. ==============
  31. c1 c2 c3
  32. t1 1.0 2.0 7.0
  33. t2 3.0 4.0 8.0
  34. t3 5.0 6.0 9.0
  35. t4 NaN 10.0 NaN
  36. ==============
  37. c1 c2 c3 c4
  38. t1 1.0 2.0 7.0 NaN
  39. t2 3.0 4.0 8.0 11.0
  40. t3 5.0 6.0 9.0 NaN
  41. t4 NaN 10.0 NaN NaN
  42. ==============
  43. c1 c2 c3 c4 c5
  44. t1 1.0 2.0 7.0 NaN NaN
  45. t2 3.0 4.0 8.0 11.0 NaN
  46. t3 5.0 6.0 9.0 NaN NaN
  47. t4 NaN 10.0 NaN NaN NaN
  48. t5 NaN NaN NaN NaN 12.0
  49. ==============
  50. c1 c2 c3 c4 c5
  51. t1 1.0 2.0 7.0 NaN NaN
  52. t2 3.0 4.0 8.0 11.0 NaN
  53. t3 5.0 6.0 9.0 NaN NaN
  54. t4 NaN 10.0 NaN NaN NaN
  55. t5 NaN NaN NaN NaN 12.0

② 基于df[]增加一列

语法:df['列标签'] = data

data的长度必须等于df的行数,data可以是list、tuple、range()、numpy.ndarray、Series、DataFrame

注意:当data为Series或DataFrame时,必须为其定义与df相对应的index(顺序可以不同,Pandas会自动根据标签进行匹配),如果不写index,由于DataFrame的自动对齐,会导致新增的值都是NaN

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,3],[2,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('==============')
  5. print('list、tuple、range()的情况略'); print('==============')
  6. df['c3'] = np.array([5,6])
  7. print(df); print('==============')
  8. df['c4'] = pd.Series([7,8],index=['t2','t1']) # 给Series定义正确的index,顺序无所谓
  9. print(df); print('==============')
  10. df['c5'] = pd.Series([9,10]) # 未给Series定义index,错误
  11. print(df); print('==============')
  12. df['c6'] = pd.DataFrame([11,12],index=['t2','t1']) # 给DataFrame定义正确的index,顺序无所谓
  13. print(df); print('==============')
  14. df['c7'] = pd.DataFrame([13,14]) # 未给DataFrame定义index,错误
  15. print(df)
  16. 执行结果:
  17. c1 c2
  18. t1 1 3
  19. t2 2 4
  20. ==============
  21. listtuplerange()的情况略
  22. ==============
  23. c1 c2 c3
  24. t1 1 3 5
  25. t2 2 4 6
  26. ==============
  27. c1 c2 c3 c4
  28. t1 1 3 5 8
  29. t2 2 4 6 7
  30. ==============
  31. c1 c2 c3 c4 c5
  32. t1 1 3 5 8 NaN
  33. t2 2 4 6 7 NaN
  34. ==============
  35. c1 c2 c3 c4 c5 c6
  36. t1 1 3 5 8 NaN 12
  37. t2 2 4 6 7 NaN 11
  38. ==============
  39. c1 c2 c3 c4 c5 c6 c7
  40. t1 1 3 5 8 NaN 12 NaN
  41. t2 2 4 6 7 NaN 11 NaN

③ 基于df.append()增加一行

语法:df.append(series),详见本章二、Pandas模块 - 12. DataFrame的合并 - (2)df.append()

④ 基于df.assign()增加一列

语法:df = df.assign(新列标签索引=表达式)

常用于根据现有的列进行表达式计算,产生新的列

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2],[3,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('==============')
  5. df = df.assign(c3 = df['c1']/df['c2'])
  6. print(df)
  7. 执行结果:
  8. c1 c2
  9. t1 1 2
  10. t2 3 4
  11. ==============
  12. c1 c2 c3
  13. t1 1 2 0.50
  14. t2 3 4 0.75

(3)删除若干行、删除若干列

① 仅删除一列:del

语法:

  • 当列标签为label index(列标签索引)时,只能使用label index删:del df['列标签索引']
  • 当列标签为position index(列位置索引)时,只能使用position index删:del df[列位置索引]

注意:del方法只能用于删除一列,不能使用索引、切片的方法删除多列

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,3,5,7,9],[2,4,6,8,10]])
  4. print(df); print('==============')
  5. del df[1]
  6. print(df); print('==============')
  7. df.columns=['c1','c2','c3','c4']
  8. df.index=['t1','t2']
  9. print(df); print('==============')
  10. del df['c2']
  11. print(df)
  12. 执行结果:
  13. 0 1 2 3 4
  14. 0 1 3 5 7 9
  15. 1 2 4 6 8 10
  16. ==============
  17. 0 2 3 4
  18. 0 1 5 7 9
  19. 1 2 6 8 10
  20. ==============
  21. c1 c2 c3 c4
  22. t1 1 5 7 9
  23. t2 2 6 8 10
  24. ==============
  25. c1 c3 c4
  26. t1 1 7 9
  27. t2 2 8 10

② 删除若干行、删除若干列:df.drop()

语法:

  • 当标签为label index(标签索引)时,只能使用label index删:

    1. df.drop('标签索引'或['标签索引','标签索引',...], axis=0, inplace=False)
  • 当标签为position index(位置索引)时,只能使用position index删:

    1. df.drop(位置索引或[位置索引,位置索引,...], axis=0, inplace=False)

参数:

  • axis:默认为0,按行删;axis=1时,按列删
  • inplace:默认值为False,不对df本身进行修改;inplace=True时,直接对df进行修改
  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame(np.arange(100,149).reshape(7, 7))
  4. print(df); print('==============')
  5. df = df.drop(0) # 删除第0行
  6. df = df.drop([1,2]) # 删除第1、2行
  7. print(df); print('==============')
  8. df = df.drop(0,axis=1) # 删除第0列
  9. df = df.drop([1,2],axis=1) # 删除第1、2列
  10. print(df); print('==============')
  11. df.columns=['c1','c2','c3','c4']
  12. df.index=['t1','t2','t3','t4']
  13. print(df); print('==============')
  14. df = df.drop('t1') # 删除't1'行
  15. df = df.drop(['t2','t3']) # 删除't2'、't3'列
  16. print(df); print('==============')
  17. df = df.drop('c1',axis=1) # 删除'c1'行
  18. df = df.drop(['c2','c3'],axis=1) # 删除'c2'、'c3'列
  19. print(df)
  20. 执行结果:
  21. 0 1 2 3 4 5 6
  22. 0 100 101 102 103 104 105 106
  23. 1 107 108 109 110 111 112 113
  24. 2 114 115 116 117 118 119 120
  25. 3 121 122 123 124 125 126 127
  26. 4 128 129 130 131 132 133 134
  27. 5 135 136 137 138 139 140 141
  28. 6 142 143 144 145 146 147 148
  29. ==============
  30. 0 1 2 3 4 5 6
  31. 3 121 122 123 124 125 126 127
  32. 4 128 129 130 131 132 133 134
  33. 5 135 136 137 138 139 140 141
  34. 6 142 143 144 145 146 147 148
  35. ==============
  36. 3 4 5 6
  37. 3 124 125 126 127
  38. 4 131 132 133 134
  39. 5 138 139 140 141
  40. 6 145 146 147 148
  41. ==============
  42. c1 c2 c3 c4
  43. t1 124 125 126 127
  44. t2 131 132 133 134
  45. t3 138 139 140 141
  46. t4 145 146 147 148
  47. ==============
  48. c1 c2 c3 c4
  49. t4 145 146 147 148
  50. ==============
  51. c4
  52. t4 148

(3)修改DataFrame数据的值

首先使用df[]、df.loc[]、df.iloc[]、df.ix[]等方法选择相应的数据,然后使用等号赋值即可

特别地,可以对布尔值索引的筛选结果进行赋值修改,如:

  1. # 将所有负数转化为正数
  2. df[df<0] = -df
  3. # 将所有PE小于0的PE数据赋值为1000
  4. df.loc[df['PE'<0],'PE'] = 1000
  5. # 新增一列new_column,并且令PE为负的行的new_column列为0(PE非负的行的new_column列的值将是NaN)
  6. df.loc[df['PE']<0,'new_column'] = 0

(4)对DataFrame数据的值进行替换:df.replace()

语法:

  1. df.replace('替换前的值', '替换后的值', inplace=False) # 单个值的替换
  2. df.replace({'旧1':'新1','旧2':'新2'...}, inplace=False) # 多个值的替换

若要同时进行多个值的替换,可以使用字典将替换前的值、替换后的值组成键值对

参数inplace:默认值为False,不对df本身进行修改;inplace=True时,直接对df进行修改

注意:仅对值进行替换,不会对标签索引或位置索引进行替换

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2],[3,4]])
  4. df.columns=[3,4]
  5. print(df); print('===========')
  6. df.replace(3,33,inplace=True)
  7. print(df); print('===========')
  8. df.replace({2:22,4:44},inplace=True)
  9. print(df)
  10. 执行结果:
  11. 3 4
  12. 0 1 2
  13. 1 3 4
  14. ===========
  15. 3 4
  16. 0 1 2
  17. 1 33 4
  18. ===========
  19. 3 4
  20. 0 1 22
  21. 1 33 44

(5)按指定列或行的数据值排序:df.sort_values()

语法:df.sort_values(by, axis=0, ascending=True, inplace=False)

参数:

  • by:可以是列标签或行标签(单列排序),也可以是列标签组成的list或行标签组成的list(多列排序),注意by与axis的对应关系(axis=0时by='列标签'['列标签1','列标签2',...],axis=1时by='行标签'['行标签1','行标签2',...]
  • axis:默认值为0,按指定列的数据值排序;axis=1时,按指定行的数据值排序
  • ascending:默认值为True,升序排列;ascending=False时,降序排列
  • inplace:默认值为False,不对df本身进行修改;inplace=True时,直接对df进行修改
  1. import numpy as np
  2. import pandas as pd
  3. np.random.seed(1)
  4. arr = np.random.randint(1,100,(4,4))
  5. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4'])
  6. df.index = pd.date_range('2019-1-31', periods=4, freq='M')
  7. print('df\n',df); print('===========')
  8. # 按c1列的值的升序排列
  9. df = df.sort_values(by='c1')
  10. # df.sort_values(by='c1',inplace=True) # 这样写也行
  11. print('按c1列的值的升序排列\n',df); print('===========')
  12. # 按2019-04-30行的值的降序排列
  13. df = df.sort_values(by=pd.datetime(2019,4,30),axis=1,ascending=False)
  14. # df.sort_values(by=pd.datetime(2019,4,30),axis=1,ascending=False,inplace=True) # 这样写也行
  15. print('按2019-04-30行的值的降序排列\n',df)
  16. 执行结果:
  17. df
  18. c1 c2 c3 c4
  19. 2019-01-31 38 13 73 10
  20. 2019-02-28 76 6 80 65
  21. 2019-03-31 17 2 77 72
  22. 2019-04-30 7 26 51 21
  23. ===========
  24. c1列的值的升序排列
  25. c1 c2 c3 c4
  26. 2019-04-30 7 26 51 21
  27. 2019-03-31 17 2 77 72
  28. 2019-01-31 38 13 73 10
  29. 2019-02-28 76 6 80 65
  30. ===========
  31. 2019-04-30行的值的降序排列
  32. c3 c2 c4 c1
  33. 2019-04-30 51 26 21 7
  34. 2019-03-31 77 2 72 17
  35. 2019-01-31 73 13 10 38
  36. 2019-02-28 80 6 65 76

(6)按DataFrame的标签排序:df.sort_index()

语法:df.sort_index(axis=0, ascending=True, inplace=False)

参数:

  • axis:默认值为0,按行标签排序;axis=1时,按列标签排序
  • ascending:默认值为True,升序排列;ascending=False时,降序排列
  • inplace:默认值为False,不对df本身进行修改;inplace=True时,直接对df进行修改
  1. import numpy as np
  2. import pandas as pd
  3. np.random.seed(1)
  4. arr = np.random.randint(1,100,(4,4))
  5. df = pd.DataFrame(arr,columns=['c1','c2','c3','c4'])
  6. df.index = pd.date_range('2019-1-31', periods=4, freq='M')
  7. print('df\n',df); print('===========')
  8. # 按行标签降序排列
  9. df = df.sort_index(ascending=False)
  10. # df.sort_index(ascending=False,inplace=True) # 这样写也行
  11. print('按行标签降序排列\n',df); print('===========')
  12. # 按列标签降序排列
  13. df = df.sort_index(axis=1, ascending=False)
  14. # df.sort_index(axis=1, ascending=False, inplace=True) # 这样写也行
  15. print('按列标签降序排列\n',df)
  16. 执行结果:
  17. df
  18. c1 c2 c3 c4
  19. 2019-01-31 38 13 73 10
  20. 2019-02-28 76 6 80 65
  21. 2019-03-31 17 2 77 72
  22. 2019-04-30 7 26 51 21
  23. ===========
  24. 按行标签降序排列
  25. c1 c2 c3 c4
  26. 2019-04-30 7 26 51 21
  27. 2019-03-31 17 2 77 72
  28. 2019-02-28 76 6 80 65
  29. 2019-01-31 38 13 73 10
  30. ===========
  31. 按列标签降序排列
  32. c4 c3 c2 c1
  33. 2019-04-30 21 51 26 7
  34. 2019-03-31 72 77 2 17
  35. 2019-02-28 65 80 6 76
  36. 2019-01-31 10 73 13 38

(7)自定义列标签和行标签:df.columns和df.index

这两个属性都支持对其整体进行重新赋值,但不支持对其中的元素进行修改(会报错),详见本章“DataFrame对象的属性”

(8)将某一列的值设置为行标签索引:df.set_index()

语法:df.set_index('选中列的列标签', inplace=False)

将某一列的值设置为行标签索引(注意:指定列是被“剪切”到最左边当索引的,不是“复制”)

参数inplace:默认值为False(不替换原df,须使用一个新的变量进行接收);值为True时,直接在原df上修改

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,'a',3+4j],[2,'b',5+6j]],columns=['c1','c2','c3'],index=['t1','t2'])
  4. print(df); print('===========')
  5. df.set_index('c2', inplace = True)
  6. print(df)
  7. 执行结果:
  8. c1 c2 c3
  9. t1 1 a 3.0+4.0j
  10. t2 2 b 5.0+6.0j
  11. ===========
  12. c1 c3
  13. c2
  14. a 1 3.0+4.0j
  15. b 2 5.0+6.0j

(9)重置行索引:df.reset_index()

语法:df.reset_index(inplace=False)

将行标签索引删除,并将其保存为DataFrame数据的第一列(该列对应的列标签索引为df.index.name),df.index则被重置为0、1、2……的位置索引

参数inplace:默认值为False(不替换原df,须使用一个新的变量进行接收);值为True时,直接在原df上修改

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,3,5,7],[2,4,6,8]],columns=['c1','c2','c3','c4'],index=['t1','t2'])
  4. df.index.name = 'myindex' # 为df.index这个Series设置名字
  5. print(df); print('===========')
  6. df.reset_index(inplace=True)
  7. print(df)
  8. 执行结果:
  9. c1 c2 c3 c4
  10. myindex
  11. t1 1 3 5 7
  12. t2 2 4 6 8
  13. ===========
  14. myindex c1 c2 c3 c4
  15. 0 t1 1 3 5 7
  16. 1 t2 2 4 6 8

(10)对列标签进行重命名:df.rename()

语法:df.rename(columns={'原列标签':'新列标签',...},inplace=False)

对列标签进行重命名。注意此方法仅能修改列标签columns,不能修改行标签index。

参数:

  • columns:一个字典,里面是原列标签和新列标签组成的键值对
  • inplace:默认值为False(不替换原df,须使用一个新的变量进行接收);值为True时,直接在原df上修改
  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2,3,4],[5,6,7,8]])
  4. df1 = pd.DataFrame(arr,columns=['c1','c2','c3','c4'],index=['t1','t2'])
  5. print("查看df1\n",df1); print('===========')
  6. df2 = df1.rename(columns={'c2':'哈','c5':'嘿','t2':'哼'})
  7. print("查看df2\n",df2)
  8. 执行结果:
  9. 查看df1
  10. c1 c2 c3 c4
  11. t1 1 2 3 4
  12. t2 5 6 7 8
  13. ===========
  14. 查看df2
  15. c1 c3 c4
  16. t1 1 2 3 4
  17. t2 5 6 7 8

(11)修改某列的数据类型:astype()

语法:df['列标签'] = df['列标签'].astype('新的数据类型')

由于astype()不会对原对象本身进行修改,因此只能通过这样的赋值操作来实现修改

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2.9],[3,4.9]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('==============')
  5. print(df.dtypes); print('==============')
  6. df['c1'] = df['c1'].astype('float') # 将c1列变为float
  7. df['c2'] = df['c2'].astype('int') # 将c2列变为int
  8. print(df); print('==============')
  9. print(df.dtypes)
  10. 执行结果:
  11. c1 c2
  12. t1 1 2.9
  13. t2 3 4.9
  14. ==============
  15. c1 int64
  16. c2 float64
  17. dtype: object
  18. ==============
  19. c1 c2
  20. t1 1.0 2
  21. t2 3.0 4
  22. ==============
  23. c1 float64
  24. c2 int32
  25. dtype: object

(12)删除值重复的行:df.drop_duplicates()

语法:df.drop_duplicates(subset=None, keep='first', inplace=False)

删除值重复的行,返回一个DataFrame

参数:

  • subset:子集,默认为None,此时两行的所有列的值都相等,才认为这两行重复;当subset='列标签'subset=['列标签','列标签',...]时,只要指定的列的值相等,就认为这两行重复
  • keep:重复时保留哪一行,默认为'first',保留第一行;当keep='last'时,保留最后一行;当keep=False时,不保留
  • inplace:默认值为False(不替换原df,须使用一个新的变量进行接收);值为True时,直接在原df上修改
  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2,3],[1,2,3],[1,2,3],[1,2,4]],columns=['c1','c2','c3'],index=['t1','t2','t3','t4'])
  4. print(df); print('===========')
  5. print(df.drop_duplicates()); print('===========')
  6. print(df.drop_duplicates(keep='last')); print('===========')
  7. print(df.drop_duplicates(keep=False)); print('===========')
  8. print(df.drop_duplicates(subset=['c1','c2']))
  9. 执行结果:
  10. c1 c2 c3
  11. t1 1 2 3
  12. t2 1 2 3
  13. t3 1 2 3
  14. t4 1 2 4
  15. ===========
  16. c1 c2 c3
  17. t1 1 2 3
  18. t4 1 2 4
  19. ===========
  20. c1 c2 c3
  21. t3 1 2 3
  22. t4 1 2 4
  23. ===========
  24. c1 c2 c3
  25. t4 1 2 4
  26. ===========
  27. c1 c2 c3
  28. t1 1 2 3

(13)将数据的值整体平移若干行(或列):df.shift()

语法:df.shift(periods=1,axis=0)

返回一个DataFrame,其行标签、列标签与df均相同,值向某方向平移了若干行(或列),平移导致空缺的行(或列)使用NaN填充

参数:

  • periods:值被平移的行数或列数,默认为1(int)
  • axis:默认值为0,纵向平移;axis=1时横向平移

注意:

  • period和axis两个参数共同决定了平移的方向:

    axis=0 axis=1
    period<0 向上平移 向左平移
    period=0 不平移 不平移
    period>0 向下平移 向右平移
  • 仅对DataFrame的值进行平移,行标签、列标签不跟着平移

  • 常使用df/df.shift()计算资产价格每日收益率,见下例:

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame({'600001': [10,11,12,13,14],'600002': [20,21,22,23,24],'600003':[30,31,32,33,34]},index=['t1','t2','t3','t4','t5'])
  4. print('df\n',df); print('-----------')
  5. print('向下平移1行:df.shift()\n',df.shift()); print('-----------')
  6. print('每日收益率df/df.shift()-1\n',df/df.shift()-1); print('===========')
  7. print('向上平移1行:df.shift(-1)\n',df.shift(-1)); print('-----------')
  8. print('向右平移1行:df.shift(1,axis=1)\n',df.shift(1,axis=1)); print('-----------')
  9. print('向左平移1行:df.shift(-1,axis=1)\n',df.shift(-1,axis=1))
  10. 执行结果:
  11. df
  12. 600001 600002 600003
  13. t1 10 20 30
  14. t2 11 21 31
  15. t3 12 22 32
  16. t4 13 23 33
  17. t5 14 24 34
  18. -----------
  19. 向下平移1行:df.shift()
  20. 600001 600002 600003
  21. t1 NaN NaN NaN
  22. t2 10.0 20.0 30.0
  23. t3 11.0 21.0 31.0
  24. t4 12.0 22.0 32.0
  25. t5 13.0 23.0 33.0
  26. -----------
  27. 每日收益率df/df.shift()-1
  28. 600001 600002 600003
  29. t1 NaN NaN NaN
  30. t2 0.100000 0.050000 0.033333
  31. t3 0.090909 0.047619 0.032258
  32. t4 0.083333 0.045455 0.031250
  33. t5 0.076923 0.043478 0.030303
  34. ===========
  35. 向上平移1行:df.shift(-1)
  36. 600001 600002 600003
  37. t1 11.0 21.0 31.0
  38. t2 12.0 22.0 32.0
  39. t3 13.0 23.0 33.0
  40. t4 14.0 24.0 34.0
  41. t5 NaN NaN NaN
  42. -----------
  43. 向右平移1行:df.shift(1,axis=1)
  44. 600001 600002 600003
  45. t1 NaN 10.0 20.0
  46. t2 NaN 11.0 21.0
  47. t3 NaN 12.0 22.0
  48. t4 NaN 13.0 23.0
  49. t5 NaN 14.0 24.0
  50. -----------
  51. 向左平移1行:df.shift(-1,axis=1)
  52. 600001 600002 600003
  53. t1 20.0 30.0 NaN
  54. t2 21.0 31.0 NaN
  55. t3 22.0 32.0 NaN
  56. t4 23.0 33.0 NaN
  57. t5 24.0 34.0 NaN

(14)将DataFrame转换为字典:df.to_dict()

语法:df.to_dict(orient='dict')

将DataFrame转换为字典

参数orient:转换成的字典的类型,默认值为'dict',还可以是'list'、'series'、'split'、'records'、'index',每个参数的效果见示例代码:

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2],[3,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('===========')
  5. print(df.to_dict(orient='dict')); print('===========')
  6. print(df.to_dict(orient='list')); print('===========')
  7. print(df.to_dict(orient='series')); print('===========')
  8. print(df.to_dict(orient='split')); print('===========')
  9. print(df.to_dict(orient='records')); print('===========')
  10. print(df.to_dict(orient='index'))
  11. 执行结果:
  12. c1 c2
  13. t1 1 2
  14. t2 3 4
  15. ===========
  16. {'c1': {'t1': 1, 't2': 3}, 'c2': {'t1': 2, 't2': 4}}
  17. ===========
  18. {'c1': [1, 3], 'c2': [2, 4]}
  19. ===========
  20. {'c1': t1 1
  21. t2 3
  22. Name: c1, dtype: int64, 'c2': t1 2
  23. t2 4
  24. Name: c2, dtype: int64}
  25. ===========
  26. {'index': ['t1', 't2'], 'columns': ['c1', 'c2'], 'data': [[1, 2], [3, 4]]}
  27. ===========
  28. [{'c1': 1, 'c2': 2}, {'c1': 3, 'c2': 4}]
  29. ===========
  30. {'t1': {'c1': 1, 'c2': 2}, 't2': {'c1': 3, 'c2': 4}}

(15)使用DataFrame中的若干列构建数据透视表:df.pivot()

语法:df.pivot(index='列标签', columns='列标签', values='列标签'或['列标签','列标签'...])

返回一个数据透视表形式的DataFrame

参数:

  • index:数据透视表的y轴(str)
  • columns:数据透视表的x轴(str)
  • values:数据透视表的数据值(str或list)
  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame({'foo': ['one', 'one', 'one', 'two', 'two','two'],
  4. 'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
  5. 'baz': [1, 2, 3, 4, 5, 6],
  6. 'zoo': ['x', 'y', 'z', 'q', 'w', 't']})
  7. print(df); print('===========')
  8. df1 = df.pivot(index='foo', columns='bar', values='baz')
  9. print(df1); print(type(df1)); print('===========')
  10. df2 = df.pivot(index='foo', columns='bar', values=['baz', 'zoo'])
  11. print(df2); print(type(df2))
  12. 执行结果:
  13. foo bar baz zoo
  14. 0 one A 1 x
  15. 1 one B 2 y
  16. 2 one C 3 z
  17. 3 two A 4 q
  18. 4 two B 5 w
  19. 5 two C 6 t
  20. ===========
  21. bar A B C
  22. foo
  23. one 1 2 3
  24. two 4 5 6
  25. <class 'pandas.core.frame.DataFrame'>
  26. ===========
  27. baz zoo
  28. bar A B C A B C
  29. foo
  30. one 1 2 3 x y z
  31. two 4 5 6 q w t
  32. <class 'pandas.core.frame.DataFrame'>

(16)对层次化索引的DataFrame进行变形(行标签与列标签的转换):df.unstack()和df.stack()

详见本章“13.层次化索引 - (3)使用unstack()和stack()对层次化索引的Series和DataFrame进行变形(行标签与列标签的转换)”

9. DataFrame的空值(NaN)处理

(1)手动输入NaN的方法

  • 输入numpy.nan
  • 将None作为list中的一个元素,并使用此list创建DataFrame,则相应位置的None会自动变为NaN

(2)df.isnull(), df.isna(), df.notna()

语法1:df.isnull(), df.isna()

判断每个df的每个元素是否为NaN(是NaN时返回True),返回一个结构与df相同的、由布尔值组成的DataFrame

语法2:df.notna()

判断每个df的每个元素是否为NaN(不是NaN时返回True),返回一个结构与df相同的、由布尔值组成的DataFrame

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[np.nan,2],[3,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('===========')
  5. print(df.isnull()); print('===========')
  6. print(df.isna()); print('===========')
  7. print(df.notna())
  8. 执行结果:
  9. c1 c2
  10. t1 NaN 2
  11. t2 3.0 4
  12. ===========
  13. c1 c2
  14. t1 True False
  15. t2 False False
  16. ===========
  17. c1 c2
  18. t1 True False
  19. t2 False False
  20. ===========
  21. c1 c2
  22. t1 False True
  23. t2 True True

(3)df.dropna()

语法:df.dropna(axis=0, how='any', inplace=False)

删除df中含有NaN的行(或列)

参数:

  • axis:默认值为0,按行删除;axis=1时按列删除
  • how:默认值为'any',只要这一行(或列)有一个元素是NaN,就删除整行(或列);当how='all'时,必须这一行(或列)所有元素都是NaN,才删除整行(或列)
  • inplace:默认值为False,此时不会对df本身进行修改,需要额外定义一个变量来接收结果;而当inplace=True时,则会直接对df本身进行修改
  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[np.nan,2],[3,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df); print('===========')
  5. df.dropna(inplace=True)
  6. print(df)
  7. 执行结果:
  8. c1 c2
  9. t1 NaN 2
  10. t2 3.0 4
  11. ===========
  12. c1 c2
  13. t2 3.0 4

(4)df.fillna()、df.ffill()、df.bfill()

对df中的NaN按照一定的规则进行替换

语法:df.fillna(value=None, method=None, axis=0, inplace=False),它和df.ffill(axis=)df.bfill(axis=)的关系见下面“注意”中的表格

参数:

  • value可以有两种形式:

    • value可以是一个固定的值,表示将df中的所有NaN统一替换成这个值
    • value可以是一个字典,字典的键是df的列标签,字典的值是将该列中NaN替换成的值(可以实现对不同的列中的NaN替换成不同的值)
    • value还可以是一个Series或DataFrame,此时遇到NaN会寻找对应位置的元素进行填充
  • method是填充方法,默认为None;当method='ffill'method='pad'时,向前填充,与df.ffill(axis=)等价;当method='bfill'时,向后填充,与df.bfill(axis=)等价
  • axis:坐标轴方向,默认值为0,纵向;axis=1时为横向
  • inplace默认值为False,此时不会对df本身进行修改,需要额外定义一个变量来接收结果;而当inplace=True时,则会直接对df本身进行修改

注意:

  • value和method两个参数能且只能输入一个,即二者不能同时为None,也不能同时不为None,否则报错

  • 当使用method时,method和axis两个参数共同决定了寻找填充值的方向:

    method='ffill' method='bfill'
    axis=0 取上方单元格的值填充NaN
    等价于df.ffill()
    取下方单元格的值填充NaN
    等价于df.bfill()
    axis=1 取左侧单元格的值填充NaN
    等价于df.ffill(axis=1)
    取右侧单元格的值填充NaN
    等价于df.bfill(axis=1)

    当指向的单元格仍为NaN时,继续越过该单元格向相同方向寻找填充值,若直到DataFrame的边界都是NaN,则不再进行填充,保留这些NaN

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[np.nan,101,102,np.nan],
  4. [110,np.nan,112,113],
  5. [120,121,np.nan,123],
  6. [np.nan,131,132,np.nan]],
  7. columns=['c1','c2','c3','c4'],index=['t1','t2','t3','t4'])
  8. df0 = df.fillna(0)
  9. df1 = df.fillna({'c1':-1,'c4':-4})
  10. df2 = df.fillna(method='ffill')
  11. df3 = df.fillna(method='bfill')
  12. df4 = df.fillna(method='ffill', axis=1)
  13. df5 = df.fillna(method='bfill', axis=1)
  14. df6 = df.ffill()
  15. df7 = df.bfill()
  16. df8 = df.ffill(axis=1)
  17. df9 = df.bfill(axis=1)
  18. print('df\n',df); print('===========')
  19. print('df0(替换为0)\n',df0); print('===========')
  20. print('df1(基于字典)\n',df1); print('===========')
  21. print('df2(向上)\n',df2); print('===========')
  22. print('df3(向下)\n',df3); print('===========')
  23. print('df4(向左)\n',df4); print('===========')
  24. print('df5(向右)\n',df5); print('===========')
  25. print('df6(向上)\n',df6); print('===========')
  26. print('df7(向下)\n',df7); print('===========')
  27. print('df8(向左)\n',df8); print('===========')
  28. print('df9(向右)\n',df9)
  29. 执行结果:
  30. df
  31. c1 c2 c3 c4
  32. t1 NaN 101.0 102.0 NaN
  33. t2 110.0 NaN 112.0 113.0
  34. t3 120.0 121.0 NaN 123.0
  35. t4 NaN 131.0 132.0 NaN
  36. ===========
  37. df0(替换为0)
  38. c1 c2 c3 c4
  39. t1 0.0 101.0 102.0 0.0
  40. t2 110.0 0.0 112.0 113.0
  41. t3 120.0 121.0 0.0 123.0
  42. t4 0.0 131.0 132.0 0.0
  43. ===========
  44. df1(基于字典)
  45. c1 c2 c3 c4
  46. t1 -1.0 101.0 102.0 -4.0
  47. t2 110.0 NaN 112.0 113.0
  48. t3 120.0 121.0 NaN 123.0
  49. t4 -1.0 131.0 132.0 -4.0
  50. ===========
  51. df2(向上)
  52. c1 c2 c3 c4
  53. t1 NaN 101.0 102.0 NaN
  54. t2 110.0 101.0 112.0 113.0
  55. t3 120.0 121.0 112.0 123.0
  56. t4 120.0 131.0 132.0 123.0
  57. ===========
  58. df3(向下)
  59. c1 c2 c3 c4
  60. t1 110.0 101.0 102.0 113.0
  61. t2 110.0 121.0 112.0 113.0
  62. t3 120.0 121.0 132.0 123.0
  63. t4 NaN 131.0 132.0 NaN
  64. ===========
  65. df4(向左)
  66. c1 c2 c3 c4
  67. t1 NaN 101.0 102.0 102.0
  68. t2 110.0 110.0 112.0 113.0
  69. t3 120.0 121.0 121.0 123.0
  70. t4 NaN 131.0 132.0 132.0
  71. ===========
  72. df5(向右)
  73. c1 c2 c3 c4
  74. t1 101.0 101.0 102.0 NaN
  75. t2 110.0 112.0 112.0 113.0
  76. t3 120.0 121.0 123.0 123.0
  77. t4 131.0 131.0 132.0 NaN
  78. ===========
  79. df6(向上)
  80. c1 c2 c3 c4
  81. t1 NaN 101.0 102.0 NaN
  82. t2 110.0 101.0 112.0 113.0
  83. t3 120.0 121.0 112.0 123.0
  84. t4 120.0 131.0 132.0 123.0
  85. ===========
  86. df7(向下)
  87. c1 c2 c3 c4
  88. t1 110.0 101.0 102.0 113.0
  89. t2 110.0 121.0 112.0 113.0
  90. t3 120.0 121.0 132.0 123.0
  91. t4 NaN 131.0 132.0 NaN
  92. ===========
  93. df8(向左)
  94. c1 c2 c3 c4
  95. t1 NaN 101.0 102.0 102.0
  96. t2 110.0 110.0 112.0 113.0
  97. t3 120.0 121.0 121.0 123.0
  98. t4 NaN 131.0 132.0 132.0
  99. ===========
  100. df9(向右)
  101. c1 c2 c3 c4
  102. t1 101.0 101.0 102.0 NaN
  103. t2 110.0 112.0 112.0 113.0
  104. t3 120.0 121.0 123.0 123.0
  105. t4 131.0 131.0 132.0 NaN

(5)df.interpolate()

interpolate:v.插值

语法:df.interpolate(method='linear', axis=0, inplace=False)

使用插值法对df中的NaN进行替换

参数:

  • method:插值方法,默认为'linear',线性插值,也可以选择其他方法
  • axis:插值方向,默认为0,纵向插值;axis=0时为横向插值
  • inplace默认值为False,此时不会对df本身进行修改,需要额外定义一个变量来接收结果;而当inplace=True时,则会直接对df本身进行修改

线性插值时,df边界行(或边界列)上的NaN的处理方法:

  • 若axis=0,则上边界行上的NaN保持不变,下边界行上的NaN取其上方的值对NaN进行替换(向上填充)
  • 若axis=1,则左边界列上的NaN保持不变,右边界列上的NaN取其左侧的值对NaN进行替换(向左填充)

关于时间序列低频调整为高频(升采样)的插值法,见本章“14. Pandas中的时间相关格式及方法-(9)df.resample()-低频调整为高频(升采样):通过线性插值实现

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[10,np.nan,30],[np.nan,50,np.nan],[70,np.nan,90]],columns=['c1','c2','c3'],index=['t1','t2','t3'])
  4. df1 = df.interpolate()
  5. df2 = df.interpolate(axis=1)
  6. print('df\n',df); print('===========')
  7. print('df1\n',df1); print('===========')
  8. print('df2\n',df2)
  9. 执行结果:
  10. df
  11. c1 c2 c3
  12. t1 10.0 NaN 30.0
  13. t2 NaN 50.0 NaN
  14. t3 70.0 NaN 90.0
  15. ===========
  16. df1
  17. c1 c2 c3
  18. t1 10.0 NaN 30.0
  19. t2 40.0 50.0 60.0
  20. t3 70.0 50.0 90.0
  21. ===========
  22. df2
  23. c1 c2 c3
  24. t1 10.0 20.0 30.0
  25. t2 NaN 50.0 50.0
  26. t3 70.0 80.0 90.0

10. DataFrame对象的方法和Pandas模块的方法

(0)一元通用函数

由于Pandas底层是NumPy,所以大部分numpy模块中的通用函数都适用于df,如:

求平方根:np.sqrt(df)

四舍五入:df.round(n)、np.round(df,n)

(1)一元通用函数补充

① 判断df中的每个元素是否在指定列表里

语法:df.isin(list)

返回一个与df结构相同的、由布尔值组成的DataFrame

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2],[3,4]],columns=['c1','c2'],index=['t1','t2'])
  4. print(df.isin([2,3,5,7,11,13,17]))
  5. 执行结果
  6. c1 c2
  7. t1 False True
  8. t2 True False

② 计算纵向相对百分比变化

语法:为df.pct_change(periods=1)

返回一个DataFrame,里面的每一项都是相对百分比变化,即:

\[新的DataFrame第m行n列的值=\frac{df第m行n列的值}{df第(m-periods)行n列的值}
\]

periods是从分子到分母所移动的行数,默认值为1。当periods>0时,相当于用某单元格的值 / 它上面某单元格的值;当periods<0时,相当于用某单元格的值 / 它下面某单元格的值

常使用df.pct_change()计算资产价格的每日收益率

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame({'600001': [10,11,12,13,14],'600002': [20,21,22,23,24],'600003':[30,31,32,33,34]},index=['t1','t2','t3','t4','t5'])
  4. print('df\n',df); print('===========')
  5. print(df.pct_change()); print('===========') # 常见的收益率计算方式
  6. print(df.pct_change(-1))
  7. 执行结果:
  8. df
  9. 600001 600002 600003
  10. t1 10 20 30
  11. t2 11 21 31
  12. t3 12 22 32
  13. t4 13 23 33
  14. t5 14 24 34
  15. ===========
  16. 600001 600002 600003
  17. t1 NaN NaN NaN
  18. t2 0.100000 0.050000 0.033333
  19. t3 0.090909 0.047619 0.032258
  20. t4 0.083333 0.045455 0.031250
  21. t5 0.076923 0.043478 0.030303
  22. ===========
  23. 600001 600002 600003
  24. t1 -0.090909 -0.047619 -0.032258
  25. t2 -0.083333 -0.045455 -0.031250
  26. t3 -0.076923 -0.043478 -0.030303
  27. t4 -0.071429 -0.041667 -0.029412
  28. t5 NaN NaN NaN

(2)二元通用函数

由于Pandas底层是NumPy,所以大部分numpy模块中的通用函数都适用于df

(3)统计相关方法

① df.min()和df.idxmin()

语法df.min(axis=0)

按列(或按行)计算给定的DataFrame中的最小值,返回一个Series

参数axis:

  • 默认值为0,即按列求最小。当给定的DataFrame为m行n列时,返回的Series长度为n,其索引为DataFrame的列标签,值为该列的最小值
  • 若axis=1,则按行求最小。当给定的DataFrame为m行n列时,返回的Series长度为m,其索引为DataFrame的行标签,值为该行的最小值

语法df.idxmin(axis=0)

按列(或按行)计算给定的DataFrame中的最小值所对应的行标签(或列标签),返回一个Series

参数axis:默认值为0,即按列求最小;若axis=1,则按行求最小

注意:df.argmin()方法已弃用,改为df.idxmin()方法

  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2],[4,3]])
  4. df = pd.DataFrame(arr,columns=['c1','c2'],index=['t1','t2'])
  5. print(df); print('===========')
  6. print(df.min()); print('-----------') # 寻找每一列最小的值
  7. print(df.min(axis=1)); print('===========') # 寻找每一行最小的值
  8. print(df.idxmin()); print('-----------') # 寻找每一列最小的值对应的行标签
  9. print(df.idxmin(axis=1)) # 寻找每一行最小的值对应的行标签
  10. 执行结果:
  11. c1 c2
  12. t1 1 2
  13. t2 4 3
  14. ===========
  15. c1 1
  16. c2 2
  17. dtype: int32
  18. -----------
  19. t1 1
  20. t2 3
  21. dtype: int32
  22. ===========
  23. c1 t1
  24. c2 t1
  25. dtype: object
  26. -----------
  27. t1 c1
  28. t2 c2
  29. dtype: object

② df.max()和df.idxmax()

语法:df.max(axis=0)

按列(或按行)计算给定的DataFrame中的最大值,返回一个Series

参数axis:

  • 默认值为0,即按列求最大。当给定的DataFrame为m行n列时,返回的Series长度为n,其索引为DataFrame的列标签,值为该列的最大值
  • 若axis=1,则按行求最大。当给定的DataFrame为m行n列时,返回的Series长度为m,其索引为DataFrame的行标签,值为该行的最大值

语法df.idxmax(axis=0)

按列(或按行)计算给定的DataFrame中的最大值所对应的行标签(或列标签),返回一个Series

参数axis:默认值为0,即按列求最大;若axis=1,则按行求最大

注意:df.argmax()方法已弃用,改为df.idxmax()方法

  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2],[4,3]])
  4. df = pd.DataFrame(arr,columns=['c1','c2'],index=['t1','t2'])
  5. print(df); print('===========')
  6. print(df.max()); print('-----------') # 寻找每一列最大的值
  7. print(df.max(axis=1)); print('===========') # 寻找每一行最大的值
  8. print(df.idxmax()); print('-----------') # 寻找每一列最大的值对应的行标签
  9. print(df.idxmax(axis=1)) # 寻找每一行最大的值对应的行标签
  10. 执行结果:
  11. c1 c2
  12. t1 1 2
  13. t2 4 3
  14. ===========
  15. c1 4
  16. c2 3
  17. dtype: int32
  18. -----------
  19. t1 2
  20. t2 4
  21. dtype: int32
  22. ===========
  23. c1 t2
  24. c2 t2
  25. dtype: object
  26. -----------
  27. t1 c2
  28. t2 c1
  29. dtype: object

③ df.sum()

语法:df.sum(axis=0)

按列(或按行)对给定的DataFrame中的数据求和,返回一个Series

参数axis:

  • 默认值为0,即按列求和。当给定的DataFrame为m行n列时,返回的Series长度为n,其索引为DataFrame的列标签,值为该列所有数据的和
  • 若axis=1,则按行求和。当给定的DataFrame为m行n列时,返回的Series长度为m,其索引为DataFrame的行标签,值为该行所有数据的和
  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2],[3,4]])
  4. df = pd.DataFrame(arr,columns=['c1','c2'],index=['t1','t2'])
  5. print(df); print('===========')
  6. print(df.sum(),type(df.sum())); print('===========') # 默认按列求和
  7. print(df.sum(axis=1)) # 按行求和
  8. 执行结果:
  9. c1 c2
  10. t1 1 2
  11. t2 3 4
  12. ===========
  13. c1 4
  14. c2 6
  15. dtype: int64 <class 'pandas.core.series.Series'>
  16. ===========
  17. t1 3
  18. t2 7

④ df.mean()

语法:df.mean(axis=0)

按列(或按行)对给定的DataFrame中的数据求算数平均,返回一个Series

参数axis:

  • 默认值为0,即按列求平均。当给定的DataFrame为m行n列时,返回的Series长度为n,其索引为DataFrame的列标签,值为该列所有数据的算数平均
  • 若axis=1,则按行求平均。当给定的DataFrame为m行n列时,返回的Series长度为m,其索引为DataFrame的行标签,值为该行所有数据的算数平均
  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[1,2],[3,4]])
  4. df = pd.DataFrame(arr,columns=['c1','c2'],index=['t1','t2'])
  5. print(df); print('===========')
  6. print(df.mean(),type(df.mean())); print('===========') # 默认按列求平均
  7. print(df.mean(axis=1),type(df.mean())) # 按行求平均
  8. 执行结果:
  9. c1 c2
  10. t1 1 2
  11. t2 3 4
  12. ===========
  13. c1 2.0
  14. c2 3.0
  15. dtype: float64 <class 'pandas.core.series.Series'>
  16. ===========
  17. t1 1.5
  18. t2 3.5
  19. dtype: float64 <class 'pandas.core.series.Series'>

⑤ df.count()

语法:df.count(axis=0)

按列(或按行)统计给定的DataFrame中非空数据的个数,返回一个Series

参数axis:

  • 默认值为0,即按列计数。当给定的DataFrame为m行n列时,返回的Series长度为n,其索引为DataFrame的列标签,值为该列非空数据的个数
  • 若axis=1,则按行计数。当给定的DataFrame为m行n列时,返回的Series长度为m,其索引为DataFrame的行标签,值为该行非空数据的个数
  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[np.nan,2],[3,4]]) # 手动输入NaN的方式
  4. df = pd.DataFrame(arr,columns=['c1','c2'],index=['t1','t2'])
  5. print(df); print('===========')
  6. print(df.count(),type(df.count())); print('===========') # 默认按列计数
  7. print(df.count(axis=1)) # 按行计数
  8. 执行结果:
  9. c1 c2
  10. t1 NaN 2.0
  11. t2 3.0 4.0
  12. ===========
  13. c1 1
  14. c2 2
  15. dtype: int64 <class 'pandas.core.series.Series'>
  16. ===========
  17. t1 1
  18. t2 2
  19. dtype: int64

⑥ 累积计算:df.cumsum()、df.cumprod()、df.cummax()、df.cummin()

语法:df.cumXXX(axis=0)

按列(或按行)计算给定的DataFrame累积和、累积积、累积最大、累积最小,返回一个DataFrame

参数axis:默认值为0,即按列计算;若axis=1,则按行计算

注意:

  • 累积最大指从第一个数据到当前数据这段区间内的最大,累积最小同理
  • 累积最大、累积最小是DataFrame特有的方法,numpy.ndarray没有这两种方法
  • 累积最大常用于计算最大回撤(max drawdown)
  • 和numpy.ndarray不同,DataFrame不会将多维数据变为一维再计算其累积值
  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame({'c1':[1,-2,3,4,-5,6],'c2':[10,20,-30,-40,50,-60]},index=['t1','t2','t3','t4','t5','t6'])
  4. df1 = df.cumsum()
  5. df2 = df.cumsum(axis=1)
  6. df3 = df.cumprod()
  7. df4 = df.cummax()
  8. df5 = df.cummin()
  9. print('df\n', df); print('===========')
  10. print('df1\n', df1); print('===========')
  11. print('df2\n', df2); print('===========')
  12. print('df3\n', df3); print('===========')
  13. print('df4\n', df4); print('===========')
  14. print('df5\n', df5)
  15. 执行结果:
  16. df
  17. c1 c2
  18. t1 1 10
  19. t2 -2 20
  20. t3 3 -30
  21. t4 4 -40
  22. t5 -5 50
  23. t6 6 -60
  24. ===========
  25. df1
  26. c1 c2
  27. t1 1 10
  28. t2 -1 30
  29. t3 2 0
  30. t4 6 -40
  31. t5 1 10
  32. t6 7 -50
  33. ===========
  34. df2
  35. c1 c2
  36. t1 1 11
  37. t2 -2 18
  38. t3 3 -27
  39. t4 4 -36
  40. t5 -5 45
  41. t6 6 -54
  42. ===========
  43. df3
  44. c1 c2
  45. t1 1 10
  46. t2 -2 200
  47. t3 -6 -6000
  48. t4 -24 240000
  49. t5 120 12000000
  50. t6 720 -720000000
  51. ===========
  52. df4
  53. c1 c2
  54. t1 1 10
  55. t2 1 20
  56. t3 3 20
  57. t4 4 20
  58. t5 4 50
  59. t6 6 50
  60. ===========
  61. df5
  62. c1 c2
  63. t1 1 10
  64. t2 -2 10
  65. t3 -2 -30
  66. t4 -2 -40
  67. t5 -5 -40
  68. t6 -5 -60

⑦ df.corr() 相关系数矩阵

语法:df.corr()

返回df每一列的相关系数矩阵(DataFrame格式)

注意:也可以直接使用Series的corr()方法计算两个Series的相关系数,其用法为s1.corr(s2)

  1. # 计算上证指数、深圳成指、沪深300指数的相关系数矩阵
  2. import numpy as np
  3. import pandas as pd
  4. import tushare as ts
  5. df_close = pd.DataFrame({
  6. 'sh':ts.get_k_data('sh', start='2019-01-01',end='2019-06-30')['close'],
  7. 'sz':ts.get_k_data('sz', start='2019-01-01',end='2019-06-30')['close'],
  8. 'hs300':ts.get_k_data('hs300', start='2019-01-01',end='2019-06-30')['close'],
  9. })
  10. df_return = df_close.pct_change().fillna(0)
  11. df_corr = df_return.corr()
  12. print(df_return.head()); print('===========')
  13. print(df_corr); print(type(df_corr))
  14. 执行结果:
  15. sh sz hs300
  16. 0 0.000000 0.000000 0.000000
  17. 1 -0.000377 -0.008369 -0.001583
  18. 2 0.020496 0.027562 0.023957
  19. 3 0.007245 0.015836 0.006071
  20. 4 -0.002617 -0.001155 -0.002161
  21. ===========
  22. sh sz hs300
  23. sh 1.000000 0.953529 0.976994
  24. sz 0.953529 1.000000 0.941665
  25. hs300 0.976994 0.941665 1.000000
  26. <class 'pandas.core.frame.DataFrame'>

⑧ df.describe()

语法:df.describe(percentiles=None)

按列统计给定的DataFrame中各项描述性统计信息(包括count()、mean()、std()、min()、50%、max()和自定义的百分位数),返回一个DataFrame

参数percentiles:自定义的百分比列表,是一个由float组成的list。默认值为None,此时默认的自定义百分比是25%、75%。

注意:此方法无axis参数,无法按行统计

  1. import numpy as np
  2. import pandas as pd
  3. arr = np.array([[np.nan,2],[3,4],[5,6]])
  4. df = pd.DataFrame(arr,columns=['c1','c2'],index=['t1','t2','t3'])
  5. print(df); print('===========')
  6. print(df.describe(),'\n',type(df.describe())); print('===========')
  7. print(df.describe(percentiles=[0.05,0.95]),'\n',type(df.describe(percentiles=[0.05,0.95])))
  8. 执行结果:
  9. c1 c2
  10. t1 NaN 2.0
  11. t2 3.0 4.0
  12. t3 5.0 6.0
  13. ===========
  14. c1 c2
  15. count 2.000000 3.0
  16. mean 4.000000 4.0
  17. std 1.414214 2.0
  18. min 3.000000 2.0
  19. 25% 3.500000 3.0
  20. 50% 4.000000 4.0
  21. 75% 4.500000 5.0
  22. max 5.000000 6.0
  23. <class 'pandas.core.frame.DataFrame'>
  24. ===========
  25. c1 c2
  26. count 2.000000 3.0
  27. mean 4.000000 4.0
  28. std 1.414214 2.0
  29. min 3.000000 2.0
  30. 5% 3.100000 2.2
  31. 50% 4.000000 4.0
  32. 95% 4.900000 5.8
  33. max 5.000000 6.0
  34. <class 'pandas.core.frame.DataFrame'>

⑨ df.resample():重采样

见本章“14. Pandas中的时间相关格式及方法-(9)df.resample()-低频调整为高频(升采样):通过线性插值实现”

此外,关于DataFrame填充空值的插值法df.interpolate(),见本章“9. DataFrame的空值(NaN)处理 - (5)df.interpolate()”

⑩ df.rolling():滑动时间窗

见本章“14. Pandas中的时间相关格式及方法 -(10)df.rolling():滑动时间窗”

(4)将DataFrame存储为本地文件

包括两类方法:

  • df.to_xxx()系列方法
  • 基于HDF5的存储方法

详见“AQF笔记-第2部分-第7章-金融数据源处理实现-二、金融数据的存储

(5)其他重要方法

① df.apply()

语法:df.apply(func, axis=0)

将df逐列(或逐行)以Series的形式传递给func作为其参数并执行func(),并将每次func()的返回值组成一个Series,作为df.apply()整体的返回值。

参数:

  • func:已定义的函数名,也可以是一个匿名函数
  • axis:默认值为0,逐列传递;axis=1时,逐行传递

此外,对于DataFrame分组聚合时建立的分组对象group_obj,也有类似的apply()方法(一个不同之处在于group_obj.apply(func)没有axis参数),其原理及应用详见本章“11. DataFrame的分组、聚合 - (3)分组对象group_obj的应用 - ⑤ 使用group_obj.apply()

  1. import numpy as np
  2. import pandas as pd
  3. # 从CSV文件读取数据,进行处理后,保留前5行的'code','name','roe'三列
  4. data = pd.read_csv('2019Q1.csv')
  5. data = data.sort_values('code').reset_index()
  6. data = data[['code','name','roe']].head(5)
  7. print(data); print('===========')
  8. # 按ROE对股票进行分类的函数
  9. def map_func(x):
  10. print('----map_func内部开始----')
  11. print(x)
  12. print(type(x))
  13. print('----map_func内部结束----')
  14. if x['roe'] > 4:
  15. return '高成长'
  16. elif x['roe'] >= 0:
  17. return '低成长'
  18. elif x['roe'] < 0:
  19. return '亏损'
  20. # 执行data.apply(),axis=1代表按行取Series传给map_func()
  21. result = data.apply(map_func, axis=1)
  22. print('===========')
  23. print(result)
  24. print(type(result))
  25. print('===========')
  26. # 根据 ROE 数据计算“成长性”,并将此列添加到data
  27. data['成长性'] = result # 相当于data['成长性'] = data.apply(map_func, axis=1)
  28. print(data)
  29. 执行结果:
  30. code name roe
  31. 0 1 平安银行 2.96
  32. 1 2 万科A 0.71
  33. 2 4 国农科技 4.66
  34. 3 5 世纪星源 -1.20
  35. 4 6 深振业A 1.75
  36. ===========
  37. ----map_func内部开始----
  38. code 1
  39. name 平安银行
  40. roe 2.96
  41. Name: 0, dtype: object
  42. <class 'pandas.core.series.Series'>
  43. ----map_func内部结束----
  44. ----map_func内部开始----
  45. code 2
  46. name 万科A
  47. roe 0.71
  48. Name: 1, dtype: object
  49. <class 'pandas.core.series.Series'>
  50. ----map_func内部结束----
  51. ----map_func内部开始----
  52. code 4
  53. name 国农科技
  54. roe 4.66
  55. Name: 2, dtype: object
  56. <class 'pandas.core.series.Series'>
  57. ----map_func内部结束----
  58. ----map_func内部开始----
  59. code 5
  60. name 世纪星源
  61. roe -1.2
  62. Name: 3, dtype: object
  63. <class 'pandas.core.series.Series'>
  64. ----map_func内部结束----
  65. ----map_func内部开始----
  66. code 6
  67. name 深振业A
  68. roe 1.75
  69. Name: 4, dtype: object
  70. <class 'pandas.core.series.Series'>
  71. ----map_func内部结束----
  72. ===========
  73. 0 低成长
  74. 1 低成长
  75. 2 高成长
  76. 3 亏损
  77. 4 低成长
  78. dtype: object
  79. <class 'pandas.core.series.Series'>
  80. ===========
  81. code name roe 成长性
  82. 0 1 平安银行 2.96 低成长
  83. 1 2 万科A 0.71 低成长
  84. 2 4 国农科技 4.66 高成长
  85. 3 5 世纪星源 -1.20 亏损
  86. 4 6 深振业A 1.75 低成长

② df.applymap()

语法:df.applymap(func)

将df中的每个元素分别传递给func作为其参数并执行func(),并将每次func()的返回值组成一个结构相同的新的DataFrame,作为df.applymap()整体的返回值。

参数:func:已定义的函数名,也可以是一个匿名函数

  1. import numpy as np
  2. import pandas as pd
  3. df1 = pd.DataFrame([[10,20],[30,40]],columns=['c1','c2'],index=['t1','t2'])
  4. df2 = df1.applymap(lambda x:x+1)
  5. print(df1); print('===========')
  6. print(df2)
  7. 执行结果:
  8. c1 c2
  9. t1 10 20
  10. t2 30 40
  11. ===========
  12. c1 c2
  13. t1 11 21
  14. t2 31 41

关于apply()、applymap()和map()的总结:

apply() applymap() map()
Python内置函数 NA NA 遍历每一个元素
Series方法 遍历每一个元素 NA 遍历每一个元素
DataFrame方法 遍历行或列 遍历每一个元素 NA

③ df.iterrows()

语法:df.iterrows()

返回一个生成器(generator),该生成器使用df逐行生成一个元组,其中元组第0项是df的行索引,元组第1项是该行数据组成的Series(df的值也是Series的值,df的列索引则是Series的索引)。上述索引中,有标签索引的优先使用标签索引,否则使用位置索引。通常使用两个变量以拆包的方式分别接收两个返回值。

df.iterrows() 通常用于循环遍历df的每一行数据。

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[10,20,30],[40,50,60],[70,80,90]],columns=['c1','c2','c3'],index=['t1','t2','t3'])
  4. print(df); print('===========')
  5. print(df.iterrows()); print('===========')
  6. for i,j in df.iterrows():
  7. print(i); print('-----------')
  8. print(type(i)); print('-----------')
  9. print(j); print('-----------')
  10. print(type(j)); print('===========')
  11. 执行结果:
  12. c1 c2 c3
  13. t1 10 20 30
  14. t2 40 50 60
  15. t3 70 80 90
  16. ===========
  17. <generator object DataFrame.iterrows at 0x000000001431ECA8>
  18. ===========
  19. t1
  20. -----------
  21. <class 'str'>
  22. -----------
  23. c1 10
  24. c2 20
  25. c3 30
  26. Name: t1, dtype: int64
  27. -----------
  28. <class 'pandas.core.series.Series'>
  29. ===========
  30. t2
  31. -----------
  32. <class 'str'>
  33. -----------
  34. c1 40
  35. c2 50
  36. c3 60
  37. Name: t2, dtype: int64
  38. -----------
  39. <class 'pandas.core.series.Series'>
  40. ===========
  41. t3
  42. -----------
  43. <class 'str'>
  44. -----------
  45. c1 70
  46. c2 80
  47. c3 90
  48. Name: t3, dtype: int64
  49. -----------
  50. <class 'pandas.core.series.Series'>
  51. ===========

④ df.all()

语法:df.all(axis=0)

返回一个布尔值组成的Series

参数axis:

  • 默认值为0,按列计算,Series的索引为df的列索引,当df中该列所有值均为True时,Series中对应项为True,否则为False
  • 若axis=1,按行计算,Series的索引为df的行索引,当df中该行所有值均为True时,Series中对应项为True,否则为False
  1. import numpy as np
  2. import pandas as pd
  3. a = pd.DataFrame([[0,0],[1,1]],columns=['c1','c2'],index=['t1','t2'])
  4. b = pd.DataFrame([[1,1],[1,1]],columns=['c1','c2'],index=['t1','t2'])
  5. print(a); print('-----------')
  6. print(a.all()); print('-----------')
  7. print(a.all(axis=1)); print('===========')
  8. print(b); print('-----------')
  9. print(b.all()); print('-----------')
  10. print(b.all(axis=1))
  11. 执行结果:
  12. c1 c2
  13. t1 0 0
  14. t2 1 1
  15. -----------
  16. c1 False
  17. c2 False
  18. dtype: bool
  19. -----------
  20. t1 False
  21. t2 True
  22. dtype: bool
  23. ===========
  24. c1 c2
  25. t1 1 1
  26. t2 1 1
  27. -----------
  28. c1 True
  29. c2 True
  30. dtype: bool
  31. -----------
  32. t1 True
  33. t2 True
  34. dtype: bool

⑤ df.any()

语法:df.any(axis=0)

返回一个布尔值组成的Series

参数axis:

  • 默认值为0,按列计算,Series的索引为df的列索引,当df中该列任意一个值为True时,Series中对应项为True,否则为False
  • 若axis=1,按行计算,Series的索引为df的行索引,当df中该行任意一个值为True时,Series中对应项为True,否则为False
  1. import numpy as np
  2. import pandas as pd
  3. a = pd.DataFrame([[0,0],[1,1]],columns=['c1','c2'],index=['t1','t2'])
  4. b = pd.DataFrame([[0,0],[0,0]],columns=['c1','c2'],index=['t1','t2'])
  5. print(a); print('-----------')
  6. print(a.any()); print('-----------')
  7. print(a.any(axis=1)); print('===========')
  8. print(b); print('-----------')
  9. print(b.any()); print('-----------')
  10. print(b.any(axis=1))
  11. 执行结果:
  12. c1 c2
  13. t1 0 0
  14. t2 1 1
  15. -----------
  16. c1 True
  17. c2 True
  18. dtype: bool
  19. -----------
  20. t1 False
  21. t2 True
  22. dtype: bool
  23. ===========
  24. c1 c2
  25. t1 0 0
  26. t2 0 0
  27. -----------
  28. c1 False
  29. c2 False
  30. dtype: bool
  31. -----------
  32. t1 False
  33. t2 False
  34. dtype: bool

df.__len__()和len(df)

返回df的长度(int类型),它等于df的行数,即df.shape()返回的元组的第0项

⑦ df.head()

语法:df.head(n=5)

获取df的前n行,n的默认值为5,返回DataFrame类型。示例代码见“6.DataFrame的数据选择 - (5)使用df的属性和方法进行数据选择”

该方法主要用于快速预览一个行数较多的DataFrame

⑧ df.tail()

语法:df.tail(n=5)

获取df的后n行,n的默认值为5,返回DataFrame类型。示例代码见“6.DataFrame的数据选择 - (5)使用df的属性和方法进行数据选择”

该方法主要用于快速预览一个行数较多的DataFrame

⑨ df.info()

自动在屏幕输出df的一些基本信息

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,2],[3,4]], columns=['c1','c2'], index=['t1','t2'])
  4. df.info()
  5. 执行结果:
  6. <class 'pandas.core.frame.DataFrame'>
  7. Index: 2 entries, t1 to t2
  8. Data columns (total 2 columns):
  9. c1 2 non-null int64
  10. c2 2 non-null int64
  11. dtypes: int64(2)
  12. memory usage: 48.0+ bytes

⑩ df.duplicated()

语法:df.duplicated(subset=None, keep='first')

判断df中的每一行的值是否重复,返回一个bool组成的Series

参数:

  • subset:子集,默认为None,此时两行的所有列的值都相等,才认为这两行重复;当subset='列标签'subset=['列标签','列标签',...]时,只要指定的列的值相等,就认为这两行重复
  • keep:重复时的标记方式,默认为'first'
    • 'first':在重复的行中,除了第一行标记为False,其他行都标记为True
    • 'last':在重复的行中,除了最后一行标记为False,其他行都标记为True
    • False:在重复的行中,所有行均标记为True
  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([[1,3],[2,3],[2,3],[1,4],[2,4]])
  4. df.columns = ['c1','c2']
  5. df.index = ['t1','t2','t3','t4','t5']
  6. print(df)
  7. print('---\n',df.duplicated()) # 所有列值都相等视为重复
  8. print('---\n',df.duplicated(subset=['c1'])) # 'c1'列值相等视为重复
  9. print('---\n',df.duplicated(subset=['c2'])) # 'c1'列值相等视为重复
  10. print('---\n',df.duplicated(subset=['c1','c2'])) # 'c1','c2'列值都相等视为重复
  11. 执行结果:
  12. c1 c2
  13. t1 1 3
  14. t2 2 3
  15. t3 2 3
  16. t4 1 4
  17. t5 2 4
  18. ---
  19. t1 False
  20. t2 False
  21. t3 True
  22. t4 False
  23. t5 False
  24. dtype: bool
  25. ---
  26. t1 False
  27. t2 False
  28. t3 True
  29. t4 True
  30. t5 True
  31. dtype: bool
  32. ---
  33. t1 False
  34. t2 True
  35. t3 True
  36. t4 False
  37. t5 True
  38. dtype: bool
  39. ---
  40. t1 False
  41. t2 False
  42. t3 True
  43. t4 False
  44. t5 False
  45. dtype: bool

⑾ df.rank()

语法:

  1. df.rank(axis=0,method='average',numeric_only=None,na_option='keep',ascending=True,pct=False)

返回一个形状与df相同的DataFrame,里面的数据是其在本列(或本行)所有数据中的排名

参数:

  • axis:默认值为0,按列数据计算排名;axis=1时,按行数据计算排名
  • method:存在并列时排名的计算方法,默认值为'average',取值可以为'average','first','min', 'max','dense'。假设参与升序排名的数据为100、150、150、200:
    • average:平均排名,当存在并列时,取这些并列项的顺序排名的平均值(1、2.5、2.5、4)
    • first:顺序排名,当存在并列时,谁在DataFrame中的顺序靠前,谁的顺序排名也靠前(1、2、3、4),注意method='first'时不支持非数字类型的排名
    • min:最小排名,当存在并列时,取这些并列项的顺序排名的最小值(1、2、2、4)
    • max:最大排名,当存在并列时,取这些并列项的顺序排名的最大值(1、3、3、4)
    • dense:密集排名,后一项的排名总是与前一项相同或加一,不跳跃(1、2、2、3)
  • numeric_only:bool,是否仅仅计算数字类型的columns
  • na_option:NaN值是否参与排序及如何排序,默认值'keep',取值可以为'keep'、'top'、'bottom':
    • 'keep':NaN的排名还是NaN
    • 'top':把NaN放在排名首位
    • 'bottom':把NaN放在排名末位
  • ascending:bool,是否升序,默认值True
  • pct:bool,是否以百分比方式显示排名,默认值False

注意:df.rank()只能实现每个字段分别排名,无法实现多字段联合排名,后者的功能需要通过df.groupby(['排序字段1','排序字段2',...]).ngroup()实现

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame({'animal': ['cat', 'penguin', 'dog','spider', 'snake'],
  4. 'legs': [4, 2, 4, 8, np.nan]})
  5. print("df\n",df,'\n----')
  6. print("df.rank(method='average')\n",df.rank(method='average'),'\n----')
  7. print("df.legs.rank(method='first')\n",df.legs.rank(method='first'),'\n----')
  8. print("df.rank(method='min')\n",df.rank(method='min'),'\n----')
  9. print("df.rank(method='max')\n",df.rank(method='max'),'\n----')
  10. print("df.rank(method='dense')\n",df.rank(method='dense'),'\n====')
  11. print("df.rank(method='min',na_option='top')\n",df.rank(method='min',na_option='top'),'\n----')
  12. print("df.rank(method='min',na_option='bottom')\n",df.rank(method='min',na_option='bottom'),'\n====')
  13. print("df.rank(method='min',pct=True)\n",df.rank(method='min',pct=True))
  14. 执行结果:
  15. df
  16. animal legs
  17. 0 cat 4.0
  18. 1 penguin 2.0
  19. 2 dog 4.0
  20. 3 spider 8.0
  21. 4 snake NaN
  22. ----
  23. df.rank(method='average')
  24. animal legs
  25. 0 1.0 2.5
  26. 1 3.0 1.0
  27. 2 2.0 2.5
  28. 3 5.0 4.0
  29. 4 4.0 NaN
  30. ----
  31. df.legs.rank(method='first')
  32. 0 2.0
  33. 1 1.0
  34. 2 3.0
  35. 3 4.0
  36. 4 NaN
  37. Name: legs, dtype: float64
  38. ----
  39. df.rank(method='min')
  40. animal legs
  41. 0 1.0 2.0
  42. 1 3.0 1.0
  43. 2 2.0 2.0
  44. 3 5.0 4.0
  45. 4 4.0 NaN
  46. ----
  47. df.rank(method='max')
  48. animal legs
  49. 0 1.0 3.0
  50. 1 3.0 1.0
  51. 2 2.0 3.0
  52. 3 5.0 4.0
  53. 4 4.0 NaN
  54. ----
  55. df.rank(method='dense')
  56. animal legs
  57. 0 1.0 2.0
  58. 1 3.0 1.0
  59. 2 2.0 2.0
  60. 3 5.0 3.0
  61. 4 4.0 NaN
  62. ====
  63. df.rank(method='min',na_option='top')
  64. animal legs
  65. 0 1.0 3.0
  66. 1 3.0 2.0
  67. 2 2.0 3.0
  68. 3 5.0 5.0
  69. 4 4.0 1.0
  70. ----
  71. df.rank(method='min',na_option='bottom')
  72. animal legs
  73. 0 1.0 2.0
  74. 1 3.0 1.0
  75. 2 2.0 2.0
  76. 3 5.0 4.0
  77. 4 4.0 5.0
  78. ====
  79. df.rank(method='min',pct=True)
  80. animal legs
  81. 0 0.2 0.50
  82. 1 0.6 0.25
  83. 2 0.4 0.50
  84. 3 1.0 1.00
  85. 4 0.8 NaN

11. DataFrame的分组、聚合

(1)分组对象group_obj的创建

DataFrame的分组、聚合都是基于分组对象group_obj实现的(它是pandas.core.groupby.generic. DataFrameGroupBy类的一个实例化对象),因此首先应创建分组对象group_obj,语法为:

  • 按照一列进行分组时:group_obj = df.groupby('列标签')
  • 按照多列联合分组时:group_obj = df.groupby(['列标签','列标签',...])

(2)分组对象group_obj的构成

假设按照创建分组对象group_obj时定义的分组规则,一共可以分成n组,则group_obj就是一个由n个元组组成的可迭代对象,其中每个元组的第0项是一种分组下的列标签(或元组形式的多个列标签的组合),每个元组第1项是该分组下对应的DataFrame。

(3)分组对象group_obj的应用

① 使用group_obj的指定方法查看df的一项统计信息

  • group_obj.size():每个分组的记录数(含带空值的记录)(Series类型)
  • group_obj.max():每个分组的最大值(DataFrame类型)
  • group_obj.min():每个分组的最小值(DataFrame类型)
  • group_obj.sum():每个分组的求和(DataFrame类型)
  • group_obj.mean():每个分组的平均值(DataFrame类型)
  • group_obj.std():每个分组的标准差(DataFrame类型)
  • group_obj.count():每个分组的非空记录数(DataFrame类型)
  • group_obj.cumsum():逐行的累加和(与原DataFrame行数相等的DataFrame)
  • group_obj.cumprod():逐行的累乘积(与原DataFrame行数相等的DataFrame)
  • group_obj.cumcount():从0开始的逐行的累加计数(与原DataFrame行数相等的Series)

② 使用group_obj.describe()查看df的全部统计信息

  • group_obj.describe():横向查看,因表格过长,不推荐(DataFrame类型)
  • group_obj.describe().T:纵向查看,推荐(DataFrame类型)

③ 使用group_obj.agg()查看自定义项目的统计信息

  • group_obj.agg([np.mean, np.std]):查看所有字段的均值和标准差(DataFrame类型)
  • group_obj.agg({'c1':np.mean, 'c2':np.std}):查看'c1'字段的均值和'c2'字段的标准差(DataFrame类型)

④ 使用group_obj.get_group()获取指定分组的数据

  • 按照一列进行分组时获取数据:group_obj.get_group('分组字段的某个值')
  • 按照多列联合分组时获取数据:group_obj.get_group(('分组字段1的某个值','分组字段2的某个值',...))

⑤ 使用group_obj.ngroup()实现多字段联合排名

语法:group_obj.ngroup(ascending=True)

返回一个Series。根据创建group_obj时的几个分组字段,比较每个字段的值,当第一个字段的值相等时比较第二个字段,当第二个字段相等时比较第三个字段……若所有分组字段的值都相等,则两条记录的排名也相同(注意:排名是从0开始的)

  1. import numpy as np
  2. import pandas as pd
  3. # 创建DataFrame
  4. data = [('a', 70, 5),
  5. ('b', 80, 4),
  6. ('c', 70, 4),
  7. ('d', 70, 5),
  8. ('e', 80, 5),
  9. ('f', 75, 4)]
  10. df = pd.DataFrame(data, columns=['name', 'score', 'homework'])
  11. df = df.sort_values(['score', 'homework'], ascending=False)
  12. print(df, '\n----------')
  13. s = df.groupby(['score', 'homework']).ngroup(ascending=False)
  14. print(s, '\n----------\n', type(s), '\n----------')
  15. df['ranking'] = s + 1
  16. print(df)
  17. 执行结果:
  18. name score homework
  19. 4 e 80 5
  20. 1 b 80 4
  21. 5 f 75 4
  22. 0 a 70 5
  23. 3 d 70 5
  24. 2 c 70 4
  25. ----------
  26. 4 0
  27. 1 1
  28. 5 2
  29. 0 3
  30. 3 3
  31. 2 4
  32. dtype: int64
  33. ----------
  34. <class 'pandas.core.series.Series'>
  35. ----------
  36. name score homework ranking
  37. 4 e 80 5 1
  38. 1 b 80 4 2
  39. 5 f 75 4 3
  40. 0 a 70 5 4
  41. 3 d 70 5 4
  42. 2 c 70 4 5

⑥ 使用group_obj.apply()实现自定义功能

语法:group_obj.apply(func)

参数func:已定义的函数名,也可以是一个匿名函数

将构成group_obj的每个元组中的DataFrame分别传递给func作为其参数并执行func(),然后将每次func()的返回值纵向拼接成一个DataFrame或Series,并为其在列标签的最外层添加分组列组成的列标签索引(联合分组时则在列标签的最外层添加多层列标签索引),然后将其作为group_obj.apply()整体的返回值。group_obj.apply()的应用见下面的例3。

此外,对于DataFrame对象,也有类似的apply()方法(一个不同之处在于df.apply(func,axis=0)有axis参数),其原理及应用详见本章“10. DataFrame对象的方法和Pandas模块的方法 -(5)其他方法 - ① df.apply()

  1. # 例1:本例仅用于研究分组对象group_obj的构成(group_obj的应用见例2)
  2. import numpy as np
  3. import pandas as pd
  4. # 创建数据集
  5. np.random.seed(0)
  6. period = pd.date_range('2019-9-22', periods=1000, freq='D')
  7. df = pd.DataFrame(np.random.randn(1000, 2), columns=['c1','c2'], index = period)
  8. df['g1'] = np.random.choice(['M', 'N'], 1000)
  9. df['g2'] = np.random.choice(['X', 'Y'], 1000)
  10. for i in period: # 随机产生空值
  11. if np.random.random() < 0.05: df.loc[i,'c1'] = np.nan
  12. if np.random.random() < 0.05: df.loc[i,'c2'] = np.nan
  13. print('df.head()\n',df.head()); print('===========')
  14. # 创建分组对象(由于这里是研究分组对象group_obj的构成,所以仅查看按照两列联合分组的结果)
  15. # group_obj = df.groupby('g1') # 按照一列进行分组
  16. group_obj = df.groupby(['g1','g2']) # 按照两列联合分组
  17. for i in group_obj:
  18. print('开始一次group_obj的迭代\n',type(i)); print('-----------')
  19. for j in i:
  20. print(j); print('-----------')
  21. print(type(j)); print('-----------')
  22. 执行结果:
  23. df.head()
  24. c1 c2 g1 g2
  25. 2019-09-22 NaN 0.400157 N X
  26. 2019-09-23 0.978738 2.240893 N Y
  27. 2019-09-24 1.867558 -0.977278 M X
  28. 2019-09-25 0.950088 -0.151357 N X
  29. 2019-09-26 -0.103219 0.410599 M Y
  30. ===========
  31. 开始一次group_obj的迭代
  32. <class 'tuple'>
  33. -----------
  34. ('M', 'X')
  35. -----------
  36. <class 'tuple'>
  37. -----------
  38. c1 c2 g1 g2
  39. 2019-09-24 1.867558 -0.977278 M X
  40. ... ... ... .. ..
  41. 2022-06-17 -1.141901 -1.310970 M X
  42. [260 rows x 4 columns]
  43. -----------
  44. <class 'pandas.core.frame.DataFrame'>
  45. -----------
  46. 开始一次group_obj的迭代
  47. <class 'tuple'>
  48. -----------
  49. ('M', 'Y')
  50. -----------
  51. <class 'tuple'>
  52. -----------
  53. c1 c2 g1 g2
  54. 2019-09-26 -0.103219 0.410599 M Y
  55. ... ... ... .. ..
  56. 2022-06-15 0.197828 0.097751 M Y
  57. [245 rows x 4 columns]
  58. -----------
  59. <class 'pandas.core.frame.DataFrame'>
  60. -----------
  61. 开始一次group_obj的迭代
  62. <class 'tuple'>
  63. -----------
  64. ('N', 'X')
  65. -----------
  66. <class 'tuple'>
  67. -----------
  68. c1 c2 g1 g2
  69. 2019-09-22 NaN 0.400157 N X
  70. ... ... ... .. ..
  71. 2022-06-14 1.315138 -0.323457 N X
  72. [256 rows x 4 columns]
  73. -----------
  74. <class 'pandas.core.frame.DataFrame'>
  75. -----------
  76. 开始一次group_obj的迭代
  77. <class 'tuple'>
  78. -----------
  79. ('N', 'Y')
  80. -----------
  81. <class 'tuple'>
  82. -----------
  83. c1 c2 g1 g2
  84. 2019-09-23 0.978738 2.240893 N Y
  85. ... ... ... .. ..
  86. 2022-06-16 1.401523 NaN N Y
  87. [239 rows x 4 columns]
  88. -----------
  89. <class 'pandas.core.frame.DataFrame'>
  1. # 例2:group_obj的应用(group_obj.apply()见例3)
  2. import numpy as np
  3. import pandas as pd
  4. # 创建数据集
  5. np.random.seed(0)
  6. period = pd.date_range('2019-9-22', periods=1000, freq='D')
  7. df = pd.DataFrame(np.random.randn(1000, 2), columns=['c1','c2'], index = period)
  8. df['g1'] = np.random.choice(['M', 'N'], 1000)
  9. df['g2'] = np.random.choice(['X', 'Y'], 1000)
  10. for i in period: # 随机产生空值
  11. if np.random.random() < 0.05: df.loc[i,'c1'] = np.nan
  12. if np.random.random() < 0.05: df.loc[i,'c2'] = np.nan
  13. print('df.head()\n',df.head()); print('===========')
  14. # 创建分组对象
  15. group_obj = df.groupby('g1') # 按照一列进行分组
  16. # group_obj = df.groupby(['g1','g2']) # 按照两列联合分组
  17. print('group_obj\n',group_obj); print('===========')
  18. print('type(group_obj)\n',type(group_obj)); print('===========')
  19. # 使用分组对象的指定方法查看一项统计信息
  20. print('group_obj.size()\n',group_obj.size(),'\n',type(group_obj.size())); print('===========')
  21. print('group_obj.max()\n',group_obj.max(),'\n',type(group_obj.max())); print('===========')
  22. print('group_obj.min()\n',group_obj.min(),'\n',type(group_obj.min())); print('===========')
  23. print('group_obj.sum()\n',group_obj.sum(),'\n',type(group_obj.sum())); print('===========')
  24. print('group_obj.mean()\n',group_obj.mean(),'\n',type(group_obj.mean())); print('===========')
  25. print('group_obj.std()\n',group_obj.std(),'\n',type(group_obj.std())); print('===========')
  26. print('group_obj.count()\n',group_obj.count(),'\n',type(group_obj.count())); print('===========')
  27. # 使用分组对象的describe()方法查看全部统计信息
  28. print('group_obj.describe()\n',group_obj.describe(),'\n',type(group_obj.describe())); print('===========')
  29. print('group_obj.describe().T\n',group_obj.describe().T,'\n',type(group_obj.describe().T)); print('===========')
  30. # 使用分组对象的agg()方法查看自定义项目的统计信息
  31. print('group_obj.agg([np.mean, np.std])\n',group_obj.agg([np.mean, np.std]),'\n',type(group_obj.agg([np.mean, np.std]))); print('===========')
  32. print("group_obj.agg({'c1':np.mean, 'c2':np.std})\n",group_obj.agg({'c1':np.mean, 'c2':np.std}),'\n',type(group_obj.agg({'c1':np.mean, 'c2':np.std}))); print('===========')
  33. # 使用分组对象的get_group()方法获取指定分组的数据
  34. # 按照一列进行分组时获取数据
  35. print("group_obj.get_group('M').head()\n",group_obj.get_group('M').head())
  36. # 按照两列联合分组时获取数据
  37. # print("group_obj.get_group(('M','X')).head()\n",group_obj.get_group(('M','X')).head())
  1. # 例2的执行结果(按照一列进行分组):
  2. df.head()
  3. c1 c2 g1 g2
  4. 2019-09-22 NaN 0.400157 N X
  5. 2019-09-23 0.978738 2.240893 N Y
  6. 2019-09-24 1.867558 -0.977278 M X
  7. 2019-09-25 0.950088 -0.151357 N X
  8. 2019-09-26 -0.103219 0.410599 M Y
  9. ===========
  10. group_obj
  11. <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000000003DEB518>
  12. ===========
  13. type(group_obj)
  14. <class 'pandas.core.groupby.generic.DataFrameGroupBy'>
  15. ===========
  16. group_obj.size()
  17. g1
  18. M 505
  19. N 495
  20. dtype: int64
  21. <class 'pandas.core.series.Series'>
  22. ===========
  23. group_obj.max()
  24. c1 c2 g2
  25. g1
  26. M 2.680571 2.642936 Y
  27. N 3.170975 2.759355 Y
  28. <class 'pandas.core.frame.DataFrame'>
  29. ===========
  30. group_obj.min()
  31. c1 c2 g2
  32. g1
  33. M -2.802203 -2.772593 X
  34. N -2.994613 -3.046143 X
  35. <class 'pandas.core.frame.DataFrame'>
  36. ===========
  37. group_obj.sum()
  38. c1 c2
  39. g1
  40. M -21.519519 -23.540760
  41. N 3.243500 1.208014
  42. <class 'pandas.core.frame.DataFrame'>
  43. ===========
  44. group_obj.mean()
  45. c1 c2
  46. g1
  47. M -0.046080 -0.048338
  48. N 0.006901 0.002549
  49. <class 'pandas.core.frame.DataFrame'>
  50. ===========
  51. group_obj.std()
  52. c1 c2
  53. g1
  54. M 0.989397 0.982953
  55. N 0.963094 0.980751
  56. <class 'pandas.core.frame.DataFrame'>
  57. ===========
  58. group_obj.count()
  59. c1 c2 g2
  60. g1
  61. M 467 487 505
  62. N 470 474 495
  63. <class 'pandas.core.frame.DataFrame'>
  64. ===========
  65. group_obj.describe()
  66. c1 ... c2
  67. count mean std min ... 25% 50% 75% max
  68. g1 ...
  69. M 467.0 -0.046080 0.989397 -2.802203 ... -0.735622 -0.065488 0.549966 2.642936
  70. N 470.0 0.006901 0.963094 -2.994613 ... -0.600193 -0.003481 0.656109 2.759355
  71. [2 rows x 16 columns]
  72. <class 'pandas.core.frame.DataFrame'>
  73. ===========
  74. group_obj.describe().T
  75. g1 M N
  76. c1 count 467.000000 470.000000
  77. mean -0.046080 0.006901
  78. std 0.989397 0.963094
  79. min -2.802203 -2.994613
  80. 25% -0.726487 -0.669359
  81. 50% -0.056133 0.038123
  82. 75% 0.603422 0.669524
  83. max 2.680571 3.170975
  84. c2 count 487.000000 474.000000
  85. mean -0.048338 0.002549
  86. std 0.982953 0.980751
  87. min -2.772593 -3.046143
  88. 25% -0.735622 -0.600193
  89. 50% -0.065488 -0.003481
  90. 75% 0.549966 0.656109
  91. max 2.642936 2.759355
  92. <class 'pandas.core.frame.DataFrame'>
  93. ===========
  94. group_obj.agg([np.mean, np.std])
  95. c1 c2
  96. mean std mean std
  97. g1
  98. M -0.046080 0.989397 -0.048338 0.982953
  99. N 0.006901 0.963094 0.002549 0.980751
  100. <class 'pandas.core.frame.DataFrame'>
  101. ===========
  102. group_obj.agg({'c1':np.mean, 'c2':np.std})
  103. c1 c2
  104. g1
  105. M -0.046080 0.982953
  106. N 0.006901 0.980751
  107. <class 'pandas.core.frame.DataFrame'>
  108. ===========
  109. group_obj.get_group('M').head()
  110. c1 c2 g1 g2
  111. 2019-09-24 1.867558 -0.977278 M X
  112. 2019-09-26 -0.103219 0.410599 M Y
  113. 2019-09-29 0.443863 0.333674 M Y
  114. 2019-09-30 1.494079 -0.205158 M X
  115. 2019-10-05 0.045759 -0.187184 M X
  1. # 例2的执行结果(按照两列联合分组):
  2. df.head()
  3. c1 c2 g1 g2
  4. 2019-09-22 NaN 0.400157 N X
  5. 2019-09-23 0.978738 2.240893 N Y
  6. 2019-09-24 1.867558 -0.977278 M X
  7. 2019-09-25 0.950088 -0.151357 N X
  8. 2019-09-26 -0.103219 0.410599 M Y
  9. ===========
  10. group_obj
  11. <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000000003F5B518>
  12. ===========
  13. type(group_obj)
  14. <class 'pandas.core.groupby.generic.DataFrameGroupBy'>
  15. ===========
  16. group_obj.size()
  17. g1 g2
  18. M X 260
  19. Y 245
  20. N X 256
  21. Y 239
  22. dtype: int64
  23. <class 'pandas.core.series.Series'>
  24. ===========
  25. group_obj.max()
  26. c1 c2
  27. g1 g2
  28. M X 2.320800 2.642936
  29. Y 2.680571 2.380745
  30. N X 3.170975 2.412454
  31. Y 2.497200 2.759355
  32. <class 'pandas.core.frame.DataFrame'>
  33. ===========
  34. group_obj.min()
  35. c1 c2
  36. g1 g2
  37. M X -2.802203 -2.534554
  38. Y -2.437564 -2.772593
  39. N X -2.582797 -2.739677
  40. Y -2.994613 -3.046143
  41. <class 'pandas.core.frame.DataFrame'>
  42. ===========
  43. group_obj.sum()
  44. c1 c2
  45. g1 g2
  46. M X -18.444141 -21.132778
  47. Y -3.075378 -2.407982
  48. N X 20.090225 -1.593149
  49. Y -16.846726 2.801164
  50. <class 'pandas.core.frame.DataFrame'>
  51. ===========
  52. group_obj.mean()
  53. c1 c2
  54. g1 g2
  55. M X -0.077496 -0.083860
  56. Y -0.013430 -0.010247
  57. N X 0.084413 -0.006611
  58. Y -0.072615 0.012022
  59. <class 'pandas.core.frame.DataFrame'>
  60. ===========
  61. group_obj.std()
  62. c1 c2
  63. g1 g2
  64. M X 1.002794 0.976511
  65. Y 0.976399 0.990480
  66. N X 0.985893 0.900264
  67. Y 0.934578 1.059461
  68. <class 'pandas.core.frame.DataFrame'>
  69. ===========
  70. group_obj.count()
  71. c1 c2
  72. g1 g2
  73. M X 238 252
  74. Y 229 235
  75. N X 238 241
  76. Y 232 233
  77. <class 'pandas.core.frame.DataFrame'>
  78. ===========
  79. group_obj.describe()
  80. c1 ... c2
  81. count mean std ... 50% 75% max
  82. g1 g2 ...
  83. M X 238.0 -0.077496 1.002794 ... -0.122370 0.553665 2.642936
  84. Y 229.0 -0.013430 0.976399 ... 0.024612 0.548398 2.380745
  85. N X 238.0 0.084413 0.985893 ... 0.001248 0.547481 2.412454
  86. Y 232.0 -0.072615 0.934578 ... -0.008210 0.823504 2.759355
  87. [4 rows x 16 columns]
  88. <class 'pandas.core.frame.DataFrame'>
  89. ===========
  90. group_obj.describe().T
  91. g1 M N
  92. g2 X Y X Y
  93. c1 count 238.000000 229.000000 238.000000 232.000000
  94. mean -0.077496 -0.013430 0.084413 -0.072615
  95. std 1.002794 0.976399 0.985893 0.934578
  96. min -2.802203 -2.437564 -2.582797 -2.994613
  97. 25% -0.799725 -0.652409 -0.531745 -0.708426
  98. 50% -0.031588 -0.061743 0.039490 0.018710
  99. 75% 0.601873 0.604137 0.721432 0.591636
  100. max 2.320800 2.680571 3.170975 2.497200
  101. c2 count 252.000000 235.000000 241.000000 233.000000
  102. mean -0.083860 -0.010247 -0.006611 0.012022
  103. std 0.976511 0.990480 0.900264 1.059461
  104. min -2.534554 -2.772593 -2.739677 -3.046143
  105. 25% -0.698973 -0.740036 -0.575788 -0.680178
  106. 50% -0.122370 0.024612 0.001248 -0.008210
  107. 75% 0.553665 0.548398 0.547481 0.823504
  108. max 2.642936 2.380745 2.412454 2.759355
  109. <class 'pandas.core.frame.DataFrame'>
  110. ===========
  111. group_obj.agg([np.mean, np.std])
  112. c1 c2
  113. mean std mean std
  114. g1 g2
  115. M X -0.077496 1.002794 -0.083860 0.976511
  116. Y -0.013430 0.976399 -0.010247 0.990480
  117. N X 0.084413 0.985893 -0.006611 0.900264
  118. Y -0.072615 0.934578 0.012022 1.059461
  119. <class 'pandas.core.frame.DataFrame'>
  120. ===========
  121. group_obj.agg({'c1':np.mean, 'c2':np.std})
  122. c1 c2
  123. g1 g2
  124. M X -0.077496 0.976511
  125. Y -0.013430 0.990480
  126. N X 0.084413 0.900264
  127. Y -0.072615 1.059461
  128. <class 'pandas.core.frame.DataFrame'>
  129. ===========
  130. group_obj.get_group(('M','X')).head()
  131. c1 c2 g1 g2
  132. 2019-09-24 1.867558 -0.977278 M X
  133. 2019-09-30 1.494079 -0.205158 M X
  134. 2019-10-05 0.045759 -0.187184 M X
  135. 2019-10-12 -1.048553 -1.420018 M X
  136. 2019-10-13 NaN 1.950775 M X
  1. # 例3:group_obj.apply()的原理及应用
  2. import numpy as np
  3. import pandas as pd
  4. # 创建数据集
  5. np.random.seed(0)
  6. period = pd.date_range('2019-9-22', periods=1000, freq='D')
  7. df = pd.DataFrame(np.random.randn(1000, 2), columns=['c1','c2'], index = period)
  8. df['g1'] = np.random.choice(['M', 'N'], 1000)
  9. df['g2'] = np.random.choice(['X', 'Y'], 1000)
  10. for i in period: # 随机产生空值
  11. if np.random.random() < 0.05: df.loc[i,'c1'] = np.nan
  12. if np.random.random() < 0.05: df.loc[i,'c2'] = np.nan
  13. print('df.head()\n',df.head()); print('===========')
  14. # 仅演示按照两列联合分组的情况
  15. # group_obj = df.groupby('g1') # 按照一列进行分组
  16. group_obj = df.groupby(['g1','g2']) # 按照两列联合分组
  17. def group_func(df):
  18. print('---group_func内部开始---')
  19. print(df)
  20. print(type(df))
  21. print('---group_func内部结束---')
  22. # 将df按照'c1'列升序排列,取前两行结果作为返回值
  23. return df.sort_values(['c1'], ascending=True)[:2]
  24. result = group_obj.apply(group_func)
  25. print('===========')
  26. print(result); print('-----------')
  27. print(type(result)); print('-----------')
  28. print(result.index)
  29. 执行结果:
  30. df.head()
  31. c1 c2 g1 g2
  32. 2019-09-22 NaN 0.400157 N X
  33. 2019-09-23 0.978738 2.240893 N Y
  34. 2019-09-24 1.867558 -0.977278 M X
  35. 2019-09-25 0.950088 -0.151357 N X
  36. 2019-09-26 -0.103219 0.410599 M Y
  37. ===========
  38. ---group_func内部开始---
  39. c1 c2 g1 g2
  40. 2019-09-24 1.867558 -0.977278 M X
  41. ... ... ... .. ..
  42. 2022-06-17 -1.141901 -1.310970 M X
  43. [260 rows x 4 columns]
  44. <class 'pandas.core.frame.DataFrame'>
  45. ---group_func内部结束---
  46. ---group_func内部开始---
  47. c1 c2 g1 g2
  48. 2019-09-26 -0.103219 0.410599 M Y
  49. ... ... ... .. ..
  50. 2022-06-15 0.197828 0.097751 M Y
  51. [245 rows x 4 columns]
  52. <class 'pandas.core.frame.DataFrame'>
  53. ---group_func内部结束---
  54. ---group_func内部开始---
  55. c1 c2 g1 g2
  56. 2019-09-22 NaN 0.400157 N X
  57. ... ... ... .. ..
  58. 2022-06-14 1.315138 -0.323457 N X
  59. [256 rows x 4 columns]
  60. <class 'pandas.core.frame.DataFrame'>
  61. ---group_func内部结束---
  62. ---group_func内部开始---
  63. c1 c2 g1 g2
  64. 2019-09-23 0.978738 2.240893 N Y
  65. ... ... ... .. ..
  66. 2022-06-16 1.401523 NaN N Y
  67. [239 rows x 4 columns]
  68. <class 'pandas.core.frame.DataFrame'>
  69. ---group_func内部结束---
  70. ===========
  71. c1 c2 g1 g2
  72. g1 g2
  73. M X 2021-08-31 -2.802203 -1.188424 M X
  74. 2020-03-07 -2.659172 0.606320 M X
  75. Y 2022-03-03 -2.437564 1.114925 M Y
  76. 2020-05-13 -2.288620 0.251484 M Y
  77. N X 2020-11-20 -2.582797 -1.153950 N X
  78. 2020-06-12 -2.369587 0.864052 N X
  79. Y 2021-09-14 -2.994613 0.880938 N Y
  80. 2021-06-11 -2.777359 1.151734 N Y
  81. -----------
  82. <class 'pandas.core.frame.DataFrame'>
  83. -----------
  84. MultiIndex([('M', 'X', '2021-08-31'),
  85. ('M', 'X', '2020-03-07'),
  86. ('M', 'Y', '2022-03-03'),
  87. ('M', 'Y', '2020-05-13'),
  88. ('N', 'X', '2020-11-20'),
  89. ('N', 'X', '2020-06-12'),
  90. ('N', 'Y', '2021-09-14'),
  91. ('N', 'Y', '2021-06-11')],
  92. names=['g1', 'g2', None])

12. DataFrame的合并

DataFrame的合并可以基于DataFrame定义、concat()、join()、merge()来实现,其中merge()的功能最为强大,使用它也可以实现其他方法的功能

(1)基于DataFrame定义的合并

最原始的合并方式,需要手动逐列定义字典的键(列标签)和值(列数据),行标签则只能采取外连接方式(取并集)

  1. import numpy as np
  2. import pandas as pd
  3. # 定义原始数据
  4. df1 = pd.DataFrame([[1,2],[3,4]], columns=['c2','c1'], index=['t2','t1'])
  5. df2 = pd.DataFrame([[5,6],[7,8]], columns=['c3','c1'], index=['t3','t1'])
  6. # 开始合并
  7. df = pd.DataFrame({'C2': df1['c2'], 'C3': df2['c3']})
  8. print('df1\n',df1); print('===========')
  9. print('df2\n',df2); print('===========')
  10. print('df\n',df)
  11. 执行结果:
  12. df1
  13. c2 c1
  14. t2 1 2
  15. t1 3 4
  16. ===========
  17. df2
  18. c3 c1
  19. t3 5 6
  20. t1 7 8
  21. ===========
  22. df
  23. C2 C3
  24. t1 3.0 7.0
  25. t2 1.0 NaN
  26. t3 NaN 5.0

(2)df.append()

语法:df.append(obj, sort=???, ignore_index=False)

整体与pd.concat()实现的效果类似,纵向拼接,行标签不合并且保留原始顺序,列标签会合并

参数:

  • obj:拼接对象,可以是一个DataFrame或Series。当是Series时,须满足下面两个条件之一(即要么拼接的这行自己有名字作为其行标签,要么忽略所有行标签),否则报错:

    • 该Series有name属性
    • df.append()中的ignore_index参数值为True
  • sort:布尔值,拼接后的DataFrame是否按列标签排序。注意:当前版本Pandas默认值为None(根据不同的情况默认True或False),未来版本会取消默认值,因此为保险起见,不管sort为True还是False都要写上,不写会弹出警告(warning)
  • ignore_index:拼接后的DataFrame是否忽略所有行标签(即重置为0、1、2……的行位置索引),默认值为False
  1. import numpy as np
  2. import pandas as pd
  3. import warnings; warnings.simplefilter('ignore') # 忽略可能会出现的警告信息;警告并不是错误,可以忽略;可能出现警告的场景包括:df.ix[]、pd.concat()
  4. # 定义原始数据
  5. df1 = pd.DataFrame([[1,2],[3,4]], columns=['c2','c1'], index=['t2','t1'])
  6. df2 = pd.DataFrame([[5,6],[7,8]], columns=['c3','c1'], index=['t3','t1'])
  7. s1 = pd.Series([9,10,11],index=['c2','c4','c3'], name='s1')
  8. s2 = pd.Series([12,13,14],index=['c2','c4','c3'])
  9. # 开始拼接
  10. df3 = df1.append(df2, sort=False)
  11. df4 = df1.append(df2, sort=True)
  12. df5 = df1.append(df2, sort=False, ignore_index=True)
  13. df6 = df1.append(s1, sort=False)
  14. df7 = df1.append(s2, sort=False, ignore_index=True)
  15. print('df1\n',df1); print('===========')
  16. print('df2\n',df2); print('===========')
  17. print('df3\n',df3); print('===========')
  18. print('df4\n',df4); print('===========')
  19. print('df5\n',df5); print('===========')
  20. print('df6\n',df6); print('===========')
  21. print('df7\n',df7)
  22. 执行结果:
  23. df1
  24. c2 c1
  25. t2 1 2
  26. t1 3 4
  27. ===========
  28. df2
  29. c3 c1
  30. t3 5 6
  31. t1 7 8
  32. ===========
  33. df3
  34. c2 c1 c3
  35. t2 1.0 2 NaN
  36. t1 3.0 4 NaN
  37. t3 NaN 6 5.0
  38. t1 NaN 8 7.0
  39. ===========
  40. df4
  41. c1 c2 c3
  42. t2 2 1.0 NaN
  43. t1 4 3.0 NaN
  44. t3 6 NaN 5.0
  45. t1 8 NaN 7.0
  46. ===========
  47. df5
  48. c2 c1 c3
  49. 0 1.0 2 NaN
  50. 1 3.0 4 NaN
  51. 2 NaN 6 5.0
  52. 3 NaN 8 7.0
  53. ===========
  54. df6
  55. c2 c1 c3 c4
  56. t2 1.0 2.0 NaN NaN
  57. t1 3.0 4.0 NaN NaN
  58. s1 9.0 NaN 11.0 10.0
  59. ===========
  60. df7
  61. c2 c1 c3 c4
  62. 0 1.0 2.0 NaN NaN
  63. 1 3.0 4.0 NaN NaN
  64. 2 12.0 NaN 14.0 13.0

(3)df.join()

语法:df1.join(df2, how='left', lsuffix='', rsuffix='')

只能实现横向拼接,列标签不允许重名也不能合并(重名时须指定后缀),行标签可以选择左、右、内、外四种连接方式(默认左连接)

参数:

  • how:行标签显示方式

    • 默认值为'left',左连接,显示左侧df的所有行标签
    • how='right'时,右连接,显示右侧df的所有行标签
    • how='inner'时,内连接,显示df1和df2行标签的交集
    • how='outer'时,外连接,显示df1和df2行标签的并集
  • lsuffix:有重名列时,左侧df该列的标签添加的后缀,默认为空字符串''
  • rsuffix:有重名列时,右侧df该列的标签添加的后缀,默认为空字符串''

注意:

  • 当有重名列时,lsuffix和rsuffix至少应有一个不为空,否则报错
  1. import numpy as np
  2. import pandas as pd
  3. # 定义原始数据
  4. df1 = pd.DataFrame([[1,2],[3,4]], columns=['c2','c1'], index=['t2','t1'])
  5. df2 = pd.DataFrame([[5,6],[7,8]], columns=['c3','c1'], index=['t3','t1'])
  6. # 开始合并
  7. df3 = df1.join(df2, lsuffix='_l', rsuffix='_r')
  8. df4 = df1.join(df2, how='left', lsuffix='_l', rsuffix='_r')
  9. df5 = df1.join(df2, how='right', lsuffix='_l', rsuffix='_r')
  10. df6 = df1.join(df2, how='inner', lsuffix='_l', rsuffix='_r')
  11. df7 = df1.join(df2, how='outer', lsuffix='_l', rsuffix='_r')
  12. print('df1\n',df1); print('===========')
  13. print('df2\n',df2); print('===========')
  14. print('df3\n',df3); print('===========')
  15. print('df4\n',df4); print('===========')
  16. print('df5\n',df5); print('===========')
  17. print('df6\n',df6); print('===========')
  18. print('df7\n',df7)
  19. 执行结果:
  20. df1
  21. c2 c1
  22. t2 1 2
  23. t1 3 4
  24. ===========
  25. df2
  26. c3 c1
  27. t3 5 6
  28. t1 7 8
  29. ===========
  30. df3
  31. c2 c1_l c3 c1_r
  32. t2 1 2 NaN NaN
  33. t1 3 4 7.0 8.0
  34. ===========
  35. df4
  36. c2 c1_l c3 c1_r
  37. t2 1 2 NaN NaN
  38. t1 3 4 7.0 8.0
  39. ===========
  40. df5
  41. c2 c1_l c3 c1_r
  42. t3 NaN NaN 5 6
  43. t1 3.0 4.0 7 8
  44. ===========
  45. df6
  46. c2 c1_l c3 c1_r
  47. t1 3 4 7 8
  48. ===========
  49. df7
  50. c2 c1_l c3 c1_r
  51. t1 3.0 4.0 7.0 8.0
  52. t2 1.0 2.0 NaN NaN
  53. t3 NaN NaN 5.0 6.0

(4)pd.concat()

语法:pd.concat(objs, axis=0, join='outer', ignore_index=False, sort=???, keys=None, names=None)

实现纵向拼接(拼接轴为y轴)或横向拼接(拼接轴为x轴),拼接轴上的标签不合并且保留原始顺序,非拼接轴上的标签会合并

参数:

  • objs:由若干个DataFrame组成的可迭代对象,如(df1,df2)[df1,df2,df3]

  • axis:默认值为0,纵向拼接,行标签不合并且顺序不变,列标签合并;axis=1时,横向拼接,列标签不合并且顺序不变,行标签合并。

  • join:默认值为'outer',非拼接轴外连接(取并集);join='inner'时,非拼接轴内连接(取交集)

    注意:join的取值只能是'outer'或'inner',没有别的

  • ignore_index:默认值为False,保留拼接轴的标签索引;ignore_index=True时,删除拼接轴的标签索引

  • sort:当join='outer'时,非拼接轴是否按标签排序;当join='inner'时,sort参数没有用。注意:当前版本Pandas默认值为True,未来版本默认值将改为False,因此为保险起见,只要join='outer',不管sort为True还是False都要写上,不写会弹出警告(warning)

  • keys:是一个list,当axis=0时,在y轴最外层添加一个层次化索引,这个list中的每个元素都是该层次化索引的行标签,即该list的长度应该等于objs的长度(因为给objs中的每一个DataFrame都分配了一个最外层层次化索引的行标签);当axis=1则对x轴执行相似操作。代码示例见“AQF笔记-第2部分-第7章-金融数据源处理实现-三、金融数据的处理-2.同时获取多只股价信息”

  • names:是一个list,当axis=0时,里面的每个元素都是y轴的每级层次化索引的名字(因为每级层次化索引都是一个Series,相当于批量设置每个Series的name属性);当axis=1则对x轴执行相似操作。代码示例见“AQF笔记-第2部分-第7章-金融数据源处理实现-三、金融数据的处理-2.同时获取多只股价信息”

  1. import numpy as np
  2. import pandas as pd
  3. import warnings; warnings.simplefilter('ignore') # 忽略可能会出现的警告信息;警告并不是错误,可以忽略;可能出现警告的场景包括:df.ix[]、pd.concat()
  4. # 定义原始数据
  5. df1 = pd.DataFrame([[1,2],[3,4]], columns=['c2','c1'], index=['t2','t1'])
  6. df2 = pd.DataFrame([[5,6],[7,8]], columns=['c3','c1'], index=['t3','t1'])
  7. # 开始拼接
  8. df3 = pd.concat((df1,df2), sort=True)
  9. df4 = pd.concat((df1,df2), sort=False)
  10. df5 = pd.concat((df1,df2), sort=True, join='inner')
  11. df6 = pd.concat((df1,df2), axis=1, sort=True)
  12. df7 = pd.concat((df1,df2), ignore_index=True, sort=True)
  13. df8 = pd.concat((df1,df2), axis=1, ignore_index=True, sort=True)
  14. print('df1\n',df1); print('===========')
  15. print('df2\n',df2); print('===========')
  16. print('df3\n',df3); print('===========')
  17. print('df4\n',df4); print('===========')
  18. print('df5\n',df5); print('===========')
  19. print('df6\n',df6); print('===========')
  20. print('df7\n',df7); print('===========')
  21. print('df8\n',df8)
  22. 执行结果:
  23. df1
  24. c2 c1
  25. t2 1 2
  26. t1 3 4
  27. ===========
  28. df2
  29. c3 c1
  30. t3 5 6
  31. t1 7 8
  32. ===========
  33. df3
  34. c1 c2 c3
  35. t2 2 1.0 NaN
  36. t1 4 3.0 NaN
  37. t3 6 NaN 5.0
  38. t1 8 NaN 7.0
  39. ===========
  40. df4
  41. c2 c1 c3
  42. t2 1.0 2 NaN
  43. t1 3.0 4 NaN
  44. t3 NaN 6 5.0
  45. t1 NaN 8 7.0
  46. ===========
  47. df5
  48. c1
  49. t2 2
  50. t1 4
  51. t3 6
  52. t1 8
  53. ===========
  54. df6
  55. c2 c1 c3 c1
  56. t1 3.0 4.0 7.0 8.0
  57. t2 1.0 2.0 NaN NaN
  58. t3 NaN NaN 5.0 6.0
  59. ===========
  60. df7
  61. c1 c2 c3
  62. 0 2 1.0 NaN
  63. 1 4 3.0 NaN
  64. 2 6 NaN 5.0
  65. 3 8 NaN 7.0
  66. ===========
  67. df8
  68. 0 1 2 3
  69. t1 3.0 4.0 7.0 8.0
  70. t2 1.0 2.0 NaN NaN
  71. t3 NaN NaN 5.0 6.0

(5)pd.merge()

只能实现横向拼接,列标签不会出现重名也不能合并(重名时会自动添加后缀),行标签可以选择内、外、左、右、四种连接方式(默认内连接)。根据主键选取方式的不同,语法分为三种情况(分别对应下方示例代码的例1、例2、例3):

  • 以行标签为主键(行标签相同的合并为一行),保留行标签信息

    1. pd.merge(df1, df2, how='inner', left_index=True, right_index=True, sort=False, suffixes=('_x', '_y'))

    注意:此方法与join()实现的效果共同;此外,left_index和right_index的默认值都是False,如果想采用此方法,需要手动传关键字参数

  • 以df1和df2的一个同名列为主键(该列值相同的合并为一行),会导致丢失行标签信息

    1. pd.merge(df1, df2, how='inner', on='主键列标签', sort=False, suffixes=('_x', '_y'))

    注意:不写on参数时,Pandas会以首个df1和df2都有的同名列为主键,可能会自动匹配到错误的列,因此建议写上on这个参数,以便明确地声明使用哪列作为主键

  • 以df1的某一列为主键,以df2的另一列为主键(主键列值相同的合并为一行),会导致丢失行标签信息

    1. pd.merge(df1, df2, how='inner', left_on='df1的主键列标签', right_on='df2的主键列标签', sort=False, suffixes=('_x','_y'))

公共参数:

  • how:行标签显示方式

    • 默认值为'inner',内连接,主键列显示df1和df2主键的交集
    • how='outer'时,外连接,主键列显示df1和df2主键的并集
    • how='left'时,左连接,主键列为左侧df1的主键列
    • how='right'时,右连接,主键列为右侧df2的主键列
  • sort:是否对返回结果的主键列排序,默认值为False
  • suffixes:非主键列重名时添加的后缀,是一个元组类型数据,元组第一项给df1用,第二项给df2用,默认值为('_x', '_y')。元组的两项值可以相同,但是不能同时为空
  1. # 例1:以行标签为主键(行标签相同的合并为一行)
  2. import numpy as np
  3. import pandas as pd
  4. # 定义原始数据
  5. df1 = pd.DataFrame([[1,2],[3,4]], columns=['c2','c1'], index=['t2','t1'])
  6. df2 = pd.DataFrame([[5,6],[7,8]], columns=['c3','c1'], index=['t3','t1'])
  7. # 开始合并
  8. df3 = pd.merge(df1,df2,left_index=True,right_index=True)
  9. df4 = pd.merge(df1,df2,how='outer',left_index=True,right_index=True)
  10. df5 = pd.merge(df1,df2,how='outer',left_index=True,right_index=True,sort=True,suffixes=('_df1', '_df2'))
  11. df6 = pd.merge(df1,df2,how='left',left_index=True,right_index=True)
  12. df7 = pd.merge(df1,df2,how='right',left_index=True,right_index=True)
  13. print('df1\n',df1); print('===========')
  14. print('df2\n',df2); print('===========')
  15. print('df3\n',df3); print('===========')
  16. print('df4\n',df4); print('===========')
  17. print('df5\n',df5); print('===========')
  18. print('df6\n',df6); print('===========')
  19. print('df7\n',df7)
  20. 执行结果:
  21. df1
  22. c2 c1
  23. t2 1 2
  24. t1 3 4
  25. ===========
  26. df2
  27. c3 c1
  28. t3 5 6
  29. t1 7 8
  30. ===========
  31. df3
  32. c2 c1_x c3 c1_y
  33. t1 3 4 7 8
  34. ===========
  35. df4
  36. c2 c1_x c3 c1_y
  37. t1 3.0 4.0 7.0 8.0
  38. t2 1.0 2.0 NaN NaN
  39. t3 NaN NaN 5.0 6.0
  40. ===========
  41. df5
  42. c2 c1_df1 c3 c1_df2
  43. t1 3.0 4.0 7.0 8.0
  44. t2 1.0 2.0 NaN NaN
  45. t3 NaN NaN 5.0 6.0
  46. ===========
  47. df6
  48. c2 c1_x c3 c1_y
  49. t2 1 2 NaN NaN
  50. t1 3 4 7.0 8.0
  51. ===========
  52. df7
  53. c2 c1_x c3 c1_y
  54. t3 NaN NaN 5 6
  55. t1 3.0 4.0 7 8
  1. # 例2:以df1和df2的同名列'c1'为主键('c1'列值相同的合并为一行),会导致丢失行标签信息
  2. import numpy as np
  3. import pandas as pd
  4. # 定义原始数据
  5. df1 = pd.DataFrame([[1,'C'],[2,'B']], columns=['c2','c1'], index=['t2','t1'])
  6. df2 = pd.DataFrame([[3,'C'],[4,'A']], columns=['c2','c1'], index=['t2','t1'])
  7. # 开始合并
  8. df3 = pd.merge(df1,df2) # 以首个df1和df2都有的列为主键,因此这里自动匹配到的是'c2'列,不是'c1'列
  9. df4 = pd.merge(df1,df2,how='inner',on='c1')
  10. df5 = pd.merge(df1,df2,how='outer',on='c1')
  11. df6 = pd.merge(df1,df2,how='outer',on='c1',sort=True,suffixes=('_df1', '_df2'))
  12. df7 = pd.merge(df1,df2,how='left',on='c1')
  13. df8 = pd.merge(df1,df2,how='right',on='c1')
  14. print('df1\n',df1); print('===========')
  15. print('df2\n',df2); print('===========')
  16. print('df3\n',df3); print('===========')
  17. print('df4\n',df4); print('===========')
  18. print('df5\n',df5); print('===========')
  19. print('df6\n',df6); print('===========')
  20. print('df7\n',df7); print('===========')
  21. print('df8\n',df8)
  22. 执行结果:
  23. df1
  24. c2 c1
  25. t2 1 C
  26. t1 2 B
  27. ===========
  28. df2
  29. c2 c1
  30. t2 3 C
  31. t1 4 A
  32. ===========
  33. df3
  34. Empty DataFrame
  35. Columns: [c2, c1]
  36. Index: []
  37. ===========
  38. df4
  39. c2_x c1 c2_y
  40. 0 1 C 3
  41. ===========
  42. df5
  43. c2_x c1 c2_y
  44. 0 1.0 C 3.0
  45. 1 2.0 B NaN
  46. 2 NaN A 4.0
  47. ===========
  48. df6
  49. c2_df1 c1 c2_df2
  50. 0 NaN A 4.0
  51. 1 2.0 B NaN
  52. 2 1.0 C 3.0
  53. ===========
  54. df7
  55. c2_x c1 c2_y
  56. 0 1 C 3.0
  57. 1 2 B NaN
  58. ===========
  59. df8
  60. c2_x c1 c2_y
  61. 0 1.0 C 3
  62. 1 NaN A 4
  1. # 例3:以df1的'c1'列为主键,以df2的'c2'列为主键(主键列值相同的合并为一行),会导致丢失行标签信息
  2. import numpy as np
  3. import pandas as pd
  4. # 定义原始数据
  5. df1 = pd.DataFrame([[1,'C'],[2,'B']], columns=['c3','c1'], index=['t2','t1'])
  6. df2 = pd.DataFrame([[3,'C'],[4,'A']], columns=['c3','c2'], index=['t2','t1'])
  7. # 开始合并
  8. df3 = pd.merge(df1,df2,left_on='c1',right_on='c2')
  9. df4 = pd.merge(df1,df2,how='outer',left_on='c1',right_on='c2')
  10. df5 = pd.merge(df1,df2,how='outer',left_on='c1',right_on='c2',sort=True,suffixes=('_df1','_df2'))
  11. df6 = pd.merge(df1,df2,how='left',left_on='c1',right_on='c2')
  12. df7 = pd.merge(df1,df2,how='right',left_on='c1',right_on='c2')
  13. print('df1\n',df1); print('===========')
  14. print('df2\n',df2); print('===========')
  15. print('df3\n',df3); print('===========')
  16. print('df4\n',df4); print('===========')
  17. print('df5\n',df5); print('===========')
  18. print('df6\n',df6); print('===========')
  19. print('df7\n',df7)
  20. 执行结果:
  21. df1
  22. c3 c1
  23. t2 1 C
  24. t1 2 B
  25. ===========
  26. df2
  27. c3 c2
  28. t2 3 C
  29. t1 4 A
  30. ===========
  31. df3
  32. c3_x c1 c3_y c2
  33. 0 1 C 3 C
  34. ===========
  35. df4
  36. c3_x c1 c3_y c2
  37. 0 1.0 C 3.0 C
  38. 1 2.0 B NaN NaN
  39. 2 NaN NaN 4.0 A
  40. ===========
  41. df5
  42. c3_df1 c1 c3_df2 c2
  43. 0 NaN NaN 4.0 A
  44. 1 2.0 B NaN NaN
  45. 2 1.0 C 3.0 C
  46. ===========
  47. df6
  48. c3_x c1 c3_y c2
  49. 0 1 C 3.0 C
  50. 1 2 B NaN NaN
  51. ===========
  52. df7
  53. c3_x c1 c3_y c2
  54. 0 1.0 C 3 C
  55. 1 NaN NaN 4 A

13. Series和DataFrame的层次化索引

由于在最新版本的Pandas中已将该Panel数据类型删除,因此可以使用层次化索引间接实现Panel数据类型的效果

(1)Series的层次化索引

① 创建层次化索引的Series

语法和创建普通Series的语法相同,只须把index变为多维结构即可。定义了层次化索引的Series后,s.index的数据类型变成了pandas.core.indexes.multi.MultiIndex

靠前的索引(如下例中的大写字母)是外层索引,其level值为0;靠后的索引(如下例中的小写字母)是内层索引,其level值以整数递增(本例中其level=1)。

  1. import numpy as np
  2. import pandas as pd
  3. s = pd.Series([1,2,3,4,5,6,7,8],
  4. index=[
  5. ['A','A','B','B','C','C','D','D'],
  6. ['e','f','e','g','f','h','g','h']
  7. ])
  8. print('s','\n',s); print('===========')
  9. print('s.index','\n',s.index,'\n',type(s.index))
  10. 执行结果:
  11. s
  12. A e 1
  13. f 2
  14. B e 3
  15. g 4
  16. C f 5
  17. h 6
  18. D g 7
  19. h 8
  20. dtype: int64
  21. ===========
  22. s.index
  23. MultiIndex([('A', 'e'),
  24. ('A', 'f'),
  25. ('B', 'e'),
  26. ('B', 'g'),
  27. ('C', 'f'),
  28. ('C', 'h'),
  29. ('D', 'g'),
  30. ('D', 'h')],
  31. )
  32. <class 'pandas.core.indexes.multi.MultiIndex'>

② 层次化索引的Series的索引和切片

  1. import numpy as np
  2. import pandas as pd
  3. s = pd.Series([1,2,3,4,5,6,7,8],
  4. index=[
  5. ['A','A','B','B','C','C','D','D'],
  6. ['e','f','e','g','f','h','g','h']
  7. ])
  8. print('s','\n',s); print('===========')
  9. print("s['A']",'\n',s['A'],'\n',type(s['A'])); print('===========')
  10. print("s['A':'C']",'\n',s['A':'C'],'\n',type(s['A':'C'])); print('===========')
  11. print("s[['A','C']]",'\n',s[['A','C']],'\n',type(s[['A','C']])); print('===========')
  12. print("s[:,'f']",'\n',s[:,'f'],'\n',type(s[:,'f'])); print('===========')
  13. print("s['A','e']",'\n',s['A','e'],'\n',type(s['A','e'])); print('===========')
  14. # 下面几种形式会导致报错:
  15. # print(s['A':'C','f'])
  16. # print(s[['A','C'],'f'])
  17. # print(s[:,'e':'f'])
  18. # print(s[:,['e','f']])
  19. 执行结果:
  20. s
  21. A e 1
  22. f 2
  23. B e 3
  24. g 4
  25. C f 5
  26. h 6
  27. D g 7
  28. h 8
  29. dtype: int64
  30. ===========
  31. s['A']
  32. e 1
  33. f 2
  34. dtype: int64
  35. <class 'pandas.core.series.Series'>
  36. ===========
  37. s['A':'C']
  38. A e 1
  39. f 2
  40. B e 3
  41. g 4
  42. C f 5
  43. h 6
  44. dtype: int64
  45. <class 'pandas.core.series.Series'>
  46. ===========
  47. s[['A','C']]
  48. A e 1
  49. f 2
  50. C f 5
  51. h 6
  52. dtype: int64
  53. <class 'pandas.core.series.Series'>
  54. ===========
  55. s[:,'f']
  56. A 2
  57. C 5
  58. dtype: int64
  59. <class 'pandas.core.series.Series'>
  60. ===========
  61. s['A','e']
  62. 1
  63. <class 'numpy.int64'>

③ 层次化索引的Series的分组聚合

s.sum(level=0)与s.groupby(level=0).sum()等效

s.sum(level=1)与s.groupby(level=1).sum()等效

  1. import numpy as np
  2. import pandas as pd
  3. s = pd.Series([1,2,3,4,5,6,7,8],
  4. index=[
  5. ['A','A','B','B','C','C','D','D'],
  6. ['e','f','e','g','f','h','g','h']
  7. ])
  8. print('s','\n',s); print('===========')
  9. s1 = s.sum(level=0)
  10. s2 = s.sum(level=1)
  11. s3 = s.groupby(level=0).sum()
  12. s4 = s.groupby(level=1).sum()
  13. print('s1','\n',s1,'\n',type(s1)); print('===========')
  14. print('s2','\n',s2,'\n',type(s2)); print('===========')
  15. print('s3','\n',s3,'\n',type(s3)); print('===========')
  16. print('s4','\n',s4,'\n',type(s4))
  17. 执行结果:
  18. s
  19. A e 1
  20. f 2
  21. B e 3
  22. g 4
  23. C f 5
  24. h 6
  25. D g 7
  26. h 8
  27. dtype: int64
  28. ===========
  29. s1
  30. A 3
  31. B 7
  32. C 11
  33. D 15
  34. dtype: int64
  35. <class 'pandas.core.series.Series'>
  36. ===========
  37. s2
  38. e 4
  39. f 7
  40. g 11
  41. h 14
  42. dtype: int64
  43. <class 'pandas.core.series.Series'>
  44. ===========
  45. s3
  46. A 3
  47. B 7
  48. C 11
  49. D 15
  50. dtype: int64
  51. <class 'pandas.core.series.Series'>
  52. ===========
  53. s4
  54. e 4
  55. f 7
  56. g 11
  57. h 14
  58. dtype: int64
  59. <class 'pandas.core.series.Series'>

(2)DataFrame的层次化索引

① 创建层次化索引的DataFrame

语法和创建普通DataFrame的语法相同,只须把index变为多维结构即可。定义了层次化索引的DataFrame后,df.index的数据类型变成了pandas.core.indexes.multi.MultiIndex

靠前的索引(如下例中的大写字母)是外层索引,其level值为0;靠后的索引(如下例中的小写字母)是内层索引,其level值以整数递增(本例中其level=1)。

关于层次化索引的df.index.name和df.index.names的区别,见本章“二、Pandas模块 - 5. DataFrame对象的属性 - (3)df.index.name和df.index.names

  1. import numpy as np
  2. import pandas as pd
  3. # 创建方式一
  4. df = pd.DataFrame([1,2,3,4,5,6,7,8])
  5. df.columns = ['c1']
  6. df.index = [['A','A','B','B','C','C','D','D'],
  7. ['e','f','e','g','f','h','g','h']]
  8. df.index.name='my_index_name'
  9. df.index.names = ['i1','i2']
  10. # 创建方式二(两种方式等效)
  11. """
  12. df = pd.DataFrame([['A','e',1],
  13. ['A','f',2],
  14. ['B','e',3],
  15. ['B','g',4],
  16. ['C','f',5],
  17. ['C','h',6],
  18. ['D','g',7],
  19. ['D','h',8]])
  20. df.columns=['i1','i2','c1']
  21. df = df.set_index(['i1','i2'])
  22. df.index.name='my_index_name'
  23. """
  24. print('df\n',df,'\n',type(df)); print('===========')
  25. print('df.index\n',df.index,'\n',type(df.index)); print('-----------')
  26. print(df.index.name); print('-----------')
  27. print(df.index.names); print('===========')
  28. print('df.columns\n',df.columns,'\n',type(df.columns))
  29. 执行结果:
  30. df
  31. c1
  32. i1 i2
  33. A e 1
  34. f 2
  35. B e 3
  36. g 4
  37. C f 5
  38. h 6
  39. D g 7
  40. h 8
  41. <class 'pandas.core.frame.DataFrame'>
  42. ===========
  43. df.index
  44. MultiIndex([('A', 'e'),
  45. ('A', 'f'),
  46. ('B', 'e'),
  47. ('B', 'g'),
  48. ('C', 'f'),
  49. ('C', 'h'),
  50. ('D', 'g'),
  51. ('D', 'h')],
  52. name='my_index_name')
  53. <class 'pandas.core.indexes.multi.MultiIndex'>
  54. -----------
  55. my_index_name
  56. -----------
  57. ['i1', 'i2']
  58. ===========
  59. df.columns
  60. Index(['c1'], dtype='object')
  61. <class 'pandas.core.indexes.base.Index'>

② 层次化索引的DataFrame的索引和切片

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([1,2,3,4,5,6,7,8],columns=['c1'],
  4. index=[
  5. ['A','A','B','B','C','C','D','D'],
  6. ['e','f','e','g','f','h','g','h']
  7. ])
  8. print('df\n',df,'\n',type(df)); print('===========')
  9. print("df.loc['A']",'\n',df.loc['A'],'\n',type(df.loc['A'])); print('===========')
  10. print("df.loc['A':'C']",'\n',df.loc['A':'C'],'\n',type(df.loc['A':'C'])); print('===========')
  11. print("df.loc[['A','C']]",'\n',df.loc[['A','C']],'\n',type(df.loc[['A','C']])); print('===========')
  12. print("df.loc[('A','f')]",'\n',df.loc[('A','f')],'\n',type(df.loc[('A','f')])); print('===========')
  13. print("df.loc[('A','f'),'c1']",'\n',df.loc[('A','f'),'c1'],'\n',type(df.loc[('A','f'),'c1'])); print('===========')
  14. # 下面的写法将导致错误:
  15. # print("df.loc[:,'f']",'\n',df.loc[:,'f'],'\n',type(df.loc[:,'f'])); print('===========')
  16. # print("df.loc[(:,'f')]",'\n',df.loc[(:,'f')],'\n',type(df.loc[(:,'f')])); print('===========')
  17. # print("df.loc[('A','f':'h')]",'\n',df.loc[('A','f':'h')],'\n',type(df.loc[('A','f':'h')])); print('===========')
  18. # print("df.loc[(['A','C'],'f')]",'\n',df.loc[(['A','C'],'f')],'\n',type(df.loc[(['A','C'],'f')])); print('===========')
  19. # print("df.loc[('A',['f','h'])]",'\n',df.loc[('A',['f','h'])],'\n',type(df.loc[('A',['f','h'])])); print('===========')
  20. 执行结果:
  21. df
  22. c1
  23. A e 1
  24. f 2
  25. B e 3
  26. g 4
  27. C f 5
  28. h 6
  29. D g 7
  30. h 8
  31. <class 'pandas.core.frame.DataFrame'>
  32. ===========
  33. df.loc['A']
  34. c1
  35. e 1
  36. f 2
  37. <class 'pandas.core.frame.DataFrame'>
  38. ===========
  39. df.loc['A':'C']
  40. c1
  41. A e 1
  42. f 2
  43. B e 3
  44. g 4
  45. C f 5
  46. h 6
  47. <class 'pandas.core.frame.DataFrame'>
  48. ===========
  49. df.loc[['A','C']]
  50. c1
  51. A e 1
  52. f 2
  53. C f 5
  54. h 6
  55. <class 'pandas.core.frame.DataFrame'>
  56. ===========
  57. df.loc[('A','f')]
  58. c1 2
  59. Name: (A, f), dtype: int64
  60. <class 'pandas.core.series.Series'>
  61. ===========
  62. df.loc[('A','f'),'c1']
  63. 2
  64. <class 'numpy.int64'>

③ 层次化索引的DataFrame的分组聚合

df.sum(level=0)与df.groupby(level=0).sum()等效

df.sum(level=1)与df.groupby(level=1).sum()等效

  1. import numpy as np
  2. import pandas as pd
  3. df = pd.DataFrame([1,2,3,4,5,6,7,8],columns=['c1'],
  4. index=[
  5. ['A','A','B','B','C','C','D','D'],
  6. ['e','f','e','g','f','h','g','h']
  7. ])
  8. print('df\n',df,'\n',type(df)); print('===========')
  9. df1 = df.sum(level=0)
  10. df2 = df.groupby(level=0).sum()
  11. df3 = df.sum(level=1)
  12. df4 = df.groupby(level=1).sum()
  13. print('df1','\n',df1,'\n',type(df1)); print('===========')
  14. print('df2','\n',df2,'\n',type(df2)); print('===========')
  15. print('df3','\n',df3,'\n',type(df3)); print('===========')
  16. print('df4','\n',df4,'\n',type(df4))
  17. 执行结果:
  18. df
  19. c1
  20. A e 1
  21. f 2
  22. B e 3
  23. g 4
  24. C f 5
  25. h 6
  26. D g 7
  27. h 8
  28. <class 'pandas.core.frame.DataFrame'>
  29. ===========
  30. df1
  31. c1
  32. A 3
  33. B 7
  34. C 11
  35. D 15
  36. <class 'pandas.core.frame.DataFrame'>
  37. ===========
  38. df2
  39. c1
  40. A 3
  41. B 7
  42. C 11
  43. D 15
  44. <class 'pandas.core.frame.DataFrame'>
  45. ===========
  46. df3
  47. c1
  48. e 4
  49. f 7
  50. g 11
  51. h 14
  52. <class 'pandas.core.frame.DataFrame'>
  53. ===========
  54. df4
  55. c1
  56. e 4
  57. f 7
  58. g 11
  59. h 14
  60. <class 'pandas.core.frame.DataFrame'>

④ 重置层次化索引

df.reset_index():重置所有层次化索引

df.reset_index(level=0):重置level=0的层次化索引

df.reset_index(level=1):重置level=1的层次化索引

也可以重新设定df.index.levels,详见本章5.DataFrame对象的属性 - (4)df.index.levels

(3)使用unstack()和stack()对层次化索引的Series和DataFrame进行变形(行标签与列标签的转换)

stack: v.堆栈,unstack:v.拆栈

s.unstack()的效果为:将s最内层行标签(纵向)进行转置变为列标签(横向),若转置后数据的行数变为1,则为Series类型数据,否则为DataFrame类型数据

s.stack():报错,Series数据类型没有stack()方法,因为Series数据类型没有可供转置用的列标签

df.unstack()的效果为:将df最内层行标签(纵向)进行转置变为列标签(横向),若转置后数据的行数变为1,则为Series类型数据,否则为DataFrame类型数据

df.stack()的效果为:将df列标签(横向)进行转置变为最内层行标签(纵向),若转置后数据的列数变为1,则为Series类型数据,否则为DataFrame类型数据

  1. # Series的数据变形的例子
  2. import numpy as np
  3. import pandas as pd
  4. s = pd.Series([1,2,3,4,5,6,7,8],
  5. index=[
  6. ['A','A','B','B','C','C','D','D'],
  7. ['e','f','e','g','f','h','g','h']
  8. ])
  9. # s_s = s.stack() # 导致报错
  10. s_u = s.unstack()
  11. s_us = s.unstack().stack() # 又变回了s
  12. s_uu = s.unstack().unstack() # 实现了内、外层索引的互转
  13. print('s\n',s,'\n',type(s)); print('===========')
  14. # print('s_s\n',s_s,'\n',type(s_s)); print('===========') # 导致报错
  15. print('s_u\n',s_u,'\n',type(s_u)); print('===========')
  16. print('s_us\n',s_us,'\n',type(s_us)); print('===========')
  17. print('s_uu\n',s_uu,'\n',type(s_uu))
  18. 执行结果:
  19. s
  20. A e 1
  21. f 2
  22. B e 3
  23. g 4
  24. C f 5
  25. h 6
  26. D g 7
  27. h 8
  28. dtype: int64
  29. <class 'pandas.core.series.Series'>
  30. ===========
  31. s_u
  32. e f g h
  33. A 1.0 2.0 NaN NaN
  34. B 3.0 NaN 4.0 NaN
  35. C NaN 5.0 NaN 6.0
  36. D NaN NaN 7.0 8.0
  37. <class 'pandas.core.frame.DataFrame'>
  38. ===========
  39. s_us
  40. A e 1.0
  41. f 2.0
  42. B e 3.0
  43. g 4.0
  44. C f 5.0
  45. h 6.0
  46. D g 7.0
  47. h 8.0
  48. dtype: float64
  49. <class 'pandas.core.series.Series'>
  50. ===========
  51. s_uu
  52. e A 1.0
  53. B 3.0
  54. C NaN
  55. D NaN
  56. f A 2.0
  57. B NaN
  58. C 5.0
  59. D NaN
  60. g A NaN
  61. B 4.0
  62. C NaN
  63. D 7.0
  64. h A NaN
  65. B NaN
  66. C 6.0
  67. D 8.0
  68. dtype: float64
  69. <class 'pandas.core.series.Series'>
  1. # DataFrame的数据变形的例子
  2. import numpy as np
  3. import pandas as pd
  4. df = pd.DataFrame([1,2,3,4,5,6,7,8],columns=['t1'],
  5. index=[
  6. ['A','A','B','B','C','C','D','D'],
  7. ['e','f','e','g','f','h','g','h']
  8. ])
  9. df_s = df.stack()
  10. df_u = df.unstack()
  11. df_us = df.unstack().stack() # 又变回了df
  12. df_uu = df.unstack().unstack()
  13. print('df\n',df,'\n',type(df)); print('===========')
  14. print('df_s\n',df_s,'\n',type(df_s)); print('===========')
  15. print('df_u\n',df_u,'\n',type(df_u)); print('===========')
  16. print('df_us\n',df_us,'\n',type(df_us)); print('===========')
  17. print('df_uu\n',df_uu,'\n',type(df_uu))
  18. 执行结果:
  19. df
  20. t1
  21. A e 1
  22. f 2
  23. B e 3
  24. g 4
  25. C f 5
  26. h 6
  27. D g 7
  28. h 8
  29. <class 'pandas.core.frame.DataFrame'>
  30. ===========
  31. df_s
  32. A e t1 1
  33. f t1 2
  34. B e t1 3
  35. g t1 4
  36. C f t1 5
  37. h t1 6
  38. D g t1 7
  39. h t1 8
  40. dtype: int64
  41. <class 'pandas.core.series.Series'>
  42. ===========
  43. df_u
  44. t1
  45. e f g h
  46. A 1.0 2.0 NaN NaN
  47. B 3.0 NaN 4.0 NaN
  48. C NaN 5.0 NaN 6.0
  49. D NaN NaN 7.0 8.0
  50. <class 'pandas.core.frame.DataFrame'>
  51. ===========
  52. df_us
  53. t1
  54. A e 1.0
  55. f 2.0
  56. B e 3.0
  57. g 4.0
  58. C f 5.0
  59. h 6.0
  60. D g 7.0
  61. h 8.0
  62. <class 'pandas.core.frame.DataFrame'>
  63. ===========
  64. df_uu
  65. t1 e A 1.0
  66. B 3.0
  67. C NaN
  68. D NaN
  69. f A 2.0
  70. B NaN
  71. C 5.0
  72. D NaN
  73. g A NaN
  74. B 4.0
  75. C NaN
  76. D 7.0
  77. h A NaN
  78. B NaN
  79. C 6.0
  80. D 8.0
  81. dtype: float64
  82. <class 'pandas.core.series.Series'>

14. Pandas中的时间相关格式及方法

(1)Pandas中的时间格式及特殊索引、切片方法

① pandas._libs.tslibs.timestamps.Timestamp:时间戳

② pandas.core.indexes.datetimes.DatetimeIndex:时间格式索引

③ pandas._libs.tslibs.period.Period:时期

④ pandas.core.indexes.period.PeriodIndex:时期格式索引

其中,②是由①组成的,④是由③组成的

当一个DataFrame拥有②或者④格式的行标签索引时,它将支持下面各种灵活的索引、切片方式(注意:对频率为月的④类型行标签索引,索引该月的任意一天即视为索引该月;对频率为年的④类型行标签索引,索引该年的任意一天即视为索引该年):

  1. # 精确索引,只能使用df.loc[]和df.ix[]方式
  2. # df['2019-12-31'] # 精确索引不能使用df[]格式,会导致报错
  3. # df['2019.12.31'] # 精确索引不能使用df[]格式,会导致报错
  4. df.loc['20191231']
  5. df.loc['2019-12-31']
  6. df.loc[pd.datetime(2019,12,31)]
  7. df.ix['20191231']
  8. df.ix['2019-12-31']
  9. df.ix[pd.datetime(2019,12,31)]
  10. ...
  11. # 模糊索引,可以使用df[]、df.loc[]和df.ix[]方式
  12. df['2019-12']
  13. df['2019.12']
  14. df['2019']
  15. df.loc['2019-12']
  16. df.loc['2019.12']
  17. df.loc['2019']
  18. df.ix['2019-12']
  19. df.ix['2019.12']
  20. df.ix['2019']
  21. ...
  22. # 混合使用精确索引和模糊索引进行切片
  23. df['2019-08':'2019-09-22']
  24. df.loc['2019-08':'2019-09-22']
  25. df.ix['2019-08':'2019-09-22']
  26. ...

(2)pd.Timestamp()

语法:pd.Timestamp(n)

返回一个pandas._libs.tslibs.timestamps.Timestamp对象

参数n:经过时间原点的纳秒(10的负9次方秒)数

  1. import numpy as np
  2. import pandas as pd
  3. t1 = pd.Timestamp(0)
  4. t2 = pd.Timestamp(1)
  5. print(t1)
  6. print(t2)
  7. print(type(t2))
  8. 执行结果:
  9. 1970-01-01 00:00:00
  10. 1970-01-01 00:00:00.000000001
  11. <class 'pandas._libs.tslibs.timestamps.Timestamp'>

(3)pd.datetime()

语法:pd.datetime(年,月,日)

返回一个datetime.datetime对象

  1. import numpy as np
  2. import pandas as pd
  3. t = pd.datetime(2019,9,22)
  4. print(t)
  5. print(type(t))
  6. 执行结果:
  7. 2019-09-22 00:00:00
  8. <class 'datetime.datetime'>

(4)pd.to_datetime()

语法:pd.to_datetime(“看着像日期”的数据类型或其组成的list、ndarray、Series)

将“看着像日期”的数据类型(或其组成的list、ndarray、Series)转换为pandas._libs.tslibs.timestamps.Timestamp类型数据(或pandas.core.indexes.datetimes.DatetimeIndex类型数据)

独立的None会转换为None,但是列表中的None则会转换为NaT(pandas._libs.tslibs.nattype.NaTType类的实例化对象)

可使用df['列标签'] = pd.to_datetime(df['列标签']) 的形式将df中的某列从str类型转换为时间类型

可使用df.index = pd.to_datetime(df.index) 的形式将df中的行索引从str类型转换为时间类型

  1. import numpy as np
  2. import pandas as pd
  3. # print(pd.to_datetime('2019922')) 导致报错
  4. print(pd.to_datetime('20190922'),type(pd.to_datetime('20190922'))); print('-----------')
  5. print(pd.to_datetime(['2019-09-22','2019.09.23']))
  6. print(pd.to_datetime(['2019-9-22','2019.9.23']))
  7. print(pd.to_datetime(['Sept 22 2019','September 23rd, 2019'])); print('===========')
  8. print(pd.to_datetime(None),type(pd.to_datetime(None))); print('-----------')
  9. print(pd.to_datetime([None])); print(type(pd.to_datetime([None])));
  10. print(pd.to_datetime([None])[0]); print(type(pd.to_datetime([None])[0])); print('===========')
  11. print(pd.to_datetime(
  12. np.array(['20190922','20190923'])
  13. )); print('-----------')
  14. print(pd.to_datetime(
  15. pd.Series(['20190922','20190923'])
  16. ))
  17. 执行结果:
  18. 2019-09-22 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'>
  19. -----------
  20. DatetimeIndex(['2019-09-22', '2019-09-23'], dtype='datetime64[ns]', freq=None)
  21. DatetimeIndex(['2019-09-22', '2019-09-23'], dtype='datetime64[ns]', freq=None)
  22. DatetimeIndex(['2019-09-22', '2019-09-23'], dtype='datetime64[ns]', freq=None)
  23. ===========
  24. None <class 'NoneType'>
  25. -----------
  26. DatetimeIndex(['NaT'], dtype='datetime64[ns]', freq=None)
  27. <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
  28. NaT
  29. <class 'pandas._libs.tslibs.nattype.NaTType'>
  30. ===========
  31. DatetimeIndex(['2019-09-22', '2019-09-23'], dtype='datetime64[ns]', freq=None)
  32. -----------
  33. 0 2019-09-22
  34. 1 2019-09-23
  35. dtype: datetime64[ns]

(5)pd.DatetimeIndex()

输入一个由“看着像日期”的数据类型组成的一维list,将其中的每一项元素转为pandas._libs.tslibs.timestamps.Timestamp类型后,整体以pandas.core.indexes.datetimes.DatetimeIndex类型返回

列表中的None会转换为NaT(pandas._libs.tslibs.nattype.NaTType类的实例化对象)

可使用df['列标签'] = pd.DatetimeIndex(df['列标签']) 的形式将df中的某列从str类型转换为时间类型

  1. import datetime
  2. import numpy as np
  3. import pandas as pd
  4. dti1 = pd.DatetimeIndex(['20190101','20190102',None])
  5. dti2 = pd.DatetimeIndex(['2019-01-01','2019-01-02'])
  6. dti3 = pd.DatetimeIndex(['Jan 1,2019','January 2nd, 2019'])
  7. dti4 = pd.DatetimeIndex([datetime.datetime(2019,1,1),datetime.datetime(2019,1,2)])
  8. dti5 = pd.DatetimeIndex([pd.datetime(2019,1,1),pd.datetime(2019,1,2)])
  9. dti6 = pd.DatetimeIndex([pd.Timestamp(0),pd.Timestamp(1e18)])
  10. print(dti1,'\n',type(dti1[0]))
  11. print(dti2,'\n',type(dti2[0]))
  12. print(dti3,'\n',type(dti3[0]))
  13. print(dti4,'\n',type(dti4[0]))
  14. print(dti5,'\n',type(dti5[0]))
  15. print(dti6,'\n',type(dti6[0]))
  16. 执行结果:
  17. DatetimeIndex(['2019-01-01', '2019-01-02', 'NaT'], dtype='datetime64[ns]', freq=None)
  18. <class 'pandas._libs.tslibs.timestamps.Timestamp'>
  19. DatetimeIndex(['2019-01-01', '2019-01-02'], dtype='datetime64[ns]', freq=None)
  20. <class 'pandas._libs.tslibs.timestamps.Timestamp'>
  21. DatetimeIndex(['2019-01-01', '2019-01-02'], dtype='datetime64[ns]', freq=None)
  22. <class 'pandas._libs.tslibs.timestamps.Timestamp'>
  23. DatetimeIndex(['2019-01-01', '2019-01-02'], dtype='datetime64[ns]', freq=None)
  24. <class 'pandas._libs.tslibs.timestamps.Timestamp'>
  25. DatetimeIndex(['2019-01-01', '2019-01-02'], dtype='datetime64[ns]', freq=None)
  26. <class 'pandas._libs.tslibs.timestamps.Timestamp'>
  27. DatetimeIndex(['1970-01-01 00:00:00', '2001-09-09 01:46:40'], dtype='datetime64[ns]', freq=None)
  28. <class 'pandas._libs.tslibs.timestamps.Timestamp'>

(6)pd.date_range()

语法:pd.date_range(start=None, end=None, periods=None, freq='D')

生成由若干个pandas._libs.tslibs.timestamps.Timestamp对象组成的pandas.core.indexes.datetimes.DatetimeIndex对象

参数:

  • start:起始日期

  • end:终止日期

  • periods:长度(数据个数)

  • freq:频率(相邻数据的间隔时间),默认值为1天'D'。可以改成诸如30秒'30S'、5分钟'5T'、2小时'2H'、3天'3D'、2周'2W'、每月最后一天'M'、每月第一天'MS'、1年'Y'等形式。此外,频率以'B'为单位时代表工作日,但是这个工作日仅仅代表周一到周五,不考虑法定节假日。此项参数的其他复杂取值:

    名称 说明
    W-MON 周-星期一
    WOM-1MON 月-第1个星期一
    Q-JAN 季度,以一月最后一日结束(可把JAN换成FEB, MAR)
    QS-JAN 季度,以一月第一日结束(可把JAN换成FEB, MAR)
    A-JAN 年,以一月最后一个日历日结束(可把JAN换成FEB,...,DEC)
    AS-JAN 年,以一月第一个日历日结束(可把JAN换成FEB,...,DEC)

注意:

  • 参数freq默认值为'D',start、end、periods三个参数,至少要输入两个,否则报错

  • pd.date_range()常用于给df.index赋值,以便生成行标签,如:

    1. ...
    2. df.index = pd.date_range('2019-9-22', periods=5, freq='M')
  • pd.date_range()生成的DatetimeIndex对象可以用索引方式来取值,如:

    1. ...
    2. t = pd.date_range('2019-9-22', periods=5, freq='M')
    3. print(t[0])
  • 不可以直接用字符串来判断其是否等于返回结果中的某一个日期,可以用pd.datetime()来判断。不过,对于DataFrame中的pd.date_range()类型的标签索引,既可以使用pd.datetime()进行标签索引,也可以使用字符串进行标签索引

代码示例:

  1. import numpy as np
  2. import pandas as pd
  3. import warnings; warnings.simplefilter('ignore') # 忽略可能会出现的警告信息;警告并不是错误,可以忽略;可能出现警告的场景包括:df.ix[]、pd.concat()
  4. t1 = pd.date_range('2019-9-22', periods=2, freq='3D')
  5. t2 = pd.date_range('2019-9-22', periods=2, freq='2W')
  6. t3 = pd.date_range('2019-9-22', periods=3, freq='M')
  7. t4 = pd.date_range('2019-9-22', periods=3, freq='Y')
  8. print('t1','\n',t1,'\n',type(t1),'\n',t1[0],'\n',type(t1[0])); print('-----------')
  9. print('t2','\n',t2); print('-----------')
  10. print('t3','\n',t3); print('-----------')
  11. print('t4','\n',t4); print('===========')
  12. print(t1[0] == '2019-9-22') # 错误的判断方式
  13. print(t1[0] == '2019-09-22') # 错误的判断方式
  14. print(t1[0] == pd.datetime(2019,9,22)) # 正确的判断方式
  15. 执行结果:
  16. t1
  17. DatetimeIndex(['2019-09-22', '2019-09-25'], dtype='datetime64[ns]', freq='3D')
  18. <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
  19. 2019-09-22 00:00:00
  20. <class 'pandas._libs.tslibs.timestamps.Timestamp'>
  21. -----------
  22. t2
  23. DatetimeIndex(['2019-09-22', '2019-10-06'], dtype='datetime64[ns]', freq='2W-SUN')
  24. -----------
  25. t3
  26. DatetimeIndex(['2019-09-30', '2019-10-31', '2019-11-30'], dtype='datetime64[ns]', freq='M')
  27. -----------
  28. t4
  29. DatetimeIndex(['2019-12-31', '2020-12-31', '2021-12-31'], dtype='datetime64[ns]', freq='A-DEC')
  30. ===========
  31. False
  32. False
  33. True

(7)pd.period_range()

语法:pd.period_range(start=None, end=None, periods=None, freq='D')

生成由若干个pandas._libs.tslibs.period.Period对象组成的pandas.core.indexes.period.PeriodIndex对象

参数:

  • start:起始日期
  • end:终止日期
  • periods:长度(数据个数)
  • freq:频率(相邻数据的间隔时间),默认值为1天'D'。可以改成诸如30秒'30S'、5分钟'5T'、2小时'2H'、3天'3D'、每周一'W-Mon'、2周'2W'、1个月'M'、1年'Y'等形式。此外,频率以'B'为单位时代表工作日,但是这个工作日仅仅代表周一到周五,不考虑法定节假日。当频率以月为单位时,产生的数据中仅有年、月;当频率以年为单位时,产生的数据中仅有年

注意:

  • 参数freq默认值为'D'时,start、end、periods三个参数,至少要输入两个,否则报错

  • pd.period_range()常用于给df.index赋值,以便生成行标签,如:

    1. ...
    2. df.index = pd.period_range('2019-9-22', periods=5, freq='W')
  • pd.period_range()生成的PeriodIndex对象可以用索引方式来取值,如:

    1. ...
    2. p = pd.period_range('2019-9-22', periods=5, freq='M')
    3. print(p[0])
  • 不可以直接用字符串来判断其是否等于返回结果中的某一个日期,也不能用pd.datetime()来判断。不过,对于DataFrame中的pandas.core.indexes.period.PeriodIndex类型的标签索引,既可以使用pd.datetime()进行标签索引,也可以使用字符串进行标签索引(对频率为月的pandas.core.indexes.period.PeriodIndex类型行标签索引,索引该月的任意一天即视为索引该月;对频率为年的pandas.core.indexes.period.PeriodIndex类型行标签索引,索引该年的任意一天即视为索引该年)

代码示例:

  1. # 不可以直接用字符串来判断其是否等于返回结果中的某一个日期,也不能用pd.datetime()来判断
  2. import numpy as np
  3. import pandas as pd
  4. p1 = pd.period_range('2019-9-22', periods=2, freq='3D')
  5. p2 = pd.period_range('2019-9-22', periods=2, freq='2W')
  6. p3 = pd.period_range('2019-9-22', periods=3, freq='M')
  7. p4 = pd.period_range('2019-9-22', periods=3, freq='Y')
  8. print('p1','\n',p1,'\n',type(p1),'\n',p1[0],'\n',type(p1[0])); print('-----------')
  9. print('p2','\n',p2); print('-----------')
  10. print('p3','\n',p3); print('-----------')
  11. print('p4','\n',p4); print('===========')
  12. print(p1[0] == '2019-9-22') # 错误的判断方式
  13. print(p1[0] == '2019-09-22') # 错误的判断方式
  14. print(p1[0] == pd.datetime(2019,9,22)) # 错误的判断方式
  15. 执行结果:
  16. p1
  17. PeriodIndex(['2019-09-22', '2019-09-25'], dtype='period[3D]', freq='3D')
  18. <class 'pandas.core.indexes.period.PeriodIndex'>
  19. 2019-09-22
  20. <class 'pandas._libs.tslibs.period.Period'>
  21. -----------
  22. p2
  23. PeriodIndex(['2019-09-16/2019-09-22', '2019-09-30/2019-10-06'], dtype='period[2W-SUN]', freq='2W-SUN')
  24. -----------
  25. p3
  26. PeriodIndex(['2019-09', '2019-10', '2019-11'], dtype='period[M]', freq='M')
  27. -----------
  28. p4
  29. PeriodIndex(['2019', '2020', '2021'], dtype='period[A-DEC]', freq='A-DEC')
  30. ===========
  31. False
  32. False
  33. False
  1. # 频率为日的索引示例
  2. import numpy as np
  3. import pandas as pd
  4. np.random.seed(0)
  5. arr = np.random.randn(5,2)
  6. p = pd.period_range('2019-9-22', periods=5, freq='D') # 频率为日
  7. df = pd.DataFrame(arr, columns=['c1','c2'], index=p)
  8. print(df); print('===========')
  9. print(df.loc['2019-9-22']); print('===========')
  10. print(df.loc[pd.datetime(2019,9,22)])
  11. 执行结果:
  12. c1 c2
  13. 2019-09-22 1.764052 0.400157
  14. 2019-09-23 0.978738 2.240893
  15. 2019-09-24 1.867558 -0.977278
  16. 2019-09-25 0.950088 -0.151357
  17. 2019-09-26 -0.103219 0.410599
  18. ===========
  19. c1 1.764052
  20. c2 0.400157
  21. Name: 2019-09-22, dtype: float64
  22. ===========
  23. c1 1.764052
  24. c2 0.400157
  25. Name: 2019-09-22, dtype: float64
  1. # 频率为月的索引示例
  2. import numpy as np
  3. import pandas as pd
  4. np.random.seed(0)
  5. arr = np.random.randn(5,2)
  6. p = pd.period_range('2019-9-22', periods=5, freq='M') # 频率为月
  7. df = pd.DataFrame(arr, columns=['c1','c2'], index=p)
  8. print(df); print('-----------')
  9. print(df.loc['20190922']); print('-----------')
  10. print(df.loc['2019-9-23']); print('-----------')
  11. print(df.loc[pd.datetime(2019,9,22)]); print('-----------')
  12. print(df.loc[pd.datetime(2019,9,23)])
  13. 执行结果:
  14. c1 c2
  15. 2019-09 1.764052 0.400157
  16. 2019-10 0.978738 2.240893
  17. 2019-11 1.867558 -0.977278
  18. 2019-12 0.950088 -0.151357
  19. 2020-01 -0.103219 0.410599
  20. -----------
  21. c1 1.764052
  22. c2 0.400157
  23. Name: 2019-09, dtype: float64
  24. -----------
  25. c1 1.764052
  26. c2 0.400157
  27. Name: 2019-09, dtype: float64
  28. -----------
  29. c1 1.764052
  30. c2 0.400157
  31. Name: 2019-09, dtype: float64
  32. -----------
  33. c1 1.764052
  34. c2 0.400157
  35. Name: 2019-09, dtype: float64
  1. # 频率为年的索引示例
  2. import numpy as np
  3. import pandas as pd
  4. np.random.seed(0)
  5. arr = np.random.randn(5,2)
  6. p = pd.period_range('2019-9-22', periods=5, freq='Y') # 频率为年
  7. df = pd.DataFrame(arr, columns=['c1','c2'], index=p)
  8. print(df); print('-----------')
  9. print(df.loc['20190922']); print('-----------')
  10. print(df.loc['2019-9-23']); print('-----------')
  11. print(df.loc[pd.datetime(2019,9,22)]); print('-----------')
  12. print(df.loc[pd.datetime(2019,9,23)])
  13. 执行结果:
  14. c1 c2
  15. 2019 1.764052 0.400157
  16. 2020 0.978738 2.240893
  17. 2021 1.867558 -0.977278
  18. 2022 0.950088 -0.151357
  19. 2023 -0.103219 0.410599
  20. -----------
  21. c1 1.764052
  22. c2 0.400157
  23. Name: 2019, dtype: float64
  24. -----------
  25. c1 1.764052
  26. c2 0.400157
  27. Name: 2019, dtype: float64
  28. -----------
  29. c1 1.764052
  30. c2 0.400157
  31. Name: 2019, dtype: float64
  32. -----------
  33. c1 1.764052
  34. c2 0.400157
  35. Name: 2019, dtype: float64

(8)pd.date_range()和pd.period_range()的对比

相同点:

  • 返回值可以作为DataFrame的行标签索引,并支持df[]形式的特殊索引
  • 返回值都可以作为DataFrame数据中的一列

不同点:

  • freq='M'、freq='Y'时显示的数据不同
  • 数据类型不同
  • 由于数据类型不同,导致个别的属性和方法不同(这里不再展开)

(9)df.resample():重采样

resample:v.重采样

对行索引为pandas.core.indexes.datetimes.DatetimeIndex或pandas.core.indexes.period.PeriodIndex类型的DataFrame进行重采样(频率调整),具体步骤为:

  • 首先,获取DataFrame格式数据df

  • 接着,使用resample_obj = df.resample(rule,axis=0,closed=None)获取resample对象(pandas.core.resample.DatetimeIndexResampler类型)

    参数:

    • rule:调整后的频率,如:'S'(秒)、'T''min'(分钟)、'H'(小时)、'D'(天)、'W'(周)、'M'(月)、'Q'(季度)、'A''Y'(年),还可以在字母前加上数字,如:'3D'(3天)
    • axis:默认值为0,按列处理;axis=1时按行处理(一般无须指定此参数)
    • closed:时间区间的闭合方式,left为前闭,right为后闭(一般无须指定此参数)
  • 最后,应用resemple对象的相应方法进行处理,如:

    • 高频调整为低频(降采样)适用的方法:

      • resample_obj.mean():使用对应时间段内所有数据的平均值进行聚合
      • resample_obj.max():使用对应时间段内所有数据的最大值进行聚合(最高价聚合常用)
      • resample_obj.min():使用对应时间段内所有数据的最小值进行聚合(最低价聚合常用)
      • resample_obj.median():使用对应时间段内所有数据的中位数进行聚合
      • resample_obj.sum():使用对应时间段内所有数据的和进行聚合(成交量聚合常用)
      • resample_obj.prod():使用对应时间段内所有数据的乘积进行聚合
      • resample_obj.std():使用对应时间段内所有数据的标准差进行聚合
      • resample_obj.var():使用对应时间段内所有数据的方差进行聚合
      • resample_obj.count():使用对应时间段内所有非空数据的计数进行聚合
      • resample_obj.first():使用对应时间段内的第一个数据进行聚合(开盘价聚合常用)
      • resample_obj.last():使用对应时间段内的最后一个数据进行聚合(收盘价聚合常用)
      • resample_obj.nunique():使用对应时间段内有多少个不同的值来进行聚合
      • resample_obj.asfreq():使用显示的日期所对应的数据进行聚合(比如将日数据降采样为月数据,显示的是每月最后一天,就使用这天的数据进行聚合,但是每月最后一天可能不是交易日没有数据,此时这条数据就是NaN)
      • resample_obj.ohlc():使用对应时间段内所有数据的open、high、low、close四项特征数据进行聚合
      • resample_obj.apply(<func>):使用自定义的聚合函数,apply()方法的详细解释本章“10. DataFrame对象的方法和Pandas模块的方法 -(5)其他方法”,示例代码见本节下面
    • 低频调整为高频(升采样)适用的方法:
      • resample_obj.ffill():使用向前填充法处理空值
      • resample_obj.pad():使用向前填充法处理空值
      • resample_obj.bfill():使用向后填充法处理空值
      • resample_obj.fillna():使用fillna()方法处理空值
      • 线性插值法:
        • resample_obj.interpolate():使用线性插值法填充两个数据之间的空值,简便,推荐
        • df.interpolate():也可以不基于resample对象,手动在两条数据间插入指定数量的空值,然后使用DataFrame对象自带的插值法进行填充,详见本章“9. DataFrame的空值(NaN)处理-(5)df.interpolate()”。但是这样操作过于复杂,不推荐
      • resample_obj.apply(<func>):使用自定义的插值函数,每次传到func()里的是对应时间段的数据组成的Series或DataFrame,详见本章“10. DataFrame对象的方法和Pandas模块的方法 -(5)其他重要方法 - ①df.apply()”

注意:讲义中提到的df.resample('M', how='mean')里的how参数已弃用,以上述新方法为准。

① 高频调整为低频(降采样):通过聚合实现

注意:聚合后的索引是聚合前的索引在该时间段内的最后一个值(若日数据按照月重采样,则索引变为每个月的最后一天)

  1. # 基于收益率的resample_obj.mean()和resample_obj.apply(<func>)方法示例
  2. import pandas as pd
  3. import numpy as np
  4. # 读取本地文件'000001.csv'
  5. data = pd.read_csv('000001.csv', index_col=0, parse_dates=True)
  6. # 使用收盘价计算每日收益率
  7. data_return = data['close'] / data['close'].shift()
  8. # 获取频率为月的resample对象
  9. resample_obj = data_return.resample('M')
  10. print(resample_obj,'\n',type(resample_obj)); print('===========')
  11. # 使用对应月份所有数据的平均值进行聚合(两种方式等效)
  12. print(resample_obj.mean()); print('-----------')
  13. print(resample_obj.apply(lambda x: x.mean())); print('===========') # 当只有一列时,x为Series;当有多列时,x为DataFrame
  14. # 检验聚合结果是否正确
  15. print(data_return['2017-03'].mean().round(6)); print('===========')
  16. print(data_return['2019-07'].mean().round(6))
  17. 执行结果:
  18. DatetimeIndexResampler [freq=<MonthEnd>, axis=0, closed=right, label=right, convention=start, base=0]
  19. <class 'pandas.core.resample.DatetimeIndexResampler'>
  20. ===========
  21. date
  22. 2017-02-28 1.005302
  23. 2017-03-31 0.998575
  24. ...
  25. 2019-07-31 1.001199
  26. 2019-08-31 1.000752
  27. Freq: M, Name: close, dtype: float64
  28. -----------
  29. date
  30. 2017-02-28 1.005302
  31. 2017-03-31 0.998575
  32. ...
  33. 2019-07-31 1.001199
  34. 2019-08-31 1.000752
  35. Freq: M, Name: close, dtype: float64
  36. ===========
  37. 0.998575
  38. ===========
  39. 1.001199
  1. # 基于收盘价的resample_obj.ohlc()方法示例
  2. import pandas as pd
  3. import numpy as np
  4. # 读取本地文件'000001.csv'
  5. data = pd.read_csv('000001.csv', index_col=0, parse_dates=True)
  6. # 获取每日收盘价
  7. data_close = data['close']
  8. # 获取频率为1个月的resample对象
  9. resample_obj = data_close.resample('M')
  10. print(resample_obj,'\n',type(resample_obj)); print('===========')
  11. # 使用对应时间段内所有数据的open、high、low、close四项特征数据进行聚合
  12. print(resample_obj.ohlc()); print('===========')
  13. # 检验OHLC结果是否正确
  14. print(data_close['2017-03-01'])
  15. print(data_close['2017-04'].max())
  16. print(data_close['2019-06'].min())
  17. print(data_close['2019-07-31'])
  18. 执行结果:
  19. DatetimeIndexResampler [freq=<MonthEnd>, axis=0, closed=right, label=right, convention=start, base=0]
  20. <class 'pandas.core.resample.DatetimeIndexResampler'>
  21. ===========
  22. open high low close
  23. date
  24. 2017-02-28 9.43 9.48 9.43 9.48
  25. 2017-03-31 9.49 9.52 9.08 9.17
  26. 2017-04-30 9.21 9.21 8.91 8.99
  27. ...
  28. 2019-06-30 11.90 13.80 11.85 13.78
  29. 2019-07-31 13.93 14.37 13.54 14.13
  30. 2019-08-31 14.10 15.12 13.35 14.25
  31. ===========
  32. 9.49
  33. 9.21
  34. 11.85
  35. 14.13

② 低频调整为高频(升采样):通过线性插值实现

注意:若使用resample_obj.interpolate()方法,则插值前的索引是插值后的索引在该时间段的第一个值(假设日数据按照小时重采样,则每天的实际值变为该日00:00:00的值)

  1. # 基于收盘价的resample_obj.interpolate()方法示例
  2. import pandas as pd
  3. import numpy as np
  4. # 读取本地文件'000001.csv'
  5. data = pd.read_csv('000001.csv', index_col=0, parse_dates=True)
  6. # 获取前两天的收盘价
  7. data_close = data['close'][1:3]
  8. print(data_close); print('===========')
  9. # 获取频率为1小时的resample对象
  10. resample_obj = data_close.resample('H')
  11. print(resample_obj,'\n',type(resample_obj)); print('===========')
  12. # 使用线性插值法填补中间空缺的数据
  13. print(resample_obj.interpolate())
  14. 执行结果:
  15. date
  16. 2017-02-28 9.48
  17. 2017-03-01 9.49
  18. Name: close, dtype: float64
  19. ===========
  20. DatetimeIndexResampler [freq=<Hour>, axis=0, closed=left, label=left, convention=start, base=0]
  21. <class 'pandas.core.resample.DatetimeIndexResampler'>
  22. ===========
  23. date
  24. 2017-02-28 00:00:00 9.480000
  25. 2017-02-28 01:00:00 9.480417
  26. 2017-02-28 02:00:00 9.480833
  27. 2017-02-28 03:00:00 9.481250
  28. ...
  29. 2017-02-28 21:00:00 9.488750
  30. 2017-02-28 22:00:00 9.489167
  31. 2017-02-28 23:00:00 9.489583
  32. 2017-03-01 00:00:00 9.490000
  33. Freq: H, Name: close, dtype: float64

(10)df.rolling():滑动时间窗

对DataFrame或Series类型数据进行滑动时间窗处理,具体步骤为:

  • 首先,获取DataFrame格式数据df(或Series类型数据s)
  • 接着,使用rolling_obj = df.rolling(window, min_periods=None, center=False)获取rolling对象(pandas.core.window.Rolling类型),参数:
    • window:时间窗大小,即时间窗中包含几个数据,必须输入(int类型)
    • min_periods:在边界处使时间窗计算结果不为NaN的最小数据量,默认为None,此时时间窗中必须有window个数据才会计算结果,否则显示NaN;指定min_periods后,时间窗中只要有min_periods个数据就可以计算结果。
    • center:时间窗标签是否居中,默认为False,此时时间窗标签为时间窗内最后一个时间点(即时间窗内最后一行的行标签);center=True时,时间窗标签为时间窗内中间位置的时间点(即时间窗内中间一行的行标签)
  • 最后,应用rolling对象的相应方法进行处理,如:
    • rolling_obj.mean():使用时间窗内所有数据的平均值作为时间窗标签对应的值(移动平均SMA)
    • rolling_obj.max():使用时间窗内所有数据的最大值作为时间窗标签对应的值
    • rolling_obj.min():使用时间窗内所有数据的最小值作为时间窗标签对应的值
    • rolling_obj.sum():使用时间窗内所有数据的和作为时间窗标签对应的值
    • rolling_obj.std():使用时间窗内所有数据的标准差作为时间窗标签对应的值
    • rolling_obj.apply(<func>):编写自定义函数func,将时间窗内所有数据作为参数传递给func,并将func的返回值作为时间窗标签对应的值
  1. # 滑动时间窗示例
  2. import pandas as pd
  3. import numpy as np
  4. # 读取本地文件'000001.csv'
  5. data = pd.read_csv('000001.csv', index_col=0, parse_dates=True)
  6. # 获取每日收盘价
  7. data_close = data['close']
  8. # 获取不同参数的rolling对象
  9. rolling_obj3 = data_close.rolling(3)
  10. rolling_obj32 = data_close.rolling(3, min_periods=2)
  11. rolling_obj31 = data_close.rolling(3, min_periods=1)
  12. rolling_obj3c = data_close.rolling(3, center=True)
  13. # 使用rolling对象进行滑动时间窗处理
  14. print('data_close\n',data_close); print('===========')
  15. print(rolling_obj3,type(rolling_obj3)); print('===========')
  16. print('rolling_obj3.mean()\n',rolling_obj3.mean()); print('===========')
  17. print('rolling_obj32.mean()\n',rolling_obj32.mean()); print('===========')
  18. print('rolling_obj31.mean()\n',rolling_obj31.mean()); print('===========')
  19. print('rolling_obj3c.mean()\n',rolling_obj3c.mean())
  20. 执行结果:
  21. data_close
  22. date
  23. 2017-02-27 9.43
  24. 2017-02-28 9.48
  25. 2017-03-01 9.49
  26. 2017-03-02 9.43
  27. 2017-03-03 9.40
  28. ...
  29. 2019-08-20 14.99
  30. 2019-08-21 14.45
  31. 2019-08-22 14.31
  32. 2019-08-23 14.65
  33. 2019-08-26 14.25
  34. Name: close, Length: 613, dtype: float64
  35. ===========
  36. Rolling [window=3,center=False,axis=0] <class 'pandas.core.window.Rolling'>
  37. ===========
  38. rolling_obj3.mean()
  39. date
  40. 2017-02-27 NaN
  41. 2017-02-28 NaN
  42. 2017-03-01 9.466667
  43. 2017-03-02 9.466667
  44. 2017-03-03 9.440000
  45. ...
  46. 2019-08-20 14.936667
  47. 2019-08-21 14.786667
  48. 2019-08-22 14.583333
  49. 2019-08-23 14.470000
  50. 2019-08-26 14.403333
  51. Name: close, Length: 613, dtype: float64
  52. ===========
  53. rolling_obj32.mean()
  54. date
  55. 2017-02-27 NaN
  56. 2017-02-28 9.455000
  57. 2017-03-01 9.466667
  58. 2017-03-02 9.466667
  59. 2017-03-03 9.440000
  60. ...
  61. 2019-08-20 14.936667
  62. 2019-08-21 14.786667
  63. 2019-08-22 14.583333
  64. 2019-08-23 14.470000
  65. 2019-08-26 14.403333
  66. Name: close, Length: 613, dtype: float64
  67. ===========
  68. rolling_obj31.mean()
  69. date
  70. 2017-02-27 9.430000
  71. 2017-02-28 9.455000
  72. 2017-03-01 9.466667
  73. 2017-03-02 9.466667
  74. 2017-03-03 9.440000
  75. ...
  76. 2019-08-20 14.936667
  77. 2019-08-21 14.786667
  78. 2019-08-22 14.583333
  79. 2019-08-23 14.470000
  80. 2019-08-26 14.403333
  81. Name: close, Length: 613, dtype: float64
  82. ===========
  83. rolling_obj3c.mean()
  84. date
  85. 2017-02-27 NaN
  86. 2017-02-28 9.466667
  87. 2017-03-01 9.466667
  88. 2017-03-02 9.440000
  89. 2017-03-03 9.426667
  90. ...
  91. 2019-08-20 14.786667
  92. 2019-08-21 14.583333
  93. 2019-08-22 14.470000
  94. 2019-08-23 14.403333
  95. 2019-08-26 NaN
  96. Name: close, Length: 613, dtype: float64

Python数据分析之Pandas操作大全的更多相关文章

  1. Python数据分析之Numpy操作大全

    从头到尾都是手码的,文中的所有示例也都是在Pycharm中运行过的,自己整理笔记的最大好处在于可以按照自己的思路来构建矿建,等到将来在需要的时候能够以最快的速度看懂并应用=_= 注:为方便表述,本章设 ...

  2. Python数据分析库pandas基本操作

    Python数据分析库pandas基本操作2017年02月20日 17:09:06 birdlove1987 阅读数:22631 标签: python 数据分析 pandas 更多 个人分类: Pyt ...

  3. 【Python数据分析】Python3操作Excel(二) 一些问题的解决与优化

    继上一篇[Python数据分析]Python3操作Excel-以豆瓣图书Top250为例 对豆瓣图书Top250进行爬取以后,鉴于还有一些问题没有解决,所以进行了进一步的交流讨论,这期间得到了一只尼玛 ...

  4. Python数据分析之pandas基本数据结构:Series、DataFrame

    1引言 本文总结Pandas中两种常用的数据类型: (1)Series是一种一维的带标签数组对象. (2)DataFrame,二维,Series容器 2 Series数组 2.1 Series数组构成 ...

  5. Python 数据分析:Pandas 缺省值的判断

    Python 数据分析:Pandas 缺省值的判断 背景 我们从数据库中取出数据存入 Pandas None 转换成 NaN 或 NaT.但是,我们将 Pandas 数据写入数据库时又需要转换成 No ...

  6. python中numpy矩阵运算操作大全(非常全)!

    python中numpy矩阵运算操作大全(非常全) //2019.07.10晚python矩阵运算大全1.矩阵的输出形式:对于任何一个矩阵,python输出的模板是:import numpy as n ...

  7. Python数据分析之pandas学习

    Python中的pandas模块进行数据分析. 接下来pandas介绍中将学习到如下8块内容:1.数据结构简介:DataFrame和Series2.数据索引index3.利用pandas查询数据4.利 ...

  8. Python openpyxl、pandas操作Excel方法简介与具体实例

    本篇重点讲解windows系统下 Python3.5中第三方excel操作库-openpyxl: 其实Python第三方库有很多可以操作Excel,如:xlrd,xlwt,xlwings甚至注明的数据 ...

  9. Python数据分析之pandas

    Python中的pandas模块进行数据分析. 接下来pandas介绍中将学习到如下8块内容:1.数据结构简介:DataFrame和Series2.数据索引index3.利用pandas查询数据4.利 ...

随机推荐

  1. 转载:DRC

    https://cn.mathworks.com/help/audio/ug/dynamic-range-control.html?requestedDomain=cn.mathworks.com h ...

  2. windows系统下,gpu开发环境部署

    1,安装python,使用anaconda或者直接用python.exe安装都可以.我用的是python3.6版的 对于相关的程序包,比如tensorflow或者opencv等,anaconda可以在 ...

  3. curl模板----php发送post,get请求

    function _grab($curl,$ip='',$referer='',$postInfo='',$cookie=''){ $ch = curl_init(); curl_setopt($ch ...

  4. IDEA 运行项目、模块的多个实例

    IDEA默认只能运行同一项目|模块的一个实例. 运行多个实例: 比如springcloud的端口设置: --server.port=9001 . 当然,也可以在项目的配置文件中修改参数. 命令行.ID ...

  5. bugku getshell

    http://123.206.87.240:8002/web9/ 该题是walf严格匹配,通过修改Content-type后字母的大小写可以绕过检测, 然后还有,后缀黑名单检测和类型检测,逐个绕过,如 ...

  6. python evel()的用法

    老生常谈部分: eval(expression[, globals[, locals]]) expression -- 表达式. globals -- 变量作用域,全局命名空间,如果被提供,则必须是一 ...

  7. 02-Spring的IOC示例程序(通过id获取对象)

    *******通过IOC容器创建id对象并为属性赋值******** 整体结构: ①创建一个java工程 ②导包 ③创建log4j.properties日记配置文件 # Global logging ...

  8. NIO的理解

    一.缓冲区(Buffer):在java NIO中负责数据的存取,实际上就是数组,用于存储不用数据类型的数据,根据数据类型不同(boolean除外),提供了相应类型的缓冲区(ByteBuffer,Cha ...

  9. 【Python协程的实现】

    " 补充:数据安全问题 进程: 多个进程操作同一个文件,会出现数据不安全 线程: 多个线程操作同一个全局变量,会出现数据不安全 对于共享的数据操作: 如果是 += *= /= -= 操作,都 ...

  10. disconf---分布式配置管理平台的搭建(windows版本)

    本人由刚开始接触博客,难免会有不足和错误,写博客只是记录本人在学习和工作的过程中的成长,如有不足,欢迎各位指正,谢谢~ 一.废话不多说,直接进入正题: ①获取github代码 https://gith ...