Pandas数据处理

Series对象

Series对象是一个带索引构成的一维数组,可以用一个数组创建Series对象:

import pandas as pd

In [2]: pd.Series([1,2,3,4,5,6])

Out[2]: 
0    1
1    2
2    3
3    4
4    5
5    6
dtype: int64

In [5]: data.index
Out[5]: RangeIndex(start=0, stop=6, step=1)

In [7]: data.values
Out[7]: array([1, 2, 3, 4, 5, 6])

Series对象是一种显式定义的索引与数值关联,可以不再仅仅是整数,还可以是任意想要的类型。你可以把Series看成一种特殊的python字典。

DataFrame

创建DataFrame对象

  1. 通过单个Series对象创建
In [15]: pd.DataFrame(pd.Series([1,2,3]), columns=['test'])
Out[15]: 
   test
0     1
1     2
2     3

  1. 通过字典列表创建
In [11]: pd.DataFrame([{'a':1, 'b':2}])

Out[11]: 

   a  b

0  1  2
  1. 通过Series对象字典创建
In [16]: pd.DataFrame({ 'a':pd.Series([1,2,3]), 'b':pd.Series([2,3,4])})
Out[16]: 
   a  b
0  1  2
1  2  3
2  3  4
  1. 通过Numpy二维数组创建
In [14]: pd.DataFrame(np.random.rand(3,2), columns=['foo', 'bar'], index=['a','b','c'])
Out[14]: 
        foo       bar
a  0.528223  0.955862
b  0.506073  0.432731
c  0.310693  0.522418
  1. 通过Numpy结构化数组创建
a = np.zeros(3,dtype=[('A', '<i8'), ('B', '<f8')])

Pandas的Index对象

Pandas的Index对象是一个很有趣的数据结构,可以将它看作是一个不可变数组或有序集合。可以看成index不可变数组和有序集合。

In [17]: ind = pd.Index([2,3,4,5,7])

In [18]: ind
Out[18]: Int64Index([2, 3, 4, 5, 7], dtype='int64')

数据选择方式

Series

  1. 将Series看作Series看作字典,用键值映射。
  2. 将Series看作一维数组,可以索引、掩码和花哨。
  3. 索引器:loc\iloc和ix
    前面提到的取值和切片,其实它们的索引方式不同,所以整数索引会产生混淆。loc表示取值和切片都是显式的,iloc表示取值和切片都是Python形式的隐式索(也就是元素所在位置, 一定从0开始)。第三种是ix,两种的混合,常用于DataFrame。

DataFrame

  1. 将DataFrame看作字典
  2. 将DataFrame看作二维数组,可以用Values属性按行查看数据。
  3. 索引器loc,iloc,ix
    loc可以结合使用掩码与花哨的索引方法:data.loc[data.density > 100, ['pop', 'density']] ,如果用掩码也可以直接data[data.density > 100]

Pandas数值运算方法

pandas一元运算,通用函数将在输出结果中保留索引和列标签,二元运算,会自动对齐索引。二元运算索引是并集操作,如果缺失会用NaN来代替。

处理缺失值

在数据表或者DataFrame有很多识别缺失值,一般有两种:掩码和标签值。None是python对象的缺失值,NaN是数值类型的缺失值。在Pandas可以看作等价交换的。

In [3]: pd.Series([1,np.nan,2, None])

Out[3]: 

0    1.0

1    NaN

2    2.0

3    NaN

dtype: float64

发现/处理缺失值函数

  • isnull(): 创建一个布尔类型的掩码标签缺失值
  • notnull(): 与isnull()操作相反
  • dropna(): 返回一个剔除缺失值的数据
  • fillna():填充缺失值

发现缺失值

isnull()和notnull()可以发现缺失值,返回布尔类型掩码数据。

In [4]: data = pd.Series([1, np.nan, 'hello', None])
In [5]: data.isnull()
Out[5]: 

0    False

1     True

2    False

3     True

dtype: bool

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

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

剔除缺失值

可以用dropna()剔除缺失值

In [7]: data.dropna()
Out[7]: 
0        1
2    hello
dtype: object

在DataFrame上使用它们需要设置一些参数,我们没有办法单独剔除一个值,要么剔除缺失值所在整行,要么整列。

In [8]: df = pd.DataFrame([[1,np.nan,2],[2,3,5],[np.nan,4,6]])

In [9]: df
Out[9]: 
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6

# 剔除任何包含缺失值整行数据
In [10]: df.dropna()
Out[10]: 
     0    1  2
1  2.0  3.0  5
# 删除任何包含缺失值的整列数据
In [11]: df.dropna(axis='columns')
Out[11]: 
   2
