利用python进行数据分析——pandas基础

这里主要是对《利用python进行数据分析》的学习,原书的电子版地址为:

https://github.com/iamseancheney/python_for_data_analysis_2nd_chinese_version
不知道这个项目是不是译者或者是什么好心人整理的。

数据结构

pandas是基于numpy数组构建的,但pandas更是专门为了处理表格和混杂数据设计的,而numpy则更适合处理同质数据。

pandas中的数据结构主要有两种:

  • series:类似于一维数组
  • dataframe:类似于多维数组
import pandas as pd
from pandas import Series, DataFrame

 Series

之前提到series类似于一维数组,不同的是相较于numpy中的数组,series中的还有与数据相关的标签,也就是索引:

a = pd.Series(range(5))
print(a, a.index, a.values,sep="\n\n")

结果为: 

0    0
1    1
2    2
3    3
4    4
dtype: int64

RangeIndex(start=0, stop=5, step=1)

[0 1 2 3 4]

可以看出,series类型是由index和value组合而成的,类似于numpy中的dtype,pandas中的index也是能够指定的: 

a = pd.Series(range(5), index=["one","two","three","four","five"])
print(a, a.index, a.values,sep="\n\n")

结果为: 

one      0
two      1
three    2
four     3
five     4
dtype: int64

Index(['one', 'two', 'three', 'four', 'five'], dtype='object')

[0 1 2 3 4]

可见,value部分的值没变,只是index的部分更改了。而之前由于指定index部分,因此默认是由递增的整数型数值代替的。

 因此对于数据的访问,可以通过多种形式访问:

a = pd.Series(range(5), index=["one","two","three","four","five"])
print(a[1],a[0:2],a["two"],a[["two","one","five"]],a[a>2],sep="\n\n")

结果为: 

1

one    0
two    1
dtype: int64

1

two     1
one     0
five    4
dtype: int64

four    3
five    4
dtype: int64

即可以通过下标,切片,index,index列表,布尔值数组的形式进行索引访问,这些基本和numpy中数组的访问形式是一致的。

同样series的算术运算也是和numpy一致的,另外因为index是pandas中数据的重要组成部分,因此针对index的逻辑判断也是合理的。

a = pd.Series(range(5), index=["one","two","three","four","five"])
print(a ** 2, "one" in a, sep="\n\n")

结果为: 

one       0
two       1
three     4
four      9
five     16
dtype: int64

True

上面对索引的逻辑判断和字典的键值判断很类似,因此从字典来生成pandas数据也是可以的: 

a = pd.Series({"one":1,"two":2,"three":3,"four":4,"five":5})
print(a)

结果为:

one      1
two      2
three    3
four     4
five     5
dtype: int64

即会将字典的键作为index,值作为value来组织series数据。

 而如果同时传入字典和index,就会将index和字典中的键做匹配生成series数据,如果index不能匹配字典中的键,就会以NaN代替:

a = pd.Series({"one":1,"two":2,"three":3,"four":4,"five":5}, index=["one","two","three","four","six"])
print(a)

结果为:

one      1.0
two      2.0
three    3.0
four     4.0
six      NaN
dtype: float64

可见,字典中的"five"不在index中,会直接从结果中除去。

 同时NaN可以使用isnull函数或notnull函数来检测:

a.isnull()
pd.isnull(a)
a.notnull()
pd.notnull(a)

这四种形式得到的结果是类似的: 

one      False
two      False
three    False
four     False
six       True
dtype: bool

之前提到series对象和标量间的运算会作用到每个元素上,而如果是series对象间的算术运算则会根据index来确认结果:

a = pd.Series(range(5), index=["one","two","three","four","five"])
b = pd.Series({"one":1,"two":2,"three":3,"four":4,"five":5}, index=["one","two","three","four","six"])
print(a,b,a+b,sep="\n\n")

结果为:

one      0
two      1
three    2
four     3
five     4
dtype: int64

one      1.0
two      2.0
three    3.0
four     4.0
six      NaN
dtype: float64

five     NaN
four     7.0
one      1.0
six      NaN
three    5.0
two      3.0
dtype: float64

同时还可以设置series对象的name属性及index的name属性: 

a = pd.Series(range(5), index=["one","two","three","four","five"])
a.name = "test"
a.index.name = "index_test"
print(a,sep="\n\n")

 结果为:

index_test
one      0
two      1
three    2
four     3
five     4
Name: test, dtype: int64

DataFrame

如果说Series是一维数据,那么DataFrame就可以理解为二维数据,即表格型数据。和Series类似,DataFrame有一组有序的列,每列都可以有不同的值类型(数值、字符串和布尔值等)。

