1. 程式人生 > >數據分析之pandas教程-----概念篇

數據分析之pandas教程-----概念篇

對齊 0.12 概念 sta 等等 valid nbsp get 小數

目錄

  • 1 pandas基本概念
    • 1.1 pandas數據結構剖析
      • 1.1.1 Series
      • 1.1.2 DataFrame
      • 1.1.3 索引
      • 1.1.4 pandas基本操作
        • 1.1.4.1 重索引
        • 1.1.4.2 丟棄一行或者一列
        • 1.1.4.3 數據選取
        • 1.1.4.4 數據對齊
      • 1.1.5 pandas函數簡單介紹
        • 1.1.5.1 apply和applymap函數
        • 1.1.5.2 排序函數
        • 1.1.5.3 匯總計算函數
      • 1.1.6 缺失值的處理
      • 1.1.7 整數索引

pandas基本概念

pandas數據結構剖析

Series

Series = 一組數據 + 數據標簽

如果從表格的角度來看, 就是表格裏面的一列帶著索引.

from pandas import Series, DataFrame
import pandas as pd
import numpy as np

obj = Series(data=[1, 2, 3, 4])
print(obj)

# 我們可以用values和index分別獲取數據和標簽
print(obj.values)
print(type(obj.values))
print(obj.index)
print(type(obj.index))
0    1
1    2
2    3
3    4
dtype: int64
[1 2 3 4]
<class ‘numpy.ndarray‘>
RangeIndex(start=0, stop=4, step=1)
<class ‘pandas.core.indexes.range.RangeIndex‘>

我們發現, 這個obj.values其實就是一個numpy對象, 而obj.index是一個index對象, 我們也可以在代碼指定index:

obj2 = Series(data=[1, 2, 3, 4], index=[‘a‘, ‘b‘, ‘c‘, ‘d‘], dtype=np.float32, name=‘test‘)
print(obj2)
a    1.0
b    2.0
c    3.0
d    4.0
Name: test, dtype: float32

我們要註意, Series的標簽和數據的對應關系, 不隨運算而改變. 大部分在np裏面可以使用的操作, 在Series上都是行得通的.

print(obj2 * 2)
print(obj2 ** 2)
print(np.exp(obj2))
a    2.0
b    4.0
c    6.0
d    8.0
Name: test, dtype: float32
a     1.0
b     4.0
c     9.0
d    16.0
Name: test, dtype: float32
a     2.718282
b     7.389056
c    20.085537
d    54.598148
Name: test, dtype: float32

Series其實也可以看作是一個字典, 我們來看這麽個例子:

obj3 = Series({‘a‘:1, ‘b‘:2})
print(obj3)
print(‘a‘ in obj3)
a    1
b    2
dtype: int64
True

我們照樣可以改變索引:

obj3 = Series({‘a‘:1, ‘b‘:2}, index=[‘a‘, ‘c‘])
print(obj3)
a    1.0
c    NaN
dtype: float64

NaN表示缺失數據, 我們可以用isnull和notnull看來判斷:

print(pd.isnull(obj3))
print(pd.notnull(obj3))
a    False
c     True
dtype: bool
a     True
c    False
dtype: bool

我們來看一個加法的例子:

a = Series([1, 2], index=[‘a‘, ‘b‘])
b = Series([2, 3], index=[‘b‘, ‘c‘])
print(a + b)
a    NaN
b    4.0
c    NaN
dtype: float64

兩個Series對象在做運算時, 會自動對齊.

DataFrame

DataFrame可以看作是一張表, 我們也可以把它看作是橫向和縱向兩個Series.

構造DataFrame可以通過一個ndarray或者是list的字典來構造.

data = {‘a‘:[1, 2, 3], ‘b‘:[4, 5, 6] }
frame = DataFrame(data)
print(frame)
   a  b
0  1  4
1  2  5
2  3  6

我們一樣也可以指定index, 不過對於DataFrame, 要指定columns和index.

frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])
print(frame)
   a  b    c
