11.Pandas的基本使用方法

Pandas基本使用方法

Pandas有三个基本的数据结构:Series、DataFrame和Index

Pandas的Series对象是一个带索引数据构成的一维数组

可以用数组创建Series对象:

import pandas as pd
import numpy as np

data = pd.Series([0.25, 0.5, 0.75, 1.0])
data
0    0.25
1    0.50
2    0.75
3    1.00
dtype: float64

从上面的结果中可以看出,Series对象将一维数组数据和一组索引绑定在一起,可以通过values属性和index属性获取数据,values属性返回的结果与Numpy数组类似:

print(data.values)
type(data.values)
[0.25 0.5  0.75 1.  ]
numpy.ndarray

index属性返回的是一个类型为pd.Index的类数组对象

print(data.index)
print(type(data.index))
RangeIndex(start=0, stop=4, step=1)
<class 'pandas.core.indexes.range.RangeIndex'>

和Numpy数组一样,数据可以通过Python中括号索引标签获取

print(data[1])
print(data[1:3])
0.5
1    0.50
2    0.75
dtype: float64

Pandas的Series与Numpy的一维数组的本质差别是Series对象用一种显示定义的索引与数值关联,显示索引定义可以是任意想要的类型

data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a','b','c','d'])
data
a    0.25
b    0.50
c    0.75
d    1.00
dtype: float64

获取数值的方式与之前一样:

data['b']
0.5

也可以使用不连续或者不按顺序的索引:

data = pd.Series([0.25, 0.5, 0.75, 1.0], index=[2,5,3,7])
data
2    0.25
5    0.50
3    0.75
7    1.00
dtype: float64
data[5]
0.5

Series也是一种特殊类型的字典,操作起来比python的字典更加高效。
可以直接使用Python的字典创建一个Series对象,让Series对象比字典更加清晰:

population_dict = {'California':38332521,
                  'Texas':26448193,
                  'New York':19651127,
                  'Florida':19552860,
                  'Illinois':12882135}
population = pd.Series(population_dict)
population
California    38332521
Texas         26448193
New York      19651127
Florida       19552860
Illinois      12882135
dtype: int64
population['California']
38332521

和字典不用,Series对象还支持数组类型的操作,比如切片:左右都闭

population['California':'Florida']
California    38332521
Texas         26448193
New York      19651127
Florida       19552860
dtype: int64

创建Series对象的集中方式:index是可选参数,data可以是列表或者numpy数组,或者是字典,也可以是标量,创建Series对象时会重复填充到每个索引上。

pd.Series(5,index=[100,200,300])
100    5
200    5
300    5
dtype: int64

data还可以是一个字典,可以通过显示指定索引筛选需要的结果

pd.Series({2:'a', 1:'b', 3:'c'},index=[2,3])
2    a
3    c
dtype: object

Pandas的DataFrame对象是一个二维的带有索引的数组。

可以用字典来创建DateFrame对象:

area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297,
'Florida': 170312, 'Illinois': 149995}
area = pd.Series(area_dict)
area
California    423967
Texas         695662
New York      141297
Florida       170312
Illinois      149995
dtype: int64
states  = pd.DataFrame({'population':population,'area':area})
states
populationarea
California38332521423967
Texas26448193695662
New York19651127141297
Florida19552860170312
Illinois12882135149995

和Series一样,DataFrame也有一个index属性可以获取索引标签。

states.index
Index(['California', 'Texas', 'New York', 'Florida', 'Illinois'], dtype='object')

另外,DataFrame还有一个columns属性,存放的是列标签的index

states.columns
Index(['population', 'area'], dtype='object')

DataFrame也是一个特殊的字典,DataFrame是一列映射一个Series数据,这里需要注意的是,在 NumPy 的二维数组里, data[0]返回第一行;而在 DataFrame 中,data[‘col0’]返回第一列。