通过传入一个由等长列表或NumPy数组组成的字典可以直接构建DataFrame对象:

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002, 2003],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)

frame结果为:

    state	year	pop
0	Ohio	2000	1.5
1	Ohio	2001	1.7
2	Ohio	2002	3.6
3	Nevada	2001	2.4
4	Nevada	2002	2.9
5	Nevada	2003	3.2

对于比较大的DataFrame,head方法会选择前N行:

frame.head(3)

结果为:

    state	year	pop
0	Ohio	2000	1.5
1	Ohio	2001	1.7
2	Ohio	2002	3.6

而如果指定了列序列,DataFrame就会按照顺序重新进行排列:

pd.DataFrame(frame, columns=["year","state","pop"])

结果为:

    year	state	pop
0	2000	Ohio	1.5
1	2001	Ohio	1.7
2	2002	Ohio	3.6
3	2001	Nevada	2.4
4	2002	Nevada	2.9
5	2003	Nevada	3.2

而如果传入的列在数据中找不到,就会产生NaN:

frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five', 'six'])

frame2结果为:

	    year	state	pop	debt
one	    2000	Ohio	1.5	NaN
two	    2001	Ohio	1.7	NaN
three	2002	Ohio	3.6	NaN
four	2001	Nevada	2.4	NaN
five	2002	Nevada	2.9	NaN
six	    2003	Nevada	3.2	NaN

这里可以看到,DataFrame存在各种属性:

print(frame2.index, frame2.values, frame2.columns, sep="\n\n")

结果为:

Index(['one', 'two', 'three', 'four', 'five', 'six'], dtype='object')

[[2000 'Ohio' 1.5 nan]
 [2001 'Ohio' 1.7 nan]
 [2002 'Ohio' 3.6 nan]
 [2001 'Nevada' 2.4 nan]
 [2002 'Nevada' 2.9 nan]
 [2003 'Nevada' 3.2 nan]]

Index(['year', 'state', 'pop', 'debt'], dtype='object')

 和Series类似,DataFrame也可以设置index和columns的name属性:

frame3.index.name = "year"
frame3.columns.name = "state"
print(frame3)

结果为:

state  Nevada  Ohio
year               
2000      NaN   1.5
2001      2.4   1.7
2002      2.9   3.6

而通过列名就可以获取DataFrame的列,该列为Series对象:

print(frame2.state, frame2["state"], type(frame2.state), sep="\n\n")

结果为:

one        Ohio
two        Ohio
three      Ohio
four     Nevada
five     Nevada
six      Nevada
Name: state, dtype: object

one        Ohio
two        Ohio
three      Ohio
four     Nevada
five     Nevada
six      Nevada
Name: state, dtype: object

<class 'pandas.core.series.Series'>

可见frame2.state和frame2["state"]两种方式获取到的数据一样,均为Series类型,同时index的name属性也被设置为列名。

上面获取到的是列数据,也可以获取到行数据。行数据可以通过位置或者名称方式进行获取:

比如可以通过索引利用loc属性获取:

frame2.loc[["three","two"]]

结果为:

        year	state	pop	debt
three	2002	Ohio	3.6	NaN
two	    2001	Ohio	1.7	NaN

也可以通过索引利用iloc属性获取:

frame2.iloc[[2,1]]

结果为:

        year	state	pop	debt
three	2002	Ohio	3.6	NaN
two	    2001	Ohio	1.7	NaN

而赋值可以对单个元素赋值,也可以对整行或整列赋值,不过将列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配:

frame2.debt[1] = 100
print(frame2,"\n")
frame2.loc["three"] = [2005, "abc",10,20]
print(frame2,"\n")
frame2.debt = range(6)
print(frame2,"\n")

结果为:

       year   state  pop debt
one    2000    Ohio  1.5  NaN
two    2001    Ohio  1.7  100
three  2002    Ohio  3.6  NaN
four   2001  Nevada  2.4  NaN
five   2002  Nevada  2.9  NaN
six    2003  Nevada  3.2  NaN 

       year   state   pop debt
one    2000    Ohio   1.5  NaN
two    2001    Ohio   1.7  100
three  2005     abc  10.0   20
four   2001  Nevada   2.4  NaN
five   2002  Nevada   2.9  NaN
six    2003  Nevada   3.2  NaN 

       year   state   pop  debt
one    2000    Ohio   1.5     0
two    2001    Ohio   1.7     1
three  2005     abc  10.0     2
four   2001  Nevada   2.4     3
five   2002  Nevada   2.9     4
six    2003  Nevada   3.2     5 

也可以使用Series为DataFrame的某一列进行赋值,此时会通过两者的索引进行匹配,所有的空位会被填充NaN:

frame2["debt"] = val
frame2["new"] = val
print(frame2)

结果为:

       year   state   pop  debt  new
one    2000    Ohio   1.5   NaN  NaN
two    2001    Ohio   1.7  -1.2 -1.2
three  2005     abc  10.0   NaN  NaN
four   2001  Nevada   2.4  -1.5 -1.5
five   2002  Nevada   2.9  -1.7 -1.7
six    2003  Nevada   3.2   NaN  NaN

可见,为不存在的列赋值会创建出一个新列。

DataFrame列的删除则可以使用del关键字:

del frame2["new"]
print(frame2)

结果为:

       year   state   pop  debt
one    2000    Ohio   1.5   NaN
two    2001    Ohio   1.7  -1.2
three  2005     abc  10.0   NaN
four   2001  Nevada   2.4  -1.5
five   2002  Nevada   2.9  -1.7
six    2003  Nevada   3.2   NaN

而通过嵌套字典的方式也可以创建DataFrame,此时会将外层字典的键作为列,内层键则作为行索引:

pop = {'Nevada': {2001: 2.4, 2002: 2.9},
       'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}

frame3 = pd.DataFrame(pop)
print(frame3)

结果为:

      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7
2002     2.9   3.6

同时因为pandas基于numpy,因此可以DataFrame可以使用numpy的方法:

frame3.T

结果为:

        2000	2001	2002
Nevada	NaN	     2.4	2.9
Ohio	1.5	     1.7	3.6

下表为DataFrame构造函数所能接受的各种数据:

索引对象

pandas的索引对象负责管理轴标签和其他元数据(比如轴名称等)。构建Series或DataFrame时,所用到的任何数组或其他序列的标签都会被转换成一个Index:

index = frame3.index

index结果为: 

Int64Index([2000, 2001, 2002], dtype='int64', name='year')

同时索引对象是不可变的,不能够进行修改和赋值。

也可以单独构建索引对象:

pd.Index(range(5))

结果为:

RangeIndex(start=0, stop=5, step=1)

这样的话,就可以在不同的pandas对象间共享索引对象。

不过同python的集合不同,pandas中的索引对象可以包含重复的标签:

pd.Index(["one","two","three","one"])

结果为:

Index(['one', 'two', 'three', 'one'], dtype='object')

和索引对象相关的方法和属性有:

基本功能

重新索引

pandas对象可以通过reindex方法进行重新索引,即对数据进行重新排序:

tmp = pd.Series([5,3,6,98,7],index=["three","four","two","one","five"])
tmp.reindex(["one","two","three","four","five"])

结果为:

one      98
two       6
three     5
four      3
five      7
dtype: int64

但reindex是创建了一个新对象,并不改变原对象。

和之前一样,如果reindex中的索引不存在,就会引入NaN。

同时重新索引时需要进行一些插值处理,可以借助其中的method参数进行填充设置,ffill表示使用前向值填充,bfill表示使用后向值填充,nearest表示使用最近值填充,默认不填充:

tmp = pd.Series(["red","orange","yellow","green","pink"],index=[0,1,2,4,6])
tmp.reindex(range(7),method="ffill")

结果为:

0       red
1    orange
2    yellow
3    yellow
4     green
5     green
6      pink
dtype: object

对于DataFrame对象来说,也是一样的:

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002, 2003],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data, index=["one","two","three","four","five","six"])

frame.reindex(["six","five","four","three","two","one"])

结果为:

        state	year	pop
six	    Nevada	2003	3.2
five	Nevada	2002	2.9
four	Nevada	2001	2.4
three	Ohio	2002	3.6
two	    Ohio	2001	1.7
one	    Ohio	2000	1.5

除了根据index进行重新索引,也可以根据列名进行重新索引:

frame.reindex(columns=["year","state","pop"])

结果为:

	    year	state	pop
one	    2000	Ohio	1.5
two	    2001	Ohio	1.7
three	2002	Ohio	3.6
four	2001	Nevada	2.4
five	2002	Nevada	2.9
six	    2003	Nevada	3.2

reindex函数的各参数及说明为:

丢弃指定轴上的项

drop方法可以移除指定轴上的项,并返回新对象,默认删除行方向的内容:

frame.drop(["one","three"])

结果为:

        state	year	pop
two	    Ohio	2001	1.7
four	Nevada	2001	2.4
five	Nevada	2002	2.9
six	    Nevada	2003	3.2

也可以指定axis=1或axis=columns,移除列方向上的内容:

frame.drop(["year"],axis=1)

结果为:

	    state	pop
one	    Ohio	1.5
two	    Ohio	1.7
three	Ohio	3.6
four	Nevada	2.4
five	Nevada	2.9
six	    Nevada	3.2