A  1  4  NaN
B  2  5  NaN
C  3  6  NaN

我們可以用一個二維ndarray來初始化DataFrame:

data = np.random.randn(3, 3)
frame = DataFrame(data)
print(frame)

print("-----------------------------------------------------------------")

frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])
print(frame)
          0         1         2
0 -0.219102 -1.849864 -0.545050
1 -2.639734  0.489300  0.911258
2  0.810350  0.383256 -0.815600
-----------------------------------------------------------------
          a         b         c
A -0.219102 -1.849864 -0.545050
B -2.639734  0.489300  0.911258
C  0.810350  0.383256 -0.815600

我們用索引的方式, 可以獲取到某一列, 作為Series.

print(frame[‘a‘])
A   -0.219102
B   -2.639734
C    0.810350
Name: a, dtype: float64

我們發現, 這個Series的名字, 就是列名.

如果我們要修改DataFrame的某個值, 怎麽改呢? 我們先來看看怎麽修改某一列的值.

# 修改某一個列的值
frame[‘a‘] = [1,1,1]
print(frame)
   a         b         c
A  1 -1.849864 -0.545050
B  1  0.489300  0.911258
C  1  0.383256 -0.815600
# 如果我們list的長度不符合, 就會報錯
frame[‘a‘] = [1,1]
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-81-54000a6faf10> in <module>()
      1 # 如果我們list的長度不符合, 就會報錯
----> 2 frame[‘a‘] = [1,1]


d:\anaconda3\envs\tensorflow_gpu\lib\site-packages\pandas\core\frame.py in __setitem__(self, key, value)
   2329         else:
   2330             # set column
-> 2331             self._set_item(key, value)
   2332 
   2333     def _setitem_slice(self, key, value):


d:\anaconda3\envs\tensorflow_gpu\lib\site-packages\pandas\core\frame.py in _set_item(self, key, value)
   2395 
   2396         self._ensure_valid_index(value)
-> 2397         value = self._sanitize_column(key, value)
   2398         NDFrame._set_item(self, key, value)
   2399 


d:\anaconda3\envs\tensorflow_gpu\lib\site-packages\pandas\core\frame.py in _sanitize_column(self, key, value, broadcast)
   2566 
   2567             # turn me into an ndarray
-> 2568             value = _sanitize_index(value, self.index, copy=False)
   2569             if not isinstance(value, (np.ndarray, Index)):
   2570                 if isinstance(value, list) and len(value) > 0:


d:\anaconda3\envs\tensorflow_gpu\lib\site-packages\pandas\core\series.py in _sanitize_index(data, index, copy)
   2877 
   2878     if len(data) != len(index):
-> 2879         raise ValueError(‘Length of values does not match length of ‘ ‘index‘)
   2880 
   2881     if isinstance(data, PeriodIndex):


ValueError: Length of values does not match length of index
# 對於這種情況, 我們可以用Series來搞定
s = Series({‘A‘:1, ‘B‘:1})
frame[‘a‘] = s
print(frame)
     a         b         c
A  1.0 -1.849864 -0.545050
B  1.0  0.489300  0.911258
C  NaN  0.383256 -0.815600

如果我們要新加一列, 可以這樣寫:

frame[‘d‘] = s
print(frame)
     a         b         c    d
A  1.0 -1.849864 -0.545050  1.0
B  1.0  0.489300  0.911258  1.0
C  NaN  0.383256 -0.815600  NaN

如果我們要刪除一列, 可以用del

print(frame.columns)
del frame[‘d‘]
print(frame.columns)
Index([‘a‘, ‘b‘, ‘c‘, ‘d‘], dtype=‘object‘)
Index([‘a‘, ‘b‘, ‘c‘], dtype=‘object‘)

我們還可以用字典來初始化我們的DataFrame:

data = {‘a‘:{‘A‘:1,‘B‘:2}, ‘b‘:{‘A‘:3,‘B‘:4}}
frame = DataFrame(data)
print(frame)
print(frame.columns)
print(frame.index)
print(frame.values)
   a  b