states['area']
California    423967
Texas         695662
New York      141297
Florida       170312
Illinois      149995
Name: area, dtype: int64

创建DataFrame对象:
(1)通过单个Series对象创建

pd.DataFrame(population,columns=['population'])
population
California38332521
Texas26448193
New York19651127
Florida19552860
Illinois12882135

(2)通过字典列表创建,任何元素是字典的列表都可以变成 DataFrame 。用一个简单的列表
综合来创建一些数据:

data = [{'a':i, 'b':2*i} for i in range(3)]
data
[{'a': 0, 'b': 0}, {'a': 1, 'b': 2}, {'a': 2, 'b': 4}]
pd.DataFrame(data)
ab
000
112
224

(3)通过Series对象创建DataFrame

pd.DataFrame({'population':population, 'area':area})
populationarea
California38332521423967
Texas26448193695662
New York19651127141297
Florida19552860170312
Illinois12882135149995

(4)通过numpy二维数组创建。假如有一个二维数组,就可以创建一个可以指定行列索引值的 DataFrame 。如果不指定行列索引值,那么行列默认都是整数索引值:

pd.DataFrame(np.random.rand(3,2))
01
00.5986020.090202
10.0243230.922540
20.4122610.443546
pd.DataFrame(np.random.rand(3,2), index=['a','b','c'],columns=['foo','bar'])
foobar
a0.8431810.250314
b0.7687020.204884
c0.3601920.082351

(5)通过numpy的结构化数组创建

A = np.zeros(3,dtype=[('A','i8'),('B','f8')])
A
array([(0, 0.), (0, 0.), (0, 0.)], dtype=[('A', '<i8'), ('B', '<f8')])
pd.DataFrame(A)
AB
000.0
100.0
200.0

Pandas的Index对象

可以将Index对象看做一个不可变数组:不能改变数值

ind = pd.Index([2,3,5,8,9])
ind
Int64Index([2, 3, 5, 8, 9], dtype='int64')
ind[1]
3
ind[::3]
Int64Index([2, 8], dtype='int64')

Index对象还有很多与numpy数组类似的属性

print(ind.shape, ind.size, ind.ndim, ind.dtype)
(5,) 5 1 int64

将Index看做有序集合

indA = pd.Index([1,3,5,7,9])
indB = pd.Index([2,3,5,7,8])
indA & indB
Int64Index([3, 5, 7], dtype='int64')
indA | indB
Int64Index([1, 2, 3, 5, 7, 8, 9], dtype='int64')
indA ^ indB
Int64Index([1, 2, 8, 9], dtype='int64')

Pandas的数据选取与选择

(1)Series的数据选择方法:可以将Series对象看做一个字典

data = pd.Series([0.25, 0.5, 0.75, 1.0], index=list('abcd'))
data
a    0.25
b    0.50
c    0.75
d    1.00
dtype: float64
data['b']
0.5

还可以通过Python字典的表达式和方法来检测key和value

'a' in data
True
data.keys()
Index(['a', 'b', 'c', 'd'], dtype='object')
list(data.items())
[('a', 0.25), ('b', 0.5), ('c', 0.75), ('d', 1.0)]

Series对象还可以用字典语法调整数据,可以 通过增加新的索引扩展Series

data['e'] = 1.5
data
a    0.25
b    0.50
c    0.75
d    1.00
e    1.50
dtype: float64

(2)可以将Series看做一个数组:索引、掩码、花哨索引等操作

# 切片
data['a':'c']
a    0.25
b    0.50
c    0.75
dtype: float64
# 将隐式整数作为切片
data[0:2]
a    0.25
b    0.50
dtype: float64
# 掩码
data[(data>0.3)&(data<0.8)]
b    0.50
c    0.75
dtype: float64
# 花哨的索引
data[['a','c']]
a    0.25
c    0.75
dtype: float64

