數據分析之pandas教程-----概念篇
目錄
- 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 整數索引
- 1.1 pandas數據結構剖析
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教程-----概念篇