A  1  3
B  2  4
Index([‘a‘, ‘b‘], dtype=‘object‘)
Index([‘A‘, ‘B‘], dtype=‘object‘)
[[1 3]
 [2 4]]

有Series的字典也可以初始化DataFrame, 我們這裏不演示了, 留作作業.

作業1: 用Series的字典初始化DataFrame.

索引

下面我們來裏聊聊索引, 這個也是pandas中比較基本的一個概念.

index = frame.index
colunms = frame.columns
print(type(colunms))
print(type(index))
print(index.name)
print(colunms.name)
<class ‘pandas.core.indexes.base.Index‘>
<class ‘pandas.core.indexes.base.Index‘>
None
None

我們可以把索引理解為 ** 不可變的hashset **

print(index)
Index([‘A‘, ‘B‘], dtype=‘object‘)
index[1]=‘D‘
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-88-e57751cb899e> in <module>()
----> 1 index[1]=‘D‘


d:\anaconda3\envs\tensorflow_gpu\lib\site-packages\pandas\core\indexes\base.py in __setitem__(self, key, value)
   1668 
   1669     def __setitem__(self, key, value):
-> 1670         raise TypeError("Index does not support mutable operations")
   1671 
   1672     def __getitem__(self, key):


TypeError: Index does not support mutable operations

註意這行錯誤:
Index does not support mutable operations

此外, 索引也支持hashset類似的操作, 我們這裏不提了.

作業2: 熟悉index的操作函數.

pandas基本操作

我們這裏來看看pands具體有哪些基本操作.

重索引

在已經有的索引的基礎上改變索引的操作我們稱為重索引.

data = np.random.randn(3, 3)
frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])
print(frame)
          a         b         c
A -0.545762 -1.089096 -2.164863
B -0.514410 -1.337000  0.434980
C -1.729591 -1.060305 -0.218492
# 將A, B, C重索引C, B, A
frame = frame.reindex(index=[‘C‘, ‘B‘, ‘A‘])
print(frame)
          a         b         c
C -1.729591 -1.060305 -0.218492
B -0.514410 -1.337000  0.434980
A -0.545762 -1.089096 -2.164863
# 同時將列也索引成c, b, a
frame = frame.reindex(index=[‘C‘, ‘B‘, ‘A‘], columns=[‘c‘, ‘b‘, ‘a‘])
print(frame)
          c         b         a
C -0.218492 -1.060305 -1.729591
B  0.434980 -1.337000 -0.514410
A -2.164863 -1.089096 -0.545762
# 加入d 新的索引
frame = frame.reindex(index=[‘C‘, ‘B‘, ‘A‘], columns=[‘c‘, ‘b‘, ‘a‘, ‘d‘])
print(frame)
          c         b         a   d
C -0.218492 -1.060305 -1.729591 NaN
B  0.434980 -1.337000 -0.514410 NaN
A -2.164863 -1.089096 -0.545762 NaN
# 將NaN值設置為0
frame = frame.reindex(index=[‘C‘, ‘B‘, ‘A‘, ‘D‘], columns=[‘c‘, ‘b‘, ‘a‘, ‘d‘], fill_value=0)
print(frame)
          c         b         a    d
C -0.218492 -1.060305 -1.729591  NaN
B  0.434980 -1.337000 -0.514410  NaN
A -2.164863 -1.089096 -0.545762  NaN
D  0.000000  0.000000  0.000000  0.0

註意到, 因為d列已經是NaN裏, 所以不會填充, 填充只發生在reindex的時候.

丟棄一行或者一列

我們可以很方便的丟棄一行或者一列:

frame = frame.drop([‘C‘, ‘B‘])
print(frame)
          c         b         a    d
A -2.164863 -1.089096 -0.545762  NaN
D  0.000000  0.000000  0.000000  0.0
# 丟棄一列
frame = frame.drop([ ‘d‘], axis=1)
print(frame)
          c         b         a
A -2.164863 -1.089096 -0.545762
D  0.000000  0.000000  0.000000
數據選取