0  2
1  5
2  6

可以通过how或者thresh参数设置剔除阈值:

In [12]: df[3] = np.nan

In [13]: df
Out[13]: 
     0    1  2   3
0  1.0  NaN  2 NaN
1  2.0  3.0  5 NaN
2  NaN  4.0  6 NaN

# how='all'全部是缺失值的行或者列
In [14]: df.dropna(axis='columns', how = 'all')
Out[14]: 
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6

thresh设置行列中非缺失值最小数量

In [15]: df.dropna(axis='rows', thresh=3)
Out[15]: 
     0    1  2   3
1  2.0  3.0  5 NaN

填充缺失值

fillna()填充缺失值

In [16]: data=pd.Series([1, np.nan, 2, None,3], index=list('abcde'))

In [17]: data
Out[17]: 
a    1.0
b    NaN
c    2.0
d    NaN
e    3.0
dtype: float64

用fillna()填充

In [18]: data.fillna(0)
Out[18]: 
a    1.0
b    0.0
c    2.0
d    0.0
e    3.0
dtype: float64

可以用前面有效值从前往后填充(forward-fill)

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

可以用后面往前填充(back-fill)

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

DataFrame与Series类似:

In [21]: df
Out[21]: 
     0    1  2   3
0  1.0  NaN  2 NaN
1  2.0  3.0  5 NaN
2  NaN  4.0  6 NaN

# 如果从前往后填充时,前面没有值,仍然是NaN
In [22]: df.fillna(method='ffill', axis=1)
Out[22]: 
     0    1    2    3
0  1.0  1.0  2.0  2.0
1  2.0  3.0  5.0  5.0
2  NaN  4.0  6.0  6.0

合并数据:Concat与Append操作

Pandas有一个pd.concat(), concat可以简单合并一维的Series或DataFrame对象

In [26]: ser1 = pd.Series(['A','B', 'C'], index=[1,2,3])

In [27]: ser2 = pd.Series(['D', 'E', 'F'], index=[4,5,6])

In [28]: pd.concat([ser1, ser2])
Out[28]: 
1    A
2    B
3    C
4    D
5    E
6    F
dtype: object

In [23]: def make_df(cols,ind):
    ...:     data = {c:[str(c) + str(i) for i in ind] for c in cols}
    ...:     return pd.DataFrame(data, ind)

In [29]: df1 = make_df('AB', [1,2])

In [30]: df2 = make_df('AB', [3,4])

In [31]: print(df1), print(df2), print(pd.concat([df1, df2]))
    A   B
1  A1  B1
2  A2  B2
    A   B
3  A3  B3
4  A4  B4
    A   B
1  A1  B1
2  A2  B2
3  A3  B3
4  A4  B4

# 列拼接
In [35]: print(df3); print(df4);print(pd.concat([df3, df4], axis=1))
    A   B
0  A0  B0
1  A1  B1
    C   D
0  C0  D0
1  C1  D1
    A   B   C   D
0  A0  B0  C0  D0
1  A1  B1  C1  D1

pandas在合并时会保留索引:

In [36]: x = make_df('AB', [0,1])

In [37]: y = make_df('CD', [2,3])

In [38]: y.index = x.index

In [39]: print(x); print(y), print(pd.concat([x,y]))
    A   B
0  A0  B0
1  A1  B1
    A   B
0  A2  B2
1  A3  B3
    A   B
0  A0  B0
1  A1  B1
0  A2  B2
1  A3  B3

如果想捕捉索引重复错误,可以用verify_integrity :pd.concat([x,y], verify_integrity=True)

可以用ignore_index参数来创建新的整数索引:ignore_index :pd.concat([x,y], ignore_index=True)

还有一种方式是可以用keys参数设置多级索引标签:pd.concat([x,y], keys=['x', 'y'])

合并DataFrame都是同样的列名,而在实际工作中,可能是数据带不同的列名,这里可以用join合并方式。

In [4]: df5 = make_df('ABC', [1,2])

In [5]: df5 = make_df('ABC', [1,2])

In [6]: df6 = make_df('BCD', [3,4])

In [7]: print(df5);print(df6);print(pd.concat([df5,df6]))
    A   B   C
1  A1  B1  C1
2  A2  B2  C2
    B   C   D
3  B3  C3  D3
4  B4  C4  D4
     A   B   C    D
1   A1  B1  C1  NaN
2   A2  B2  C2  NaN
3  NaN  B3  C3   D3
4  NaN  B4  C4   D4

默认情况下,join是outer方式并集合并,你可以用inner交集合并