另外可以通过设置inplace=True来就地修改数据:

frame.drop(["year"],axis=1,inplace=True)

此时frame的结果为:

	    state	pop
one	    Ohio	1.5
two	    Ohio	1.7
three	Ohio	3.6
four	Nevada	2.4
five	Nevada	2.9
six	    Nevada	3.2

此时不会返回新对象,而是会就地修改原数据。

索引、选取和过滤

之前提到,对于Series来说,可以通过index,数字下标和布尔操作的方式进行索引:

tmp = pd.Series([5,3,6,98,7],index=["three","four","two","one","five"])
print(tmp["three"],tmp[0],tmp[["three","four"]],tmp[[0,1]],tmp[0:2],tmp[tmp>5], sep="\n\n")

结果为:

5

5

three    5
four     3
dtype: int64

three    5
four     3
dtype: int64

three    5
four     3
dtype: int64

two      6
one     98
five     7
dtype: int64

利用index进行切片运算与python中的切片运算也有差异,其区间两端是闭合的:

tmp["three":"two"]

结果为:

three    5
four     3
two      6
dtype: int64

同时上面的几种索引方法均可以用来进行赋值。

对于DataFrame来说,使用值或序列对DataFrame进行索引就是获取一个或多个列:

data = pd.DataFrame(np.arange(16).reshape((4, 4)), 
                    index=['Ohio', 'Colorado', 'Utah', 'New York'],
                    columns=['one', 'two', 'three', 'four'])

print(data["one"],data[["one","two"]], sep="\n\n")

结果为:

Ohio         0
Colorado     4
Utah         8
New York    12
Name: one, dtype: int32

          one  two
Ohio        0    1
Colorado    4    5
Utah        8    9
New York   12   13

而如果使用数字切片或者布尔数组获取的就是行数据,不过这种方式只能通过切片方式进行索引,不能通过数字下标和数字序列进行索引:

print(data[:2],data[data["one"]>5],sep="\n\n")

结果为:

          one  two  three  four
Ohio        0    1      2     3
Colorado    4    5      6     7

          one  two  three  four
Utah        8    9     10    11
New York   12   13     14    15

同样DataFrame的索引方式也可以用来进行赋值。

用loc和iloc进行选取

之前提到,loc和iloc属性可以用来进行行数据的选取,不过loc使用轴标签,而iloc则是使用整数索引:

print(data.loc[["Ohio","Colorado","Utah"]], data.iloc[[0,1,2]], sep="\n\n")

结果为:

          one  two  three  four
Ohio        0    1      2     3
Colorado    4    5      6     7
Utah        8    9     10    11

          one  two  three  four
Ohio        0    1      2     3
Colorado    4    5      6     7
Utah        8    9     10    11

并且loc和iloc可以接受两个序列,用来进行元素定位,类似于numpy的二维索引:

print(data.loc[["Ohio","Colorado","Utah"],["one","three","two"]], data.iloc[[0,1,2],[0,2,1]], sep="\n\n")

结果为:

          one  three  two
Ohio        0      2    1
Colorado    4      6    5
Utah        8     10    9

          one  three  two
Ohio        0      2    1
Colorado    4      6    5
Utah        8     10    9

同时这两个索引函数也适用于一个标签或多个标签的切片:

print(data.loc["Ohio":"Utah","one":"two"], data.iloc[0:3,0:3][data.one>4], sep="\n\n")

结果为:

          one  two
Ohio        0    1
Colorado    4    5
Utah        8    9

      one  two  three
Utah    8    9     10

DataFrame中的索引方式主要有:

表5-4 DataFrame的索引选项

算术运算和数据对齐

和之前提到的Series类似,不同索引对象之间的算术运算就是两者的并集:

s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])
s1+s2

结果为:

a    5.2
c    1.1
d    NaN
e    0.0
f    NaN
g    NaN
dtype: float64

可以看到,在索引不重叠的部分会引入NaN,NaN会在算术运算过程中传播。

对于DataFrame来说,也是同样的效果:

df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])
df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
print(df1,df2,df1+df2,sep="\n\n")

结果为:

            b    c    d
Ohio      0.0  1.0  2.0
Texas     3.0  4.0  5.0
Colorado  6.0  7.0  8.0

          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0

            b   c     d   e
Colorado  NaN NaN   NaN NaN
Ohio      3.0 NaN   6.0 NaN
Oregon    NaN NaN   NaN NaN
Texas     9.0 NaN  12.0 NaN
Utah      NaN NaN   NaN NaN

即DataFrame会将NaN引入到index和column中不重叠的部分,而NaN与任何元素的计算都是NaN。

在算术方法中填充值