我們用[]一般選取的是一列, 當然也有幾種特殊的情況:

data = np.random.randn(3, 3)
frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])
print(frame[:2])
print(‘-----------------------------------------------------------------‘)
print(frame[1:2])
          a         b         c
A  0.542189 -2.005171  1.265211
B -0.145857 -0.054910 -1.277347
-----------------------------------------------------------------
          a        b         c
B -0.145857 -0.05491 -1.277347

frame[:2]並不是大家理解中的倒數兩列, 而是倒數兩行. 也是奇葩, 作者真是腦子有坑.

print(frame > 0.1)
       a      b      c
A   True  False   True
B  False  False  False
C   True   True   True
frame[frame > 0.1] = 0
print(frame)
          a         b         c
A  0.000000 -2.005171  0.000000
B -0.145857 -0.054910 -1.277347
C  0.000000  0.000000  0.000000

如果我們要選取特定一行呢, 我們會用到loc和ix函數.

print(frame.loc[‘A‘])
print("-----------------------------------------------------")
print(frame.loc[‘A‘:‘B‘])
print("-----------------------------------------------------")
print(frame.loc[‘A‘, ‘c‘])
print("-----------------------------------------------------")
print(frame.loc[‘A‘:‘B‘, ‘b‘:‘c‘])
print("-----------------------------------------------------")
print(frame.ix[:2, :2])
print("-----------------------------------------------------")
print(frame.ix[‘A‘:‘B‘, ‘b‘:‘c‘])
print("-----------------------------------------------------")
print(frame.ix[‘B‘, ‘b‘:‘c‘])
a    0.000000
b   -2.005171
c    0.000000
Name: A, dtype: float64
-----------------------------------------------------
          a         b         c
A  0.000000 -2.005171  0.000000
B -0.145857 -0.054910 -1.277347
-----------------------------------------------------
0.0
-----------------------------------------------------
          b         c
A -2.005171  0.000000
B -0.054910 -1.277347
-----------------------------------------------------
          a         b
A  0.000000 -2.005171
B -0.145857 -0.054910
-----------------------------------------------------
          b         c
A -2.005171  0.000000
B -0.054910 -1.277347
-----------------------------------------------------
b   -0.054910
c   -1.277347
Name: B, dtype: float64

** 註意: 對於tag, 我們兩端點是可以取到的. **

數據對齊

我們會來講講數據對齊的問題, Series的對齊我們看過了, DataFrame會在行和列兩個維度上進行對齊.

data = np.random.randn(3, 3)

a = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])
b = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘d‘, ‘c‘, ‘b‘])

print(a)
print("-----------------------------------------------------------------")
print(b)
print("-----------------------------------------------------------------")
print(a + b)
          a         b         c
A  0.148959 -1.091292 -1.371497
B  0.073900  0.339610  0.236825
C  1.130694  0.069362  0.534634
-----------------------------------------------------------------
          d         c         b
A  0.148959 -1.091292 -1.371497
B  0.073900  0.339610  0.236825
C  1.130694  0.069362  0.534634
-----------------------------------------------------------------
    a         b         c   d
A NaN -2.462789 -2.462789 NaN
B NaN  0.576435  0.576435 NaN
C NaN  0.603996  0.603996 NaN
# 設置缺失值
print(a.add(b, fill_value=0))
          a         b         c         d
A  0.148959 -2.462789 -2.462789  0.148959
B  0.073900  0.576435  0.576435  0.073900
C  1.130694  0.603996  0.603996  1.130694

DataFrame和series相加, 這裏會用到numpy裏面提到過的廣播機制. 大家可以去numpy裏面看看:

a = a.add(b, fill_value=0)
print(a)
print("-------------------------------------------------------")
b = a.iloc [0]
print(b)
          a         b         c         d
A  0.148959 -2.462789 -2.462789  0.148959
B  0.073900  0.576435  0.576435  0.073900
C  1.130694  0.603996  0.603996  1.130694
-------------------------------------------------------
a    0.148959
b   -2.462789
c   -2.462789
d    0.148959
Name: A, dtype: float64