需 要 注 意 的 是, 当 使 用 显 式 索 引( 即data[‘a’:‘c’])作切片时,结果包含最后一个索引;而当使用隐式索引(即 data[0:2] )作切片时,结果不包含最后一个索引。

(3)索引器:loc、iloc和ix
这些切片和取值的习惯用法经常会造成混乱。例如,如果你的 Series 是显式整数索引,那么
data[1] 这样的取值操作会使用显式索引,而 data[1:3] 这样的切片操作却会使用隐式索引。

data = pd.Series(['a','b','c'],index=[1,3,5])
data
1    a
3    b
5    c
dtype: object
data[1:3]
3    b
5    c
dtype: object

由于整数索引很容易造成混淆,所以Pandas提供了一些索引器属性来作为取值的方法。他们不是Series对象的函数方法,而是暴露切片接口的属性,
第一种是loc属性,表示取值和切片都是显示的

data.loc[1]
'a'
data.loc[1:3]
1    a
3    b
dtype: object

第二种是iloc属性,表示取值和切片都是隐示索引

data.iloc[0]
'a'
data.iloc[1:3]
3    b
5    c
dtype: object

第三种是ix属性,是前两种的混合形式,用于DataFrame
DataFrame的数据选择方法

(1)将DataFrame看做字典

area = pd.Series({'California': 423967, 'Texas': 695662,
                'New York': 141297, 'Florida': 170312,
                'Illinois': 149995})
pop = pd.Series({'California': 38332521, 'Texas': 26448193,
                'New York': 19651127, 'Florida': 19552860,
                'Illinois': 12882135})
data = pd.DataFrame({'area':area, 'pop':pop})
data
areapop
California42396738332521
Texas69566226448193
New York14129719651127
Florida17031219552860
Illinois14999512882135

两个 Series 分别构成 DataFrame 的一列,可以通过对列名进行字典形式(dictionary-style)的取值获取数据:

data['area']
California    423967
Texas         695662
New York      141297
Florida       170312
Illinois      149995
Name: area, dtype: int64

也可以通过属性的方式:

data.area
California    423967
Texas         695662
New York      141297
Florida       170312
Illinois      149995
Name: area, dtype: int64

和前面介绍的 Series 对象一样,还可以用字典形式的语法调整对象,如果要增加一列可以
这样做:

data['denstiy'] = data['pop']/data['area']
data
areapopdenstiy
California4239673833252190.413926
Texas6956622644819338.018740
New York14129719651127139.076746
Florida17031219552860114.806121
Illinois1499951288213585.883763

(2)将DataFrame看做二维数组
使用values直接查看数据

data.values
array([[4.23967000e+05, 3.83325210e+07, 9.04139261e+01],
       [6.95662000e+05, 2.64481930e+07, 3.80187404e+01],
       [1.41297000e+05, 1.96511270e+07, 1.39076746e+02],
       [1.70312000e+05, 1.95528600e+07, 1.14806121e+02],
       [1.49995000e+05, 1.28821350e+07, 8.58837628e+01]])
data.T
CaliforniaTexasNew YorkFloridaIllinois
area4.239670e+056.956620e+051.412970e+051.703120e+051.499950e+05
pop3.833252e+072.644819e+071.965113e+071.955286e+071.288214e+07
denstiy9.041393e+013.801874e+011.390767e+021.148061e+028.588376e+01
data.values[0]
array([4.23967000e+05, 3.83325210e+07, 9.04139261e+01])
data['area']
California    423967
Texas         695662
New York      141297
Florida       170312
Illinois      149995
Name: area, dtype: int64
data.iloc[:3,:2]
areapop
California42396738332521
Texas69566226448193
New York14129719651127

使用 ix 索引器可以实现一种混合效果:容易混淆

# data.ix[:3,:'pop']

掩码操作