之前提到,NaN与任何元素的计算都是NaN,而有时需要在计算得到的NaN中填充其它值,这就需要其它参数。

如当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值(比如0):

df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])
df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

print(df1,df2,df1.add(df2, fill_value=0), sep="\n\n")

结果为:

            b    c    d
Ohio      0.0  1.0  2.0
Texas     3.0  4.0  5.0
Colorado  6.0  7.0  8.0

          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0

            b    c     d     e
Colorado  6.0  7.0   8.0   NaN
Ohio      3.0  1.0   6.0   5.0
Oregon    9.0  NaN  10.0  11.0
Texas     9.0  4.0  12.0   8.0
Utah      0.0  NaN   1.0   2.0

没有重叠的位置就会产生NA值。

下面列出了Series和DataFrame的算术方法。r开头的方法会翻转参数。因此df1.div(df2)和df2.rdiv(df1)是等价的。

表5-5 灵活的算术方法

DataFrame和Series之间的运算

由于pandas基于numpy,而numpy存在广播机制,因此DataFrame和Series也存在类似的机制。

frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
series = pd.Series([1,2,3], index=list('bdf'))

print(frame, series, frame - series, sep="\n\n")

结果为:

          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0

b    1
d    2
f    3
dtype: int64

          b    d   e   f
Utah   -1.0 -1.0 NaN NaN
Ohio    2.0  2.0 NaN NaN
Texas   5.0  5.0 NaN NaN
Oregon  8.0  8.0 NaN NaN

可以看到,DataFrame和Series之间的算术运算会将Series的索引匹配到DataFrame的列,然后沿着行一直向下广播。而如果某个索引值在DataFrame的列或Series的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集

而如果希望在列上进行广播,就必须使用算术运算方法:

frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
series = pd.Series([1,2,3], index=['Utah', 'Ohio', 'Colorado'])

print(frame, series, frame.sub(series, axis=0), sep="\n\n")

结果为:

          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0

Utah        1
Ohio        2
Colorado    3
dtype: int64

            b    d    e
Colorado  NaN  NaN  NaN
Ohio      1.0  2.0  3.0
Oregon    NaN  NaN  NaN
Texas     NaN  NaN  NaN
Utah     -1.0  0.0  1.0

函数应用和映射

numpy的某些元素级数组方法也可以应用于pandas对象:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

print(frame, np.abs(frame),sep="\n\n")

结果为:

               b         d         e
Utah    0.697534 -0.134106 -0.329323
Ohio   -0.907970 -0.448474 -0.498009
Texas  -0.327485  1.706504  1.692652
Oregon -0.129142  1.167562 -1.035300

               b         d         e
Utah    0.697534  0.134106  0.329323
Ohio    0.907970  0.448474  0.498009
Texas   0.327485  1.706504  1.692652
Oregon  0.129142  1.167562  1.035300

另外,还可以将函数应用到由各列或行所形成的一维数组上,这借助于DataFrame的apply方法即可实现:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

print(frame, frame.apply(lambda x:x.max() - x.min()), frame.apply(lambda x:x.max() - x.min(), axis=1),sep="\n\n")

结果为:

               b         d         e
Utah    0.677041  0.330069 -0.593199
Ohio    0.022976  0.095901 -1.184464
Texas   0.379823  0.799666  1.980348
Oregon -0.240406 -0.948640 -0.573052

b    0.917448
d    1.748305
e    3.164812
dtype: float64

Utah      1.270240
Ohio      1.280365
Texas     1.600525
Oregon    0.708233
dtype: float64

而传递到apply的函数不是必须返回一个标量,还可以返回由多个值组成的Series:

def func(x):
    return pd.Series([x.min(), x.max()], index=['min', 'max'])

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

print(frame, frame.apply(func),frame.apply(func,axis=1),sep="\n\n")

结果为:

               b         d         e
Utah   -0.707579  0.565288  1.650140
Ohio   -2.921518 -0.063220  0.666870
Texas   0.395668  0.787787 -1.924530
Oregon -0.438882 -0.750354  0.168851

            b         d        e
min -2.921518 -0.750354 -1.92453
max  0.395668  0.787787  1.65014

             min       max
Utah   -0.707579  1.650140
Ohio   -2.921518  0.666870
Texas  -1.924530  0.787787
Oregon -0.750354  0.168851

apply可以应用到行或列数据上,而applymap可以应用到元素级的数据上:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

print(frame, frame.applymap(lambda x: "%.2f" % x),sep="\n\n")

结果为:

               b         d         e
Utah   -0.217009 -0.330181 -0.008281
Ohio   -0.427106  1.840410  0.380936
Texas   0.993709  1.778476 -0.348506
Oregon -1.781456  0.092446  0.399635

            b      d      e
