# 核心概念

  • Pandas是一个高性能的数据操作和分析工具。它在Numpy的基础上,提供了一种高效的DataFrame数据结构,使得在Python中进行数据清洗和分析非常快捷。
  • Pandas主要用于处理表格表格型或者异质型数据,而Numpy主要处理同质且是数值类型数据。
  • Pandas的核心是三大数据结构:Series、DataFrame和Index。绝大多数操作都是围绕这三种结构进行的。
  • Series是一个一维的数组对象,它包含一个值序列和一个对应的索引序列。
  • DataFrame是Pandas的核心数据结构,表示的是二维的矩阵数据表,类似关系型数据库的结构,每一列可以是不同的值类型,比如数值、字符串、布尔值等等。

# Series

  • Series是一个一维的数组对象,它包含一个值序列和一个对应的索引序列。

    • 可以为Series对象和其索引设置name属性,有助于标记识别

      In [29]: s4.name = 'people'
      
      In [30]: s4.index.name= 'city'
      
      In [31]: s4
      Out[31]:
      city
      nanjing          NaN
      shanghai     71000.0
      guangzhou    16000.0
      beijing      35000.0
      Name: people, dtype: float64
      
      In [32]: s4.index
      Out[32]: Index(['nanjing', 'shanghai', 'guangzhou', 'beijing'], dtype='object', name='city')
      	
      
    • 可以分别通过values和index属性分别获取Series对象的值和索引。

      In [6]: s.values
      Out[6]: array([ 7, -3,  4, -2], dtype=int64)
      
      In [7]: s.index
      Out[7]: RangeIndex(start=0, stop=4, step=1)
      
      
  • Numpy的一维数组通过隐式定义的整数索引获取元素值,而Series用一种显式定义的索引与元素关联。

    • 显式索引让Series对象拥有更强的能力,索引也不再仅仅是整数,还可以是别的类型,比如字符串,索引也不需要连续,也可以重复,自由度非常高。

      In [1]: import pandas as pd
      In [2]: s = pd.Series([7,-3,4,-2])
      In [3]: s
      Out[3]:
      0    7
      1   -3
      2    4
      3   -2
      dtype: int64
      
      
    • 可以在创建时指定索引,还可以通过索引去筛选结果(使用dict创造字典时,不存在的值为NaN)

      In [8]: s2 = pd.Series([7,-3,4,-2], index=['d','b','a','c'])
      
      In [9]: s2
      Out[9]:
      d    7
      b   -3
      a    4
      c   -2
      dtype: int64
      
      In [10]: s2.index
      Out[10]: Index(['d', 'b', 'a', 'c'], dtype='object')
      
      In [5]: pd.Series({2:'a',1:'b',3:'c'}, index=[3,2]) # 通过index筛选结果
      Out[5]:
      3    c
      2    a
      dtype: object
      
    • 索引可以被修改

      In [33]: s
      Out[33]:
      0    7
      1   -3
      2    4
      3   -2
      dtype: int64
      
      In [34]: s.index = ['a','b','c','d']
      
      In [35]: s
      Out[35]:
      a    7
      b   -3
      c    4
      d   -2
      dtype: int64
      
    • 可以通过索引获取值

      In [11]: s2['a']
      Out[11]: 4
      
      In [12]: s2[['c','a','d']]
      Out[12]:
      c   -2
      a    4
      d    7
      dtype: int64
      
    • 索引可以使用in操作,因为Series比较类似Python的有序字典

      In [17]: 'b' in s2
      Out[17]: True
      
      In [18]: 'e'in s2
      Out[18]: False
      
    • 实际上默认还有一个从0开始的索引供我们使用

    • 注意:如果你的Series是显式的整数索引,那么s[1]这样的取值操作会使用显式索引,而s[1:3]这样的切片操作却会使用隐式索引。(这是一个历史遗留问题)

  • 可以对Series执行一些类似Numpy的通用函数操作

    In [13]: s2[s2>0]
    Out[13]:
    d    7
    a    4
    dtype: int64
    
    In [14]: s2*2
    Out[14]:
    d    14
    b    -6
    a     8
    c    -4
    dtype: int64
    
  • 可以使用isnull和notnull来检查缺失的数据

    In [25]: pd.isnull(s4)
    Out[25]:
    nanjing       True
    shanghai     False
    guangzhou    False
    beijing      False
    dtype: bool
    
    In [26]: pd.notnull(s4)
    Out[26]:
    nanjing      False
    shanghai      True
    guangzhou     True
    beijing       True
    dtype: bool
    
    In [27]: s4.isnull()
    Out[27]:
    nanjing       True
    shanghai     False
    guangzhou    False
    beijing      False
    dtype: bool
    