我們註意到, a的大小是(3, 4), b的大小是(1,4), tail dimenson是一致的, 可以在其他維度上進行廣播.

print(a - b)
          a         b         c         d
A  0.000000  0.000000  0.000000  0.000000
B -0.075059  3.039224  3.039224 -0.075059
C  0.981735  3.066785  3.066785  0.981735

如果我們要在列上廣播呢, 我們來看下面這個例子:

b = a[‘b‘]
print(b)
print("-------------------------------------------------------")
print(a - b) 
A   -2.462789
B    0.576435
C    0.603996
Name: b, dtype: float64
-------------------------------------------------------
    A   B   C   a   b   c   d
A NaN NaN NaN NaN NaN NaN NaN
B NaN NaN NaN NaN NaN NaN NaN
C NaN NaN NaN NaN NaN NaN NaN

我們發現, 默認是在axis=1(橫向)做減法的, 因為用了廣播機制, 同時缺失值為NaN, 我們就得到了上述的結果, 但是這並不是我們想要的.

我們可以設置需要廣播以及運算的軸

print(a.sub(b, axis=0))
          a    b    c         d
A  2.611748  0.0  0.0  2.611748
B -0.502535  0.0  0.0 -0.502535
C  0.526698  0.0  0.0  0.526698

axis=0表示縱向減法.

pandas函數簡單介紹

這裏我們會簡單介紹一些pandas的一些函數, 我們來看看, DataFrame上可以定義哪些有趣的函數.

apply和applymap函數

首先, 我們來介紹一下apply函數, 這個函數可以把我們自定義的函數用在DataFrame的每一行或者每一列上, 我們來看一個例子.

data = np.random.randn(3, 3)

a = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])

print(a)

print("------------------------------------------------------------------------")

print(a.apply(np.max))
print(a.apply(np.min))
print(a.apply(lambda x: np.max(x) - np.min(x)))

print("------------------------------------------------------------------------")
a.loc[‘max‘] = a.apply(np.max)
a.loc[‘min‘] = a.apply(np.min)
a.loc[‘margin‘] = a.apply(lambda x: np.max(x) - np.min(x))
print(a)
          a         b         c
A -0.137231 -2.008153 -0.766172
B  0.473756 -0.071421  1.549933
C  1.057641  0.375983 -0.647798
------------------------------------------------------------------------
a    1.057641
b    0.375983
c    1.549933
dtype: float64
a   -0.137231
b   -2.008153
c   -0.766172
dtype: float64
a    1.194872
b    2.384135
c    2.316105
dtype: float64
------------------------------------------------------------------------
               a         b         c
A      -0.137231 -2.008153 -0.766172
B       0.473756 -0.071421  1.549933
C       1.057641  0.375983 -0.647798
max     1.057641  0.375983  1.549933
min    -0.137231 -2.008153 -0.766172
margin  1.194872  2.384135  2.316105

a[‘max‘] = a.apply(np.max, axis=1)
a[‘min‘] = a.apply(np.min, axis=1)
a[‘margin‘] = a.apply(lambda x: np.max(x) - np.min(x), axis=1)
print(a)
               a         b         c       max       min    margin
A      -0.137231 -2.008153 -0.766172 -0.137231 -2.008153  1.870922
B       0.473756 -0.071421  1.549933  1.549933 -0.071421  1.621354
C       1.057641  0.375983 -0.647798  1.057641 -0.647798  1.705439
max     1.057641  0.375983  1.549933  1.549933  0.375983  1.173950
min    -0.137231 -2.008153 -0.766172 -0.137231 -2.008153  1.870922
margin  1.194872  2.384135  2.316105  2.384135  1.194872  1.189263

我們對軸要牢記, 0是在每一列上做, 1是在每一行上做. 這個例子希望大家好好理解.

我們如果想元素級的調用我們的函數, 我們可以用函數applymap函數:

print(a)
               a         b         c       max       min    margin
A      -0.137231 -2.008153 -0.766172 -0.137231 -2.008153  1.870922
B       0.473756 -0.071421  1.549933  1.549933 -0.071421  1.621354
C       1.057641  0.375983 -0.647798  1.057641 -0.647798  1.705439
max     1.057641  0.375983  1.549933  1.549933  0.375983  1.173950
min    -0.137231 -2.008153 -0.766172 -0.137231 -2.008153  1.870922
margin  1.194872  2.384135  2.316105  2.384135  1.194872  1.189263

如果我們想要把小數保留兩位, 怎麽搞呢, 我們可以看看在python中怎麽保留兩位小數的

x = 0.123456
print(%.2f %  x)
0.12

我們可以這麽來

print(a)

b = a.copy()


b = b.applymap(lambda x: float(%.2f %  x))
print("---------------------------------------------------------------------------------------------------------")
print(b)
               a         b         c       max       min    margin
A      -0.137231 -2.008153 -0.766172 -0.137231 -2.008153  1.870922
B       0.473756 -0.071421  1.549933  1.549933 -0.071421  1.621354
C       1.057641  0.375983 -0.647798  1.057641 -0.647798  1.705439
max     1.057641  0.375983  1.549933  1.549933  0.375983  1.173950
min    -0.137231 -2.008153 -0.766172 -0.137231 -2.008153  1.870922
margin  1.194872  2.384135  2.316105  2.384135  1.194872  1.189263
---------------------------------------------------------------------------------------------------------
           a     b     c   max   min  margin
A      -0.14 -2.01 -0.77 -0.14 -2.01    1.87
B       0.47 -0.07  1.55  1.55 -0.07    1.62
C       1.06  0.38 -0.65  1.06 -0.65    1.71
max     1.06  0.38  1.55  1.55  0.38    1.17
min    -0.14 -2.01 -0.77 -0.14 -2.01    1.87
margin  1.19  2.38  2.32  2.38  1.19    1.19

** 作業3: 對整個表格的浮點數進行四舍五入. **

排序函數

排序一直是一個很重要的課題,

a = Series(range(4), index=[‘a‘, ‘c‘, ‘b‘, ‘d‘])
print(a)
print("--------------------------------")
print(a.sort_index())
print("--------------------------------")
print(a.sort_index(ascending=False))
a    0
c    1
b    2
d    3
dtype: int32
--------------------------------
a    0
b    2
c    1
d    3
dtype: int32
--------------------------------
d    3
c    1
b    2
a    0
dtype: int32

我們可以發現, sort_index這個函數在Series上是按照index來排序的.

對於DataFrame來說, 我們可以按照某一列來排序, 用sort_values函數.

data = np.random.randn(3, 3)

a = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])

print(a)

print(‘--------------------------------------------------------------------‘)

print(a.sort_values(by=‘b‘))
          a         b         c
A -0.247148  0.117866  0.485004
B -1.303519 -1.073757 -1.265169
C  0.647247  1.171883 -0.301084
--------------------------------------------------------------------
          a         b         c
B -1.303519 -1.073757 -1.265169
A -0.247148  0.117866  0.485004
C  0.647247  1.171883 -0.301084

另外, 我們要註意的是, 這個索引是可以用重復的, 我們可以來看看:

data = np.random.randn(3, 3)

a = DataFrame(data, index=[‘A‘, ‘B‘, ‘B‘], columns=[‘a‘, ‘b‘, ‘c‘])

print(a.loc[‘B‘])
          a         b         c
B -0.364841  0.765296  1.869450
B  0.624467  0.929586  0.673822
匯總計算函數

把一串數字經過計算變成一個數字, 這樣的操作, 我們稱之為匯總. 我們有很多的函數可以幫助我們完成匯總的操作,

比如mean, sum, media等等, 下面我們來看看這些例子.

data = {‘a‘: list(range(1, 4)), ‘b‘: list(range(1, 4)), ‘c‘: list(range(1, 4))}

frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘])

print(frame)

print(‘--------------------------------------------------------------------------‘)

# 把每一行加起來求和
print(frame.sum())

print(‘--------------------------------------------------------------------------‘)

# 把每一列加起來求和
print(frame.sum(axis=1))

print(‘--------------------------------------------------------------------------‘)

frame[‘sum‘] = frame.sum(axis=1)
frame.loc[‘sum‘] = frame.sum()
print(frame)

print(‘--------------------------------------------------------------------------‘)

frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘])
frame[‘sum‘] = frame.median(axis=1)
frame.loc[‘sum‘] = frame.median()
print(frame)
   a  b  c
A  1  1  1
B  2  2  2
C  3  3  3
--------------------------------------------------------------------------
a    6
b    6
c    6
dtype: int64
--------------------------------------------------------------------------
A    3
B    6
C    9
dtype: int64
--------------------------------------------------------------------------
     a  b  c  sum
A    1  1  1    3
B    2  2  2    6
C    3  3  3    9
sum  6  6  6   18
--------------------------------------------------------------------------
       a    b    c  sum
A    1.0  1.0  1.0  1.0
B    2.0  2.0  2.0  2.0
C    3.0  3.0  3.0  3.0
sum  2.0  2.0  2.0  2.0

在這裏我們要單獨講一講這個NaN的值的處理, NaN可以選擇跳過, 也可以不跳過, 我們來看看:

data = {‘a‘: list(range(1, 4)), ‘b‘: list(range(1, 4)), ‘c‘: list(range(1, 4))}

frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘])

frame[‘a‘][‘A‘] = np.nan

print(frame)

print(frame.sum())
     a  b  c
A  NaN  1  1
B  2.0  2  2
C  3.0  3  3
a    5.0
b    6.0
c    6.0
dtype: float64

我們發現, 這個NaN被略過去了, 我們也可以選擇不略過去.

print(frame.sum(skipna=False))
a    NaN
b    6.0
c    6.0
dtype: float64

我們這裏要提兩個數學概念, 協方差和相關系數, 我們來看看這兩個的定義:

協方差:

\[ Cov(X, Y) = E[(X - E[X])(Y - E[Y])] = \frac{1}{n^2}\sum_{i=1, j=1}^n(X_{i}Y_{j}-\bar{X}\bar{Y})\]

這是我們協方差的定義, 我們可以看看相關系數的定義:

\[ \rho = \frac{ Cov(X, Y)}{\sigma_{X}\sigma_{Y}} \]

這樣, 我們就把這兩個概念用公式來表達出來了, 我們來看看具體怎麽計算.

data = np.random.randn(3, 3)

a = DataFrame(data, index=[‘A‘, ‘B‘, ‘B‘], columns=[‘a‘, ‘b‘, ‘c‘])

print(a.corr())

print(a.cov())
          a         b         c
a  1.000000 -0.804968 -0.630290
b -0.804968  1.000000  0.046734
c -0.630290  0.046734  1.000000
          a         b         c
a  0.281901 -0.189824 -0.155039
b -0.189824  0.197264  0.009616
c -0.155039  0.009616  0.214637

作業4: 了解一下相關系數和協方差的數學意義.https://www.zhihu.com/question/20852004

另外, 我們還有一個非常實用的函數, pd.value_counts

data = {‘a‘: list(range(1, 4)), ‘b‘: list(range(1, 4)), ‘c‘: list(range(1, 4))}

frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘])

print(frame.apply(pd.value_counts))
   a  b  c
3  1  1  1
2  1  1  1
1  1  1  1

a, b c三列中, 1, 2, 3各出現1次.

print(frame.apply(pd.value_counts, axis=1).fillna(0))
     1    2    3
A  3.0  0.0  0.0
B  0.0  3.0  0.0
C  0.0  0.0  3.0

A行1出現3次, B行2出現3次, C行3出現3次

缺失值的處理

我們這裏要談一個非常重要的概念, 缺失值的處理, 大致上看, 關於缺失值, 可以用丟棄和填充兩種方法.