In [8]: print(df5);print(df6);print(pd.concat([df5,df6], join='inner'))
    A   B   C
1  A1  B1  C1
2  A2  B2  C2
    B   C   D
3  B3  C3  D3
4  B4  C4  D4
    B   C
1  B1  C1
2  B2  C2
3  B3  C3
4  B4  C4

合并数据集:合并与连接

pd.merge()函数实现了三种数据连续类型:一对一,多对一和多对多。

In [14]: df1=pd.DataFrame({'employee':['Bob','Jake', 'Lisa','Sue'], 'group':['Accounting', 'Engineering', 'Engineering', 'HR']})

In [15]: df2=pd.DataFrame({'employee':['Bob','Jake', 'Lisa','Sue'], 'hire_date':[2004,2008,2012,2014]})

In [16]: print(df1);print(df2)
  employee        group
0      Bob   Accounting
1     Jake  Engineering
2     Lisa  Engineering
3      Sue           HR
  employee  hire_date
0      Bob       2004
1     Jake       2008
2     Lisa       2012
3      Sue       2014

In [17]: df3 = pd.merge(df1,df2)

In [18]: df3
Out[18]: 
  employee        group  hire_date
0      Bob   Accounting       2004
1     Jake  Engineering       2008
2     Lisa  Engineering       2012
3      Sue           HR       2014

merge发现有'employee'列,所以自动以以偏概全作为键进行连接。同时需要注意,merge会默认丢弃原来行索引。

多对一是指同一列有重复值,通过多对一的方式,会保留重复值。

In [19]: df4=pd.DataFrame({'group': ['Accounting', 'Engineering', 'HR'], 'supervisor':['Carly','Guido', 'Steve']})

In [20]: print(df3);print(df4);print(pd.merge(df3,df4))
  employee        group  hire_date
0      Bob   Accounting       2004
1     Jake  Engineering       2008
2     Lisa  Engineering       2012
3      Sue           HR       2014
         group supervisor
0   Accounting      Carly
1  Engineering      Guido
2           HR      Steve
  employee        group  hire_date supervisor
0      Bob   Accounting       2004      Carly
1     Jake  Engineering       2008      Guido
2     Lisa  Engineering       2012      Guido
3      Sue           HR       2014      Steve

多对多是指两个同一列有重复值,通过多对多的方式,会保留重复值。

In [21]: df5=pd.DataFrame({'group':['Accounting', 'Accounting', 'Engineering', 'Engineering','HR','HR'], 'skills':['math','spreadsheets', 'coding', 'linux', 'spreadsheets', 'organization']})



In [22]: print(df1); print(df5); print(pd.merge(df1,df5))

  employee        group

0      Bob   Accounting

1     Jake  Engineering

2     Lisa  Engineering

3      Sue           HR

         group        skills

0   Accounting          math

1   Accounting  spreadsheets

2  Engineering        coding

3  Engineering         linux

4           HR  spreadsheets

5           HR  organization

  employee        group        skills

0      Bob   Accounting          math

1      Bob   Accounting  spreadsheets

2     Jake  Engineering        coding

3     Jake  Engineering         linux

4     Lisa  Engineering        coding

5     Lisa  Engineering         linux

6      Sue           HR  spreadsheets

7      Sue           HR  organization

设置数据合并的键

merge()默认行为它会将两个输入的一个或多个共同列作为键进行合并,但由于输入要合并列通常不同名,所以提供了一些参数处理。如果合并两个不同列名的数据集,可以用left_onright_on 来指定。

n [23]: df3 = pd.DataFrame({'name':['Bob','Jake','Lisa','Sue'], 'salary':[7000,8000,12000,90000]})

In [24]: print(df1);print(df2);print(pd.merge(df1,df3,left_on="employee", right_on="name"))
  employee        group
0      Bob   Accounting
1     Jake  Engineering
2     Lisa  Engineering
3      Sue           HR
  employee  hire_date
0      Bob       2004
1     Jake       2008
2     Lisa       2012
3      Sue       2014
  employee        group  name  salary
0      Bob   Accounting   Bob    7000
1     Jake  Engineering  Jake    8000
2     Lisa  Engineering  Lisa   12000
3      Sue           HR   Sue   90000

还可以索引合并:

In [25]: df1a = df1.set_index('employee')

In [26]: df2a = df2.set_index('employee')

In [27]: print(df1a);print(df2a);print(pd.merge(df1a,df2a,left_index=True, right_index=True))
                group
employee             
Bob        Accounting
Jake      Engineering
Lisa      Engineering
Sue                HR
          hire_date
employee           
Bob            2004
Jake           2008
Lisa           2012
Sue            2014
                group  hire_date