# DataFrame

  • DataFrame是Pandas的核心数据结构,表示的是二维的矩阵数据表,类似关系型数据库的结构

  • DataFrame每一列可以是不同的值类型,比如数值、字符串、布尔值等等。

  • DataFrame中,一切优先按列操作。

  • DataFrame既有行索引,也有列索引,它可以被看做为一个共享相同索引的Series的字典。

    • 可以通过columns,index和values分别查看DataFrame对象的columns和index属性以及DataFrame的值。

      In [39]: f
      Out[39]:
            state  year  pop
      0   beijing  2000  1.5
      1   beijing  2001  1.7
      2   beijing  2002  3.6
      3  shanghai  2001  2.4
      4  shanghai  2002  2.9
      5  shanghai  2003  3.2
      
      In [61]: f.columns
      Out[61]: Index(['state', 'year', 'pop'], dtype='object')
      
      In [62]: f.index
      Out[62]: RangeIndex(start=0, stop=6, step=1)
      
    • 创建时可以指定columns和index

      In [45]: f2 = pd.DataFrame(data, columns=['year','state','pop'],index=['a','b','c','d','e','f'])
      
      In [47]: f2
      Out[47]:
         year     state  pop
      a  2000   beijing  1.5
      b  2001   beijing  1.7
      c  2002   beijing  3.6
      d  2001  shanghai  2.4
      e  2002  shanghai  2.9
      f  2003  shanghai  3.2
      
    • DataFrame可以为列和索引设置名字

      In [70]: f2.index.name = 'order';f2.columns.name='key'
      
  • 可以使用columns来检索某一列

    In [49]: f2['year'] # f2.year也可以,但bug多. 例如属性名不是纯字符串时或者与其他方法同名等...
    Out[49]:
    a    2000
    b    2001
    c    2002
    d    2001
    e    2002
    f    2003
    Name: year, dtype: int64
    
    • 可以直接追加列

      In [54]: f2['debt'] = 12
      
      In [55]: f2
      Out[55]:
         year     state  pop  debt
      a  2000   beijing  1.5    12
      b  2001   beijing  1.7    12
      c  2002   beijing  3.6    12
      d  2001  shanghai  2.4    12
      e  2002  shanghai  2.9    12
      f  2003  shanghai  3.2    12
      
      In [56]: f2['debt'] = np.arange(1,7)
      
      In [57]: f2
      Out[57]:
         year     state  pop  debt
      a  2000   beijing  1.5     1
      b  2001   beijing  1.7     2
      c  2002   beijing  3.6     3
      d  2001  shanghai  2.4     4
      e  2002  shanghai  2.9     5
      f  2003  shanghai  3.2     6
      
      
      In [58]: val = pd.Series([1,2,3],index = ['c','d','f'])
      
      In [59]: f2['debt'] = val
      
      In [60]: f2  # 缺失值以NaN填补
      Out[60]:
         year     state  pop  debt
      a  2000   beijing  1.5   NaN
      b  2001   beijing  1.7   NaN
      c  2002   beijing  3.6   1.0
      d  2001  shanghai  2.4   2.0
      e  2002  shanghai  2.9   NaN
      f  2003  shanghai  3.2   3.0
      
    • 使用del方法删除指定列

      del f2['new']
      
  • 可以通过loc方法选取某一行,以指定的显式索引进行索引。

    In [53]: f2.loc['a']
    Out[53]:
    year        2000
    state    beijing
    pop          1.5
    Name: a, dtype: object
    
    • 使用append方法追加行

      >>> df1 = df.loc['a']
      >>> df1
      
      state    beijing
      year        2000
      pop          1.5
      Name: a, dtype: object
      
      >>> df.append(df1)
      
      state   year    pop
      a   beijing 2000    1.5
      b   beijing 2001    1.7
      c   beijing 2002    3.6
      d   shanghai    2001    2.4
      e   shanghai    2002    2.9
      f   shanghai    2003    3.2
      a   beijing 2000    1.5
      
    • 也可以使用iloc方法选取某一行,iloc以隐含的整数索引进行索引。

  • 可以使用类似Numpy的T属性,将DataFrame进行转置

  • 可以使用info方法查看DataFrame的整体信息情况

    In [73]: f.info()
    Out[73]:
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 6 entries, 0 to 5
    Data columns (total 3 columns):
    state    6 non-null object
    year     6 non-null int64
    pop      6 non-null float64
    dtypes: float64(1), int64(1), object(1)
    memory usage: 224.0+ bytes
    