data.loc[data.denstiy>100]
areapopdenstiy
New York14129719651127139.076746
Florida17031219552860114.806121
data.loc[data.denstiy>100,['pop','density']]
/home/ldy/.pyenv/versions/3.6.8/lib/python3.6/site-packages/pandas/core/indexing.py:1418: FutureWarning: 
Passing list-likes to .loc or [] with any missing label will raise
KeyError in the future, you can use .reindex() as an alternative.

See the documentation here:
https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#deprecate-loc-reindex-listlike
  return self._getitem_tuple(key)
popdensity
New York19651127NaN
Florida19552860NaN

Pandas数值运算方法

(1)通用函数 : 保留索引

rng = np.random.RandomState(42)
ser = pd.Series(rng.randint(0, 10, 4))
ser
0    6
1    3
2    7
3    4
dtype: int64
df = pd.DataFrame(rng.randint(0, 10, (3, 4)),
columns=['A', 'B', 'C', 'D'])
df
ABCD
06926
17437
27254
np.exp(ser)
0     403.428793
1      20.085537
2    1096.633158
3      54.598150
dtype: float64
np.sin(df * np.pi / 4)
ABCD
0-1.0000007.071068e-011.000000-1.000000e+00
1-0.7071071.224647e-160.707107-7.071068e-01
2-0.7071071.000000e+00-0.7071071.224647e-16

(2)通用函数 : 索引对齐
当在两个 Series 或 DataFrame 对象上进行二元计算时,Pandas 会在计算过程中对齐两个对象的索引。

area = pd.Series({'Alaska': 1723337, 'Texas': 695662,
                'California': 423967}, name='area')
population = pd.Series({'California': 38332521, 'Texas': 26448193,
                        'New York': 19651127}, name='population')
population / area
Alaska              NaN
California    90.413926
New York            NaN
Texas         38.018740
dtype: float64

结果数组的索引是两个输入数组索引的并集。我们也可以用 Python 标准库的集合运算法则
来获得这个索引:

area.index | population.index
Index(['Alaska', 'California', 'New York', 'Texas'], dtype='object')

对于缺失位置的数据,Pandas 会用 NaN 填充,表示“此处无数”。这是 Pandas 表示缺失值
的方法.

A = pd.Series([2, 4, 6], index=[0, 1, 2])
B = pd.Series([1, 3, 5], index=[1, 2, 3])
A + B
0    NaN
1    5.0
2    9.0
3    NaN
dtype: float64

如果用 NaN 值不是我们想要的结果,那么可以用适当的对象方法代替运算符。例如,
A.add(B) 等价于 A + B ,也可以设置参数自定义 A 或 B 缺失的数据:

A.add(B, fill_value=0)
0    2.0
1    5.0
2    9.0
3    5.0
dtype: float64

DataFrame索引对齐

A = pd.DataFrame(rng.randint(0, 20, (2, 2)),columns=list('AB'))
A
AB
0111
151
B = pd.DataFrame(rng.randint(0, 10, (3, 3)),columns=list('BAC'))
B
BAC
0409
1580
2926
A+B
ABC
01.015.0NaN
113.06.0NaN
2NaNNaNNaN

你会发现,两个对象的行列索引可以是不同顺序的,结果的索引会自动按顺序排列。在
Series 中,我们可以通过运算符方法的 fill_value 参数自定义缺失值。这里,我们将用 A
中所有值的均值来填充缺失值(计算 A 的均值需要用 stack 将二维数组压缩成一维数组):

fill = A.stack().mean()
A.add(B, fill_value=fill)
ABC
01.015.013.5
113.06.04.5
26.513.510.5

(3)通用函数 : DataFrame 与 Series 的运算

A = rng.randint(10, size=(3, 4))
A
array([[3, 8, 2, 4],
       [2, 6, 4, 8],
       [6, 1, 3, 8]])
A - A[0]
array([[ 0,  0,  0,  0],
       [-1, -2,  2,  4],
       [ 3, -7,  1,  4]])

根据 NumPy 的广播规则,让二维数组减自身的一行数据会按行计算。在 Pandas 里默认也是按行运算的:

df = pd.DataFrame(A, columns=list('QRST'))
df - df.iloc[0]
QRST
00000
1-1-224
23-714
df.subtract(df['R'], axis=0)
QRST
0-50-6-4
1-40-22
25027
halfrow = df.iloc[0, ::2]
halfrow
Q    3
S    2
Name: 0, dtype: int64
df - halfrow
QRST
00.0NaN0.0NaN
1-1.0NaN2.0NaN
23.0NaN1.0NaN

这些行列索引的保留与对齐方法说明 Pandas 在运算时会一直保存这些数据内容,从而避免
在处理数据类型有差异和 / 或维度不一致的 NumPy 数组时可能遇到的问题。

Pandas处理缺省值

(1) None :Python 对象类型的缺失值

vals1 = np.array([1,None,3,4])
vals1
array([1, None, 3, 4], dtype=object)

这里 dtype=object 表示 NumPy 认为由于这个数组是 Python 对象构成的,因此将其类型
判断为 object 。虽然这种类型在某些情景中非常有用,对数据的任何操作最终都会在
Python 层面完成,但是在进行常见的快速操作时,这种类型比其他原生类型数组要消耗
更多的资源:

for dtype in ['object', 'int']:
    print("dtype =", dtype)
    %timeit np.arange(1E6, dtype=dtype).sum()
    print()
dtype = object
44.2 ms ± 553 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

dtype = int
1.27 ms ± 81.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

使用 Python 对象构成的数组就意味着如果你对一个包含 None 的数组进行累计操作,如
sum() 或者 min() ,那么通常会出现类型错误:

# vals1.sum()

(2) NaN : 数值类型的缺失值,另一种缺失值的标签是 NaN (全称 Not a Number,不是一个数字),是一种按照 IEEE 浮点
数标准设计、在任何系统中都兼容的特殊浮点数:

vals2 = np.array([1,np.nan,3,4])
vals2.dtype
dtype('float64')

无论和 NaN 进行何种操作,最终结果都是 NaN :

1 + np.nan
nan
3 * np.nan
nan

虽然这些累计操作的结果定义是合理的(即不会抛出异常),但是并非总是有效的:

vals2.sum(),vals2.min(), vals2.max()
(nan, nan, nan)

NumPy 也提供了一些特殊的累计函数,它们可以忽略缺失值的影响:

np.nansum(vals2),np.nanmin(vals2),np.nanmax(vals2)
(8.0, 1.0, 4.0)

谨记, NaN 是一种特殊的浮点数,不是整数、字符串以及其他数据类型。

(3)Pandas中NaN与None的差异

虽然 NaN 与 None 各有各的用处,但是 Pandas 把它们看成是可以等价交换的,在适当的时
候会将两者进行替换:

pd.Series([1,np.nan,2,None])
0    1.0
1    NaN
2    2.0
3    NaN
dtype: float64

Pandas 会将没有标签值的数据类型自动转换为 NaN 。例如,当我们将整型数组中的一个值设
置为 np.nan 时,这个值就会强制转换成浮点数缺失值 NaN 。

x = pd.Series(range(2))
x
0    0
1    1
dtype: int64
x[0]=None
x
0    NaN
1    1.0
dtype: float64

请注意,除了将整型数组的缺失值强制转换为浮点数,Pandas 还会自动将 None 转换为
NaN 。

处理缺省值

我们已经知道,Pandas 基本上把 None 和 NaN 看成是可以等价交换的缺失值形式。为了完成
这种交换过程,Pandas 提供了一些方法来发现、剔除、替换数据结构中的缺失值,主要包
括以下几种:

isnull():创建一个布尔类型的掩码标签缺失值。

notnull():与 isnull() 操作相反。

dropna():返回一个剔除缺失值的数据。

fillna():返回一个填充了缺失值的数据副本。

(1)发现缺省值:

data = pd.Series([1,np.nan,'hello',None])
data
0        1
1      NaN
2    hello
3     None
dtype: object
data.isnull()
0    False
1     True
2    False
3     True
dtype: bool

布尔类型掩码数组可以直接作为 Series 或 DataFrame 的索引使用:

data[data.notnull()]
0        1
2    hello
dtype: object

在 Series 里使用的 isnull() 和 notnull() 同样适用于 DataFrame ,产生的结果同样是布尔
类型。

(2)剔除缺省值

除了前面介绍的掩码方法,还有两种很好用的缺失值处理方法,分别是 dropna() (剔除缺
失值)和 fillna() (填充缺失值)。在 Series 上使用这些方法非常简单:

data.dropna()
0        1
2    hello
dtype: object

而在 DataFrame 上使用它们时需要设置一些参数,例如下面的 DataFrame :

df = pd.DataFrame([[1,np.nan, 2],
                   [2, 3, 5],
                   [np.nan, 4,6]])
df
012
01.0NaN2
12.03.05
2NaN4.06

我们没法从 DataFrame 中单独剔除一个值,要么是剔除缺失值所在的整行,要么是整列。
根据实际需求,有时你需要剔除整行,有时可能是整列, DataFrame 中的 dropna() 会有一
些参数可以配置。
默认情况下, dropna() 会剔除任何包含缺失值的整行数据:

df.dropna()
012
12.03.05

可以设置按不同的坐标轴剔除缺失值,比如 axis=1 (或 axis=‘columns’ )会剔除任何包含
缺失值的整列数据:

df.dropna(axis='columns')
2
02
15
26

默认设置是 how=‘any’ ,也就是说只要有缺失值就剔除整行或整列(通过 axis 设置坐标
轴)。你还可以设置 how=‘all’ ,这样就只会剔除全部是缺失值的行或列了:

df[3] = np.nan
df
0123
01.0NaN2NaN
12.03.05NaN
2NaN4.06NaN
df.dropna(axis='columns',how='all')
012
01.0NaN2
12.03.05
2NaN4.06

还可以通过 thresh 参数设置行或列中非缺失值的最小数量,从而实现更加个性化的配置:

df.dropna(axis='rows',thresh=3)
0123
12.03.05NaN

第 1 行与第 3 行被剔除了,因为它们只包含两个非缺失值。

(3)填充缺省值

有时候你可能并不想移除缺失值,而是想把它们替换成有效的数值。有效的值可能是像
0、1、2 那样单独的值,也可能是经过填充(imputation)或转换(interpolation)得到的。
虽然你可以通过 isnull() 方法建立掩码来填充缺失值,但是 Pandas 为此专门提供了一个
fillna() 方法,它将返回填充了缺失值后的数组副本。

data = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))
data
a    1.0
b    NaN
c    2.0
d    NaN
e    3.0
dtype: float64

我们将用一个单独的值来填充缺失值,例如用 0:

data.fillna(0)
a    1.0
b    0.0
c    2.0
d    0.0
e    3.0
dtype: float64

可以用缺失值前面的有效值来从前往后填充(forward-fill):

data.fillna(method='ffill')
a    1.0
b    1.0
c    2.0
d    2.0
e    3.0
dtype: float64

也可以用缺失值后面的有效值来从后往前填充(back-fill):

data.fillna(method='bfill')
a    1.0
b    2.0
c    2.0
d    3.0
e    3.0
dtype: float64

DataFrame 的操作方法与 Series 类似,只是在填充时需要设置坐标轴参数 axis :

df
0123
01.0NaN2NaN
12.03.05NaN
2NaN4.06NaN
df.fillna(method='ffill',axis='columns')
0123
01.01.02.02.0
12.03.05.05.0
2NaN4.06.06.0

需要注意的是,假如在从前往后填充时,需要填充的缺失值前面没有值,那么它就仍然是
缺失值。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值