因為我們拿到的數據, 不可能所有都是完整的, 所以我們需要對這些缺失值進行處理

首先, 我們來看看怎麽判斷有缺失值, 我們可以用isnull來判斷:

data = np.random.randn(3, 3)

a = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘], columns=[‘a‘, ‘b‘, ‘c‘])

a[‘a‘][‘A‘] = None

a[‘b‘][‘C‘] = None

print(a)
          a         b         c
A       NaN -1.577756  0.572846
B -1.045493 -0.852665 -0.374464
C -1.419523       NaN  0.267812
print(a.isnull())
       a      b      c
A   True  False  False
B  False  False  False
C  False   True  False

進一步我們看看每一列都有多少NaN值.

print(a.isnull().sum())
print(a.isnull().sum(axis=1))
a    1
b    1
c    0
dtype: int64
A    1
B    0
C    1
dtype: int64

我們可以過濾掉所有的有NaN的行或者列, 我們來看看:

print(a.dropna())

print("-------------------------------------")

print(a.dropna(axis=1))

print("-------------------------------------")

print(a.dropna(how=‘all‘))
          a         b         c
B -1.045493 -0.852665 -0.374464
-------------------------------------
          c
A  0.572846
B -0.374464
C  0.267812
-------------------------------------
          a         b         c
A       NaN -1.577756  0.572846
B -1.045493 -0.852665 -0.374464
C -1.419523       NaN  0.267812

我們來看看怎麽對於缺失值來進行填充, fillna我們在前面已經看過一個具體的例子了, 我們來看看別的例子:

print(a.fillna({‘a‘:0, ‘b‘:1})) # 這是用不同值對不同列進行na的填充

print(a.fillna(Series({‘a‘:0, ‘b‘:1})))
          a         b         c
A  0.000000 -1.577756  0.572846
B -1.045493 -0.852665 -0.374464
C -1.419523  1.000000  0.267812
          a         b         c
A  0.000000 -1.577756  0.572846
B -1.045493 -0.852665 -0.374464
C -1.419523  1.000000  0.267812

作業5: 熟悉一下fillna的method參數已經他們的用法.

下面我們來看看怎麽用各行的均值來填充缺失值.

print(a.fillna(a.mean()))
          a         b         c
A -1.232508 -1.577756  0.572846
B -1.045493 -0.852665 -0.374464
C -1.419523 -1.215210  0.267812

註意到, 這個均值是沿著axis=0, 也就是把每行匯總計算得到的.

整數索引

我們這裏要談一個很有意思的問題, 來看看這麽個例子:

data = {‘a‘: list(range(1, 4)), ‘b‘: list(range(1, 4)), ‘c‘: list(range(1, 4))}

frame = DataFrame(data, index=[‘A‘, ‘B‘, ‘C‘])

print(frame.loc[‘A‘:‘B‘])
print("--------------------------------------------")
print(frame.iloc[0: 1, 0:1])
print("--------------------------------------------")
print(frame.loc[‘A‘:‘B‘, ‘a‘:‘b‘])
   a  b  c
A  1  1  1
B  2  2  2
--------------------------------------------
   a
A  1
--------------------------------------------
   a  b
A  1  1
B  2  2

我們發現, 對於標簽, 我們兩個端點都是可以取到的, 但是對於數字索引, 是前閉後開.

但是, 如果是對於縮索引, 本身就是整數, 會發生什麽呢?

frame = DataFrame(data, index=[1, 2, 3])

print(frame)
   a  b  c
1  1  1  1
2  2  2  2
3  3  3  3
print(frame.iloc[0: 1])
   a  b  c
1  1  1  1
print(frame.loc[1:2])
   a  b  c
1  1  1  1
2  2  2  2

我們發現, 這個loc函數, 還是保留了標簽, 把這個整數當做標簽來處理, 兩個端點都是閉的, 而iloc是當做整數索引來處理, 前閉後開.

數據分析之pandas教程-----概念篇