# Index

  • Pandas 中的索引对象Index用于存储轴标签和其它元数据,不可变。

  • 索引可以使用in操作,因为其本质上是一个容器对象。

    In [84]: f2
    Out[84]:
    key    year     state  pop  debt
    order
    a      2000   beijing  1.5   NaN
    b      2001   beijing  1.7   NaN
    c      2002   beijing  3.6   1.0
    d      2001  shanghai  2.4   2.0
    e      2002  shanghai  2.9   NaN
    f      2003  shanghai  3.2   3.0
    
    In [86]: 'c' in f2.index
    Out[86]: True
    
    In [88]: 'pop' in f2.columns
    Out[88]: True
    
  • 索引可以包含重复的标签,同时可以查看其is_unique属性来判断是否存在重复的所有

    In [89]: dup_lables = pd.Index(['foo','foo','bar','bar'])
    
    In [90]: dup_lables
    Out[90]: Index(['foo', 'foo', 'bar', 'bar'], dtype='object')
    
    In [91]: f2.index = ['a']*6
    
    In [92]: f2
    Out[92]:
    key  year     state  pop  debt
    a    2000   beijing  1.5   NaN
    a    2001   beijing  1.7   NaN
    a    2002   beijing  3.6   1.0
    a    2001  shanghai  2.4   2.0
    a    2002  shanghai  2.9   NaN
    a    2003  shanghai  3.2   3.0
    
    In [93]: f2.loc['a']
    Out[93]:
    key  year     state  pop  debt
    a    2000   beijing  1.5   NaN
    a    2001   beijing  1.7   NaN
    a    2002   beijing  3.6   1.0
    a    2001  shanghai  2.4   2.0
    a    2002  shanghai  2.9   NaN
    a    2003  shanghai  3.2   3.0
    
    In [94]: f2.columns = ['year']*4
    
    In [95]: f2
    Out[95]:
       year      year  year  year
    a  2000   beijing   1.5   NaN
    a  2001   beijing   1.7   NaN
    a  2002   beijing   3.6   1.0
    a  2001  shanghai   2.4   2.0
    a  2002  shanghai   2.9   NaN
    a  2003  shanghai   3.2   3.0
    
  • 当使用reindex时不是就地修改,而是参照原有数据,调整顺序,并将不存在的索引引入缺失值。

    In [96]: obj=pd.Series([4.5,7.2,-5.3,3.6],index = ['d','b','a','c'])
    
    In [97]: obj
    Out[97]:
    d    4.5
    b    7.2
    a   -5.3
    c    3.6
    dtype: float64
    
    In [99]: obj2 = obj.reindex(list('abcde'))
    
    In [100]: obj2
    Out[100]:
    a   -5.3
    b    7.2
    c    3.6
    d    4.5
    e    NaN
    dtype: float64
    
    • 可以为缺失值指定填充方式method参数,比如ffill表示向前填充,bfill表示向后填充

      In [101]: obj3 = pd.Series(['blue','purple','yellow'],index = [0,2,4])
      
      In [102]: obj3
      Out[102]:
      0      blue
      2    purple
      4    yellow
      dtype: object
      
      In [103]: obj3.reindex(range(6),method='ffill')
      Out[103]:
      0      blue
      1      blue
      2    purple
      3    purple
      4    yellow
      5    yellow
      dtype: object
      
    • 当reindex只提供一个列表参数时默认是修改行索引,可以使用关键词参数columns指定修改列索引。

  • 使用map方法可以修改原油的index

    • 本质上map是对每一个元素执行一样的操作,而Index实质上也是一个容器

      In [83]: df = pd.DataFrame(np.arange(12).reshape((3, 4)),
          ...:                     index=['Ohio', 'Colorado', 'New York'],
          ...:                     columns=['one', 'two', 'three', 'four'])
          ...:
      
      In [84]: transform = lambda x: x[:4].upper() # 截取前4个字符并大写
      
      In [85]: df.index.map(transform) # map的结果
      Out[85]: Index(['OHIO', 'COLO', 'NEW '], dtype='object')
      
    • 或者传入一个字典,将指定的索引命名成新值,不会修改原有值(除非设置inplace=True)

      In [90]: df.rename(index={'OHIO': 'INDIANA'},
          ...:             columns={'three': 'peekaboo'})
          ...:
      Out[90]:
               one  two  peekaboo  four
      INDIANA    0    1         2     3
      COLO       4    5         6     7
      NEW        8    9        10    11
      
  • 使用rename方法修改索引但是不会修改原有数据

    In [88]: df.rename(index=str.title, columns=str.upper)
    Out[88]:
          ONE  TWO  THREE  FOUR
    Ohio    0    1      2     3
    Colo    4    5      6     7
    New     8    9     10    11
    
    In [89]: df # 原值未变
    Out[89]:
          one  two  three  four
    OHIO    0    1      2     3
    COLO    4    5      6     7
    NEW     8    9     10    11