Utah    -0.22  -0.33  -0.01
Ohio    -0.43   1.84   0.38
Texas    0.99   1.78  -0.35
Oregon  -1.78   0.09   0.40

而对于Series对象来说,则是map方法:

series = pd.Series(np.random.randn(4))

print(series, series.map(lambda x: "%.2f" % x),sep="\n\n")

结果为:

0    0.912111
1   -1.035146
2   -2.283053
3   -0.891400
dtype: float64

0     0.91
1    -1.04
2    -2.28
3    -0.89
dtype: object

排序和排名

要对行或列索引进行排序,可使用sort_index方法:

series = pd.Series(np.random.randn(4), index = list("dbac"))

print(series, series.sort_index(),sep="\n\n")

结果为:

d   -2.972148
b   -0.374894
a   -0.185849
c    0.571640
dtype: float64

a   -0.185849
b   -0.374894
c    0.571640
d   -2.972148
dtype: float64

sort_index是按照index排序的,而sort_values则是按照value排序的:

series = pd.Series(np.random.randn(4), index = list("dbac"))

print(series, series.sort_values(),sep="\n\n")

结果为:

d   -0.063629
b    1.178513
a    0.562040
c   -1.761235
dtype: float64

c   -1.761235
d   -0.063629
a    0.562040
b    1.178513
dtype: float64

对于DataFrame,则可以根据任意一个轴上的索引进行排序:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('dbe'), index=list("dbac"))

print(frame, frame.sort_index(),frame.sort_index(axis=1),frame.sort_values(by=["b","d"]),frame.sort_values(by=["a","c"],axis=1),sep="\n\n")

结果为:

          d         b         e
d -0.261446  1.342736  0.431499
b  2.020019  1.143758 -2.011755
a -1.059436  0.533637 -1.694812
c  0.017930  0.197699  1.062465

          d         b         e
a -1.059436  0.533637 -1.694812
b  2.020019  1.143758 -2.011755
c  0.017930  0.197699  1.062465
d -0.261446  1.342736  0.431499

          b         d         e
d  1.342736 -0.261446  0.431499
b  1.143758  2.020019 -2.011755
a  0.533637 -1.059436 -1.694812
c  0.197699  0.017930  1.062465

          d         b         e
c  0.017930  0.197699  1.062465
a -1.059436  0.533637 -1.694812
b  2.020019  1.143758 -2.011755
d -0.261446  1.342736  0.431499

          e         d         b
d  0.431499 -0.261446  1.342736
b -2.011755  2.020019  1.143758
a -1.694812 -1.059436  0.533637
c  1.062465  0.017930  0.197699

同样sort_index表示按index排序,参数axis表示方向。sort_values表示按value排序,参数axis表示方向,参数by表示排序使用的列。参数ascending表示使用升序还是降序,这里没有体现。

在排序时,NaN默认都会被放到末尾。

而rank方法则是为各组分配一个平均排名:

series = pd.Series([7, -5, 7, 4, 2, 0, 4])
series.rank()

结果为:

0    6.5
1    1.0
2    6.5
3    4.5
4    3.0
5    2.0
6    4.5
dtype: float64

也可以根据值在原数据中出现的顺序给出排名:

series = pd.Series([7, -5, 7, 4, 2, 0, 4])
series.rank(method="first")

结果为:

0    6.0
1    1.0
2    7.0
3    4.0
4    3.0
5    2.0
6    5.0
dtype: float64

这里,条目0和2没有使用平均排名6.5,它们被设成了6和7,因为数据中标签0位于标签2的前面。同样参数ascending表示使用升序还是降序,这里没有体现。

rank方法对于DataFrame也是有效的:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('dbe'), index=list("dbac"))

print(frame, frame.rank(),sep="\n\n")

结果为:

          d         b         e
d -1.120805  0.172054  0.470200
b -0.108554  0.161372  1.401574
a -1.083892 -0.726145 -0.323556
c  0.502917 -2.040901  0.160475

     d    b    e
d  1.0  4.0  3.0
b  3.0  3.0  4.0
a  2.0  2.0  1.0
c  4.0  1.0  2.0

下表为相关的method选项:

表5-6 排名时用于破坏平级关系的方法

带有重复标签的轴索引

之前提到,index可以是重复的:

series = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
index = series.index
print(index, index.is_unique,sep="\n\n")

结果为:

Index(['a', 'a', 'b', 'b', 'c'], dtype='object')

False

而如果获取重复索引的话,则会得到Series对象:

series["a"]

结果为:

a    0
a    1
dtype: int64

而非重复索引则会返回一个标量值:

series["c"]

结果为:

4

 这在DataFrame中也是类似的:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('dbe'), index=list("aabc"))

print(frame.loc["a"])

结果为:

          d         b         e
a  1.204948 -0.323096  0.718391
a  1.251217 -0.916471 -1.732916

汇总和计算描述统计

这里看几个pandas方法:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('abc'), index=list("defg"))

print(frame,frame.sum(),frame.mean(),frame.idxmax(),frame.idxmin(),frame.cumsum(),frame.describe(),sep="\n\n")

结果为:

          a         b         c
d -1.125236 -0.285921 -0.805632
e -0.497351  1.246323  1.887993
f -0.588805  2.746995 -1.245783
g  0.934575  0.346072 -1.075893

a   -1.276816
b    4.053470
c   -1.239315
dtype: float64

a   -0.319204
b    1.013367
c   -0.309829
dtype: float64

a    g
b    f
c    e
dtype: object

a    d
b    d
c    f
dtype: object

          a         b         c
d -1.125236 -0.285921 -0.805632
e -1.622586  0.960402  1.082361
f -2.211391  3.707397 -0.163422
g -1.276816  4.053470 -1.239315

              a         b         c
count  4.000000  4.000000  4.000000
mean  -0.319204  1.013367 -0.309829
std    0.880543  1.315696  1.476381
min   -1.125236 -0.285921 -1.245783
25%   -0.722913  0.188074 -1.118365
50%   -0.543078  0.796198 -0.940762
75%   -0.139369  1.621491 -0.132226
max    0.934575  2.746995  1.887993

上面约简方法的常用选项有:

pandas中与描述统计相关的方法有:

相关系数与协方差

pct_change可以计算数据的百分数变化:

frame = pd.DataFrame(np.random.randn(3, 3), columns=list('abc'), index=list("def"))

print(frame,frame.pct_change(),sep="\n\n")

结果为:

          a         b         c
d  0.032445  0.659345 -0.226624
e -1.911535 -0.467181 -0.948741
f  0.264409 -1.071222  0.941417

           a         b         c
d        NaN       NaN       NaN
e -59.916239 -1.708553  3.186415
f  -1.138323  1.292950 -1.992280

Series的corr方法用于计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数:

frame["a"].corr(frame["b"])

结果为:

0.07529315230633803

而cov用于计算协方差:

frame["a"].cov(frame["b"])

结果为:

0.07902552853380769

另外,DataFrame的corr和cov方法将以DataFrame的形式分别返回完整的相关系数或协方差矩阵:

print(frame.corr(), frame.cov(), sep="\n\n")

结果为:

          a         b         c
a  1.000000  0.075293  0.846318
b  0.075293  1.000000 -0.467443
c  0.846318 -0.467443  1.000000

          a         b         c
a  1.427933  0.079026  0.964601
b  0.079026  0.771465 -0.391604
c  0.964601 -0.391604  0.909746

而利用DataFrame的corrwith方法,则可以计算其列或行跟另一个Series或DataFrame之间的相关系数。传入一个Series将会返回一个相关系数值Series:

frame.corrwith(frame["a"])

结果为:

a    1.000000
b    0.075293
c    0.846318
dtype: float64

可以看出,corrwith的结果是corr方法的子集。而传入一个DataFrame则会计算按列名配对的相关系数:

frame.corrwith(pd.DataFrame(frame.values, columns=list("edf"),index=list("abc")).T)

结果为:

a    0.137612
b    0.484800
c    0.454882
dtype: float64

唯一值、值计数以及成员资格

Series对象的unique方法会返回value的集合,

series = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
print(series.values,series.unique(), sep="\n\n")

结果为:

['c' 'a' 'd' 'a' 'a' 'b' 'b' 'c' 'c']

['c' 'a' 'd' 'b']

而value_counts方法用于计算一个Series中各值出现的频率:

series.value_counts()

结果为:

c    3
a    3
b    2
d    1
dtype: int64

而isin用于判断矢量化集合的成员资格,可用于过滤Series中或DataFrame列中数据的子集:

print(series.isin(list("ab")), series[series.isin(list("ab"))], sep="\n\n")

结果为:

0    False
1     True
2    False
3     True
4     True
5     True
6     True
7    False
8    False
dtype: bool

1    a
3    a
4    a
5    b
6    b
dtype: object

而Index.get_indexer方法会返回一个索引数组,从可能包含重复值的数组到另一个不同值的数组:

series1 = pd.Series(['c', 'a', 'b', 'b', 'c', 'a'])
series2 = pd.Series(['c', 'b', 'a'])

pd.Index(series2).get_indexer(series1)

结果为:

array([0, 2, 1, 1, 0, 2], dtype=int64)

这些方法的介绍为:

表5-9 唯一值、值计数、成员资格方法

上面的内容也可以综合起来:

data = pd.DataFrame({'Qu1': [1, 3, 4, 3, 4], 'Qu2': [2, 3, 1, 2, 3], 'Qu3': [1, 5, 2, 4, 4]})
print(data.apply(pd.value_counts).fillna(0))

结果为:

   Qu1  Qu2  Qu3
1  1.0  1.0  1.0
2  0.0  2.0  1.0
3  2.0  2.0  0.0
4  2.0  0.0  2.0
5  0.0  0.0  1.0

这里计算的是行方向上的各个值的数目,并将不存在的值赋值为0。

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Pandas是一个Python库,用于数据处理和分析。在数据分析中,预处理是非常重要的一步,因为它可以帮助我们清洗和转换数据,使其更适合进行分析。Pandas提供了一些强大的预处理功能,包括数据清洗、数据转换、数据重塑和数据合并等。在使用Pandas进行数据分析时,预处理是必不可少的一步。 ### 回答2: 在数据分析中,数据的预处理是一个必要的过程。它的主要目的是清洗数据,准备数据,以便后续分析。在Python中,pandas是一种广泛使用的数据处理库。pandas可以通过其高效的数据结构和操作方法来清洗和处理数据。在本文中,将介绍pandas预处理的一些常见技术。 一、读取数据 在pandas中,使用read_csv()函数读取CSV格式的数据文件,read_excel()函数读取Excel格式的数据文件。它们都有很多选项,可以根据具体文件的格式进行设置。 二、查看数据 在pandas中,使用以下函数来查看数据: 1. head() - 显示数据框的前几行; 2. tail() - 显示数据框的后几行; 3. columns - 显示数据框的列名; 4. shape - 显示数据框的行列数; 5. info() - 显示数据框的基本信息,包括每列的名称、非空值数量和数据类型。 三、数据清洗 在数据清洗中,有以下一些常见的技术: 1. 删除重复行:使用drop_duplicates()函数; 2. 替换空值:使用fillna()函数; 3. 删除空值:使用dropna()函数; 4. 更改数据类型:使用astype()函数。 四、数据准备 在数据准备中,有以下一些常见的技术: 1. 数据合并:使用merge()函数; 2. 数据筛选:使用loc()函数或者iloc()函数; 3. 数据分组:使用groupby()函数; 4. 数据排序:使用sort_values()函数。 五、数据分析数据分析中,有以下一些常见的技术: 1. 数据聚合:使用agg()函数; 2. 统计描述:使用describe()函数; 3. 数据可视化:使用matplotlib或者seaborn库。 综上所述,pandas预处理是数据分析中必不可少的一步。通过使用pandas提供的函数和方法,可以方便地清理和处理数据,使其更容易被分析。 ### 回答3: PandasPython中最强大的数据处理库之一,它提供了DataFrameSeries这两种数据结构,可以快速便捷地处理数据。在数据分析过程中,我们往往需要先对数据进行预处理,以便后续的分析。Pandas提供了一系列的方法和函数,可以帮助我们进行数据的预处理。 首先,在进行数据分析之前,我们需要了解自己所面对的数据类型和数据结构。Pandas中的DataFrame结构就是类似于表格的结构,每一行代表一个样本,每一列代表一个属性。Series则是一维的数组结构。通过pandas.read_csv(),我们可以读取CSV格式的数据,并转化为DataFrame结构。 接下来,我们要对数据进行一些基本的处理,例如数据清洗、数据去重、缺失值处理、异常值处理等。在数据清洗过程中,我们往往需要对数据进行一些特殊的处理,例如字符串的分割、合并、替换等操作,Pandas提供了一系列能够对文本进行操作的函数。在数据去重方面,我们可以使用drop_duplicates()函数,它可以去除DataFrame中的重复记录。在处理缺失值时,Pandas提供了一系列的函数,如fillna()函数、dropna()函数,可以方便地将NaN值变为其他有意义的值,或者删除缺失值的行或列。在异常值处理方面,我们可以使用isoutlier()函数来找到数据中的异常值,并进行处理。 在数据预处理完成后,我们可以对数据进行一些统计分析,例如计算小计、计算总计、分位数、极差、方差、标准差等统计指标。我们可以使用describe()函数来获得数据的统计描述,还可以使用groupby()函数来对数据分组,使用agg()函数对每组进行计算统计指标。此外,我们还可以对数据进行排序、丢弃、合并等操作。 总之,Pandas是一个非常强大的Python库,可以轻松处理数据预处理和数据处理方面的任务。Pandas作为数据分析和数据处理的基础库,使用熟练后可以在数据分析中发挥更大的作用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值