employee                        
Bob        Accounting       2004
Jake      Engineering       2008
Lisa      Engineering       2012
Sue                HR       2014

当然也可以混用:

In [28]: pd.merge(df1a,df3,left_index=True, right_on='name')
Out[28]: 
         group  name  salary
0   Accounting   Bob    7000
1  Engineering  Jake    8000
2  Engineering  Lisa   12000
3           HR   Sue   90000

设置数据连接的集合操作规则

默认情况下,merge是用inner join内连接,我们可以用how来控制(outer,left,right)

In [29]: df6=pd.DataFrame({'name':['Peter','Paul','Mary'], 'food':['fish', 'beans','bread']})

In [30]: df7=pd.DataFrame({'name':['Mary','Joseph'], 'drink':['wine', 'beer']})

In [31]: pd.merge(df6,df7)
Out[31]: 
   name   food drink
0  Mary  bread  wine

In [32]: pd.merge(df6,df7, how='outer')
Out[32]: 
     name   food drink
0   Peter   fish   NaN
1    Paul  beans   NaN
2    Mary  bread  wine
3  Joseph    NaN  beer

列重名:suffixes参数

In [33]: df8=pd.DataFrame({'name':['Bob','Jake','Lisa','Sue'], 'rank':[1,2,3,4]})

In [34]: df9 = pd.DataFrame({'name':['Bob','Jake', 'Lisa', 'Sue'], 'rank':[3,1,4,2]})

In [35]: print(pd.merge(df8,df9, on="name"))
   name  rank_x  rank_y
0   Bob       1       3
1  Jake       2       1
2  Lisa       3       4
3   Sue       4       2

因为两个都有重复列名,所以默认加_x和_y,我们也可以通过suffixes定义后缀名:

n [36]: print(pd.merge(df8, df9, on='name',suffixes=["_L",'_R']))
   name  rank_L  rank_R
0   Bob       1       3
1  Jake       2       1
2  Lisa       3       4
3   Sue       4       2

GroupBy:分割、应用和组合

GroupBy可以理解为:先分割再应用函数最后组合,类似SQL

数据透视表

透视表可以理解为多维的GroupBy累计操作

df.pivot_table('column', index='[index_name]', columns='[col_name]') # column表示你要的列,index_name表示作为行的列名,columns表示列的名字

处理时间序列

python日期与时间工具

基本的日期与时间功能在标准库的datetime模块中。

In [1]: from datetime import datetime

In [2]: datetime(year=2023,month=7,day=25)
Out[2]: datetime.datetime(2023, 7, 25, 0, 0)

可以用dateutil模块对各种字符串格式的日期进行正确解析:

In [3]: from dateutil import parser

In [4]: date = parser.parse("25th of July, 2023")

In [5]: date.strftime("%A")
Out[5]: 'Tuesday'

Pandas的日期与时间工具

pandas所有关于日期与时间的处理方法全部都是通过Timestamp对象实现的。

In [7]: date = pd.to_datetime("25th of July, 2023")

In [8]: date
Out[8]: Timestamp('2023-07-25 00:00:00')

也可以直接进行Numpy类型的向量化运算

In [12]: date + pd.to_timedelta(np.arange(12), 'D')
Out[12]: 
DatetimeIndex(['2023-07-25', '2023-07-26', '2023-07-27', '2023-07-28',
               '2023-07-29', '2023-07-30', '2023-07-31', '2023-08-01',
               '2023-08-02', '2023-08-03', '2023-08-04', '2023-08-05'],
              dtype='datetime64[ns]', freq=None)

Pandas时间序列:用时间作索引

pandas可以用来处理带时间戳的索引数据

In [13]: index = pd.DatetimeIndex(["2023-08-01","2023-08-02"])

In [14]: data = pd.Series([0,1], index=index)

In [15]: data
Out[15]: 
2023-08-01    0
2023-08-02    1
dtype: int64

可以用索引来切片取值。

Pandas时间序列数据结构

最基础的日期/时间对象是Timestamp和DatetimeIndex,最常用的是pd.to_datetime() 解析日期与时间格式,返回timestamp类型,传递一个时间序列就会返回DatetimeIndex类型。

pd.date_range 可以创建有规律的时间序列。

重新取样、迁移窗口

可以用resample()asfreq() 方法。resample是以数据累计为基础,asfreq是以数据选择shift() 进行迁移数据,tshift() 迁移索引。rolling 返回类似groupby结果,移动视图使得许多累计操作成为可能。

posted on 2024-01-28 22:45  复古猴子  阅读(15)  评论(0编辑  收藏  举报

导航