分享

Python学习笔记

 hoezigin 2019-03-22

目录

什么是Pandas?

Pandas常用操作

pandas之Series创建

pandas之Series的索引和值

pandas之读取外部数据

pandas之DataFrame

pandas之取行或者列

pandas之loc

pandas之iloc

pandas之布尔索引

pandas之字符串方法

缺失数据的处理

pandas常用统计方法

数据合并之join

数据合并之merge

分组和聚合

索引和复合索引

Series复合索引

DataFrame复合索引

时间序列

生成一段时间范围

关于频率的更多缩写

在DataFrame中使用时间序列

pandas重采样

PeriodIndex

Pandas的数据结构

Series

DataFrame

Pandas的索引操作

索引对象Index

Series索引

DataFrame索引

高级索引:标签、位置和混合

Pandas的对齐运算

Series的对齐运算

DataFrame的对齐运算

填充未对齐的数据进行运算

Pandas的函数应用

apply 和 applymap

排序

处理缺失数据

层级索引(hierarchical indexing)

MultiIndex索引对象

选取子集

交换分层顺序

交换并排序分层

Pandas统计计算和描述

常用的统计计算

常用的统计描述

常用的统计描述方法:

Pandas分组与聚合

分组 (groupby)

一、GroupBy对象:DataFrameGroupBy,SeriesGroupBy

二、GroupBy对象支持迭代操作

聚合 (aggregation)

数据的分组运算

groupby.apply(func)

数据清洗

数据连接(pd.merge)

数据合并(pd.concat)

数据重构

数据转换

一、 处理重复数据

二、数据替换

聚类模型:K-Means

K-Means算法

算法思想:

算法描述:

优缺点:

全球食品数据分析


什么是Pandas?

Pandas的名称来自于面板数据(panel data)和Python数据分析(data analysis)。

Pandas是一个强大的分析结构化数据的工具集,基于NumPy构建,提供了 高级数据结构 和 数据操作工具,它是使Python成为强大而高效的数据分析环境的重要因素之一。

  • 一个强大的分析和操作大型结构化数据集所需的工具集

  • 基础是NumPy,提供了高性能矩阵的运算

  • 提供了大量能够快速便捷地处理数据的函数和方法

  • 应用于数据挖掘,数据分析

  • 提供数据清洗功能

http://pandas.

Pandas常用操作

pandas之Series创建

pandas之Series创建

pandas之Series的索引和值

pandas之读取外部数据

数据存在csv中,直接使用pd. read_csv即可

对于数据库比如mysql或者mongodb中数据pd.read_sql(sql_sentence,connection)

pandas之DataFrame

DataFrame对象既有行索引,又有列索引

行索引,表明不同行,横向索引,叫index,0轴,axis=0

列索引,表名不同列,纵向索引,叫columns,1轴,axis=1

df.sort_values(by="Count_AnimalName",ascending=False) #排序

pandas之取行或者列

df_sorted = df.sort_values(by="Count_AnimalName")

df_sorted[:100]

那么问题来了:

我们具体要选择某一列该怎么选择呢?df[" Count_AnimalName "]

我们要同时选择行和列改怎么办?df[:100][" Count_AnimalName "]

pandas之loc

还有更多的经过pandas优化过的选择方式:

1.df.loc 通过标签索引行数据

2.df.iloc 通过位置获取行数据

pandas之iloc

赋值更改数据的过程:

pandas之布尔索引

pandas之字符串方法

缺失数据的处理

我们的数据缺失通常有两种情况:

一种就是空,None等,在pandas是NaN(和np.nan一样)

另一种是我们让其为0,蓝色框中

对于NaN的数据,在numpy中我们是如何处理的?

在pandas中我们处理起来非常容易

 

判断数据是否为NaN:pd.isnull(df),pd.notnull(df)

 

处理方式1:删除NaN所在的行列dropna (axis=0, how='any', inplace=False)

处理方式2:填充数据,t.fillna(t.mean()),t.fiallna(t.median()),t.fillna(0)

 

处理为0的数据:t[t==0]=np.nan

当然并不是每次为0的数据都需要处理

计算平均值等情况,nan是不参与计算的,但是0会

pandas常用统计方法

数据合并之join

join:默认情况下他是把行索引相同的数据合并到一起

数据合并之merge

默认的合并方式inner,并集

merge outer,交集,NaN补全

merge left,左边为准,NaN补全

merge right,右边为准,NaN补全

分组和聚合

在pandas中类似的分组的操作我们有很简单的方式来完成

df.groupby(by="columns_name")

那么问题来了,调用groupby方法之后返回的是什么内容?

grouped = df.groupby(by="columns_name")

grouped是一个DataFrameGroupBy对象,是可迭代的

grouped中的每一个元素是一个元组

元组里面是(索引(分组的值),分组之后的DataFrame)

那么,回到之前的问题:

要统计美国和中国的星巴克的数量,我们应该怎么做?

分组之后的每个DataFrame的长度?

长度是一个思路,但是我们有更多的方法(聚合方法)来解决这个问题

DataFrameGroupBy对象有很多经过优化的方法

如果我们需要对国家和省份进行分组统计,应该怎么操作呢?

grouped = df.groupby(by=[df["Country"],df["State/Province"]])

很多时候我们只希望对获取分组之后的某一部分数据,或者说我们只希望对某几列数据进行分组,这个时候我们应该怎么办呢?

获取分组之后的某一部分数据:

 df.groupby(by=["Country","State/Province"])["Country"].count()

对某几列数据进行分组:

 df["Country"].groupby(by=[df["Country"],df["State/Province"]]).count()

观察结果,由于只选择了一列数据,所以结果是一个Series类型

如果我想返回一个DataFrame类型呢?

t1 = df[["Country"]].groupby(by=[df["Country"],df["State/Province"]]).count()
t2 = df.groupby(by=["Country","State/Province"])[["Country"]].count()

以上的两条命令结果一样

和之前的结果的区别在于当前返回的是一个DataFrame类型

那么问题来了:

和之前使用一个分组条件相比,当前的返回结果的前两列是什么?

索引和复合索引

简单的索引操作:

·获取index:df.index

·指定index :df.index = ['x','y']

·重新设置index : df.reindex(list("abcedf"))

·指定某一列作为index :df.set_index("Country",drop=False)

·返回index的唯一值:df.set_index("Country").index.unique()

假设a为一个DataFrame,那么当a.set_index(["c","d"])即设置两个索引的时候是什么样子的结果呢?

a = pd.DataFrame({'a': range(7),'b': range(7, 0, -1),'c': ['one','one','one','two','two','two', 'two'],'d': list("hjklmno")})

Series复合索引

DataFrame复合索引

时间序列

生成一段时间范围

pd.date_range(start=None, end=None, periods=None, freq='D')

start和end以及freq配合能够生成startend范围内以频率freq的一组时间索引

start和periods以及freq配合能够生成从start开始的频率为freq的periods时间索引

关于频率的更多缩写

在DataFrame中使用时间序列

index=pd.date_range("20170101",periods=10)

df = pd.DataFrame(np.random.rand(10),index=index)

回到最开始的911数据的案例中,我们可以使用pandas提供的方法把时间字符串转化为时间序列

df["timeStamp"] = pd.to_datetime(df["timeStamp"],format="")

format参数大部分情况下可以不用写,但是对于pandas无法格式化的时间字符串,我们可以使用该参数,比如包含中文

那么问题来了:

我们现在要统计每个月或者每个季度的次数怎么办呢?

pandas重采样

重采样:指的是将时间序列从一个频率转化为另一个频率进行处理的过程,将高频率数据转化为低频率数据为降采样,低频率转化为高频率为升采样

pandas提供了一个resample的方法来帮助我们实现频率转化

PeriodIndex

之前所学习的DatetimeIndex可以理解为时间戳

那么现在我们要学习的PeriodIndex可以理解为时间段

periods = pd.PeriodIndex(year=data["year"],month=data["month"],day=data["day"],hour=data["hour"],freq="H")

那么如果给这个时间段降采样呢?
data = df.set_index(periods).resample("10D").mean()

Pandas的数据结构

import pandas as pd

Pandas有两个最主要也是最重要的数据结构: Series 和 DataFrame

Series

Series是一种类似于一维数组的 对象,由一组数据(各种NumPy数据类型)以及一组与之对应的索引(数据标签)组成。

  • 类似一维数组的对象
  • 由数据和索引组成
    • 索引(index)在左,数据(values)在右
    • 索引是自动创建的

1. 通过list构建Series

ser_obj = pd.Series(range(10))

示例代码:

  1. # 通过list构建Series
  2. ser_obj = pd.Series(range(10, 20))
  3. print(ser_obj.head(3))
  4. print(ser_obj)
  5. print(type(ser_obj))

运行结果:

  1. 0 10
  2. 1 11
  3. 2 12
  4. dtype: int64
  5. 0 10
  6. 1 11
  7. 2 12
  8. 3 13
  9. 4 14
  10. 5 15
  11. 6 16
  12. 7 17
  13. 8 18
  14. 9 19
  15. dtype: int64
  16. <class 'pandas.core.series.Series'>

2. 获取数据和索引

ser_obj.index 和 ser_obj.values

示例代码:

  1. # 获取数据
  2. print(ser_obj.values)
  3. # 获取索引
  4. print(ser_obj.index)

运行结果:

  1. [10 11 12 13 14 15 16 17 18 19]
  2. RangeIndex(start=0, stop=10, step=1)

3. 通过索引获取数据

ser_obj[idx]

示例代码:

  1. #通过索引获取数据
  2. print(ser_obj[0])
  3. print(ser_obj[8])

运行结果:

  1. 10
  2. 18

4. 索引与数据的对应关系不被运算结果影响

示例代码:

  1. # 索引与数据的对应关系不被运算结果影响
  2. print(ser_obj * 2)
  3. print(ser_obj > 15)

运行结果:

  1. 0 20
  2. 1 22
  3. 2 24
  4. 3 26
  5. 4 28
  6. 5 30
  7. 6 32
  8. 7 34
  9. 8 36
  10. 9 38
  11. dtype: int64
  12. 0 False
  13. 1 False
  14. 2 False
  15. 3 False
  16. 4 False
  17. 5 False
  18. 6 True
  19. 7 True
  20. 8 True
  21. 9 True
  22. dtype: bool

5. 通过dict构建Series

示例代码:

  1. # 通过dict构建Series
  2. year_data = {2001: 17.8, 2002: 20.1, 2003: 16.5}
  3. ser_obj2 = pd.Series(year_data)
  4. print(ser_obj2.head())
  5. print(ser_obj2.index)

运行结果:

  1. 2001 17.8
  2. 2002 20.1
  3. 2003 16.5
  4. dtype: float64
  5. Int64Index([2001, 2002, 2003], dtype='int64')

name属性

对象名:ser_obj.name

对象索引名:ser_obj.index.name

示例代码:

  1. # name属性
  2. ser_obj2.name = 'temp'
  3. ser_obj2.index.name = 'year'
  4. print(ser_obj2.head())

运行结果:

  1. year
  2. 2001 17.8
  3. 2002 20.1
  4. 2003 16.5
  5. Name: temp, dtype: float64


DataFrame

DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同类型的值。DataFrame既有行索引也有列索引,它可以被看做是由Series组成的字典(共用同一个索引),数据是以二维结构存放的。

  • 类似多维数组/表格数据 (如,excel, R中的data.frame)
  • 每列数据可以是不同的类型
  • 索引包括列索引和行索引

1. 通过ndarray构建DataFrame

示例代码:

  1. import numpy as np
  2. # 通过ndarray构建DataFrame
  3. array = np.random.randn(5,4)
  4. print(array)
  5. df_obj = pd.DataFrame(array)
  6. print(df_obj.head())

运行结果:

  1. [[ 0.83500594 -1.49290138 -0.53120106 -0.11313932]
  2. [ 0.64629762 -0.36779941 0.08011084 0.60080495]
  3. [-1.23458522 0.33409674 -0.58778195 -0.73610573]
  4. [-1.47651414 0.99400187 0.21001995 -0.90515656]
  5. [ 0.56669419 1.38238348 -0.49099007 1.94484598]]
  6. 0 1 2 3
  7. 0 0.835006 -1.492901 -0.531201 -0.113139
  8. 1 0.646298 -0.367799 0.080111 0.600805
  9. 2 -1.234585 0.334097 -0.587782 -0.736106
  10. 3 -1.476514 0.994002 0.210020 -0.905157
  11. 4 0.566694 1.382383 -0.490990 1.944846

2. 通过dict构建DataFrame

示例代码:

  1. # 通过dict构建DataFrame
  2. dict_data = {'A': 1,
  3. 'B': pd.Timestamp('20170426'),
  4. 'C': pd.Series(1, index=list(range(4)),dtype='float32'),
  5. 'D': np.array([3] * 4,dtype='int32'),
  6. 'E': ["Python","Java","C++","C"],
  7. 'F': 'ITCast' }
  8. #print dict_data
  9. df_obj2 = pd.DataFrame(dict_data)
  10. print(df_obj2)

运行结果:

  1. A B C D E F
  2. 0 1 2017-04-26 1.0 3 Python ITCast
  3. 1 1 2017-04-26 1.0 3 Java ITCast
  4. 2 1 2017-04-26 1.0 3 C++ ITCast
  5. 3 1 2017-04-26 1.0 3 C ITCast

3. 通过列索引获取列数据(Series类型)

df_obj[col_idx] 或 df_obj.col_idx

示例代码:

  1. # 通过列索引获取列数据
  2. print(df_obj2['A'])
  3. print(type(df_obj2['A']))
  4. print(df_obj2.A)

运行结果:

  1. 0 1.0
  2. 1 1.0
  3. 2 1.0
  4. 3 1.0
  5. Name: A, dtype: float64
  6. <class 'pandas.core.series.Series'>
  7. 0 1.0
  8. 1 1.0
  9. 2 1.0
  10. 3 1.0
  11. Name: A, dtype: float64

4. 增加列数据

df_obj[new_col_idx] = data

类似Python的 dict添加key-value

示例代码:

  1. # 增加列
  2. df_obj2['G'] = df_obj2['D'] + 4
  3. print(df_obj2.head())

运行结果:

  1. A B C D E F G
  2. 0 1.0 2017-01-02 1.0 3 Python ITCast 7
  3. 1 1.0 2017-01-02 1.0 3 Java ITCast 7
  4. 2 1.0 2017-01-02 1.0 3 C++ ITCast 7
  5. 3 1.0 2017-01-02 1.0 3 C ITCast 7

5. 删除列

del df_obj[col_idx]

示例代码:

  1. # 删除列
  2. del(df_obj2['G'] )
  3. print(df_obj2.head())

运行结果:

  1. A B C D E F
  2. 0 1.0 2017-01-02 1.0 3 Python ITCast
  3. 1 1.0 2017-01-02 1.0 3 Java ITCast
  4. 2 1.0 2017-01-02 1.0 3 C++ ITCast
  5. 3 1.0 2017-01-02 1.0 3 C ITCast

Pandas的索引操作

索引对象Index

1. Series和DataFrame中的索引都是Index对象

示例代码:

  1. print(type(ser_obj.index))
  2. print(type(df_obj2.index))
  3. print(df_obj2.index)

运行结果:

  1. <class 'pandas.indexes.range.RangeIndex'>
  2. <class 'pandas.indexes.numeric.Int64Index'>
  3. Int64Index([0, 1, 2, 3], dtype='int64')

2. 索引对象不可变,保证了数据的安全

示例代码:

  1. # 索引对象不可变
  2. df_obj2.index[0] = 2

运行结果:

  1. ---------------------------------------------------------------------------
  2. TypeError Traceback (most recent call last)
  3. <ipython-input-23-7f40a356d7d1> in <module>()
  4. 1 # 索引对象不可变
  5. ----> 2 df_obj2.index[0] = 2
  6. /Users/Power/anaconda/lib/python3.6/site-packages/pandas/indexes/base.py in __setitem__(self, key, value)
  7. 1402
  8. 1403 def __setitem__(self, key, value):
  9. -> 1404 raise TypeError("Index does not support mutable operations")
  10. 1405
  11. 1406 def __getitem__(self, key):
  12. TypeError: Index does not support mutable operations

常见的Index种类

  • Index,索引
  • Int64Index,整数索引
  • MultiIndex,层级索引
  • DatetimeIndex,时间戳类型

Series索引

1. index 指定行索引名

示例代码:

  1. ser_obj = pd.Series(range(5), index = ['a', 'b', 'c', 'd', 'e'])
  2. print(ser_obj.head())

运行结果:

  1. a 0
  2. b 1
  3. c 2
  4. d 3
  5. e 4
  6. dtype: int64

2. 行索引

ser_obj[‘label’], ser_obj[pos]

示例代码:

  1. # 行索引
  2. print(ser_obj['b'])
  3. print(ser_obj[2])

运行结果:

  1. 1
  2. 2

3. 切片索引

ser_obj[2:4], ser_obj[‘label1’: ’label3’]

注意,按索引名切片操作时,是包含终止索引的。

示例代码:

  1. # 切片索引
  2. print(ser_obj[1:3])
  3. print(ser_obj['b':'d'])

运行结果:

  1. b 1
  2. c 2
  3. dtype: int64
  4. b 1
  5. c 2
  6. d 3
  7. dtype: int64

4. 不连续索引

ser_obj[[‘label1’, ’label2’, ‘label3’]]

示例代码:

  1. # 不连续索引
  2. print(ser_obj[[0, 2, 4]])
  3. print(ser_obj[['a', 'e']])

运行结果:

  1. a 0
  2. c 2
  3. e 4
  4. dtype: int64
  5. a 0
  6. e 4
  7. dtype: int64

5. 布尔索引

示例代码:

  1. # 布尔索引
  2. ser_bool = ser_obj > 2
  3. print(ser_bool)
  4. print(ser_obj[ser_bool])
  5. print(ser_obj[ser_obj > 2])

运行结果:

  1. a False
  2. b False
  3. c False
  4. d True
  5. e True
  6. dtype: bool
  7. d 3
  8. e 4
  9. dtype: int64
  10. d 3
  11. e 4
  12. dtype: int64

DataFrame索引

1. columns 指定列索引名

示例代码:

  1. import numpy as np
  2. df_obj = pd.DataFrame(np.random.randn(5,4), columns = ['a', 'b', 'c', 'd'])
  3. print(df_obj.head())

运行结果:

  1. a b c d
  2. 0 -0.241678 0.621589 0.843546 -0.383105
  3. 1 -0.526918 -0.485325 1.124420 -0.653144
  4. 2 -1.074163 0.939324 -0.309822 -0.209149
  5. 3 -0.716816 1.844654 -2.123637 -1.323484
  6. 4 0.368212 -0.910324 0.064703 0.486016

2. 列索引

df_obj[[‘label’]]

示例代码:

  1. # 列索引
  2. print(df_obj['a']) # 返回Series类型
  3. print(df_obj[[0]]) # 返回DataFrame类型
  4. print(type(df_obj[[0]])) # 返回DataFrame类型

运行结果:

  1. 0 -0.241678
  2. 1 -0.526918
  3. 2 -1.074163
  4. 3 -0.716816
  5. 4 0.368212
  6. Name: a, dtype: float64
  7. <class 'pandas.core.frame.DataFrame'>

3. 不连续索引

df_obj[[‘label1’, ‘label2’]]

示例代码:

  1. # 不连续索引
  2. print(df_obj[['a','c']])
  3. print(df_obj[[1, 3]])

运行结果:

  1. a c
  2. 0 -0.241678 0.843546
  3. 1 -0.526918 1.124420
  4. 2 -1.074163 -0.309822
  5. 3 -0.716816 -2.123637
  6. 4 0.368212 0.064703
  7. b d
  8. 0 0.621589 -0.383105
  9. 1 -0.485325 -0.653144
  10. 2 0.939324 -0.209149
  11. 3 1.844654 -1.323484
  12. 4 -0.910324 0.486016

高级索引:标签、位置和混合

Pandas的高级索引有3种

1. loc 标签索引

DataFrame 不能直接切片,可以通过loc来做切片

loc是基于标签名的索引,也就是我们自定义的索引名

示例代码:

  1. # 标签索引 loc
  2. # Series
  3. print(ser_obj['b':'d'])
  4. print(ser_obj.loc['b':'d'])
  5. # DataFrame
  6. print(df_obj['a'])
  7. # 第一个参数索引行,第二个参数是列
  8. print(df_obj.loc[0:2, 'a'])

运行结果:

  1. b 1
  2. c 2
  3. d 3
  4. dtype: int64
  5. b 1
  6. c 2
  7. d 3
  8. dtype: int64
  9. 0 -0.241678
  10. 1 -0.526918
  11. 2 -1.074163
  12. 3 -0.716816
  13. 4 0.368212
  14. Name: a, dtype: float64
  15. 0 -0.241678
  16. 1 -0.526918
  17. 2 -1.074163
  18. Name: a, dtype: float64

2. iloc 位置索引

作用和loc一样,不过是基于索引编号来索引

示例代码:

  1. # 整型位置索引 iloc
  2. # Series
  3. print(ser_obj[1:3])
  4. print(ser_obj.iloc[1:3])
  5. # DataFrame
  6. print(df_obj.iloc[0:2, 0]) # 注意和df_obj.loc[0:2, 'a']的区别

运行结果:

  1. b 1
  2. c 2
  3. dtype: int64
  4. b 1
  5. c 2
  6. dtype: int64
  7. 0 -0.241678
  8. 1 -0.526918
  9. Name: a, dtype: float64

3. ix 标签与位置混合索引

ix是以上二者的综合,既可以使用索引编号,又可以使用自定义索引,要视情况不同来使用,

如果索引既有数字又有英文,那么这种方式是不建议使用的,容易导致定位的混乱。

示例代码:

  1. # 混合索引 ix
  2. # Series
  3. print(ser_obj.ix[1:3])
  4. print(ser_obj.ix['b':'c'])
  5. # DataFrame
  6. print(df_obj.loc[0:2, 'a'])
  7. print(df_obj.ix[0:2, 0])

运行结果:

  1. b 1
  2. c 2
  3. dtype: int64
  4. b 1
  5. c 2
  6. dtype: int64
  7. 0 -0.241678
  8. 1 -0.526918
  9. 2 -1.074163
  10. Name: a, dtype: float64

注意

DataFrame索引操作,可将其看作ndarray的索引操作

标签的切片索引是包含末尾位置的

Pandas的对齐运算

是数据清洗的重要过程,可以按索引对齐进行运算,如果没对齐的位置则补NaN,最后也可以填充NaN

Series的对齐运算

1. Series 按行、索引对齐

示例代码:

  1. s1 = pd.Series(range(10, 20), index = range(10))
  2. s2 = pd.Series(range(20, 25), index = range(5))
  3. print('s1: ' )
  4. print(s1)
  5. print('')
  6. print('s2: ')
  7. print(s2)

运行结果:

  1. s1:
  2. 0 10
  3. 1 11
  4. 2 12
  5. 3 13
  6. 4 14
  7. 5 15
  8. 6 16
  9. 7 17
  10. 8 18
  11. 9 19
  12. dtype: int64
  13. s2:
  14. 0 20
  15. 1 21
  16. 2 22
  17. 3 23
  18. 4 24
  19. dtype: int64

2. Series的对齐运算

示例代码:

  1. # Series 对齐运算
  2. s1 + s2

运行结果:

  1. 0 30.0
  2. 1 32.0
  3. 2 34.0
  4. 3 36.0
  5. 4 38.0
  6. 5 NaN
  7. 6 NaN
  8. 7 NaN
  9. 8 NaN
  10. 9 NaN
  11. dtype: float64

DataFrame的对齐运算

1. DataFrame按行、列索引对齐

示例代码:

  1. df1 = pd.DataFrame(np.ones((2,2)), columns = ['a', 'b'])
  2. df2 = pd.DataFrame(np.ones((3,3)), columns = ['a', 'b', 'c'])
  3. print('df1: ')
  4. print(df1)
  5. print('')
  6. print('df2: ')
  7. print(df2)

运行结果:

  1. df1:
  2. a b
  3. 0 1.0 1.0
  4. 1 1.0 1.0
  5. df2:
  6. a b c
  7. 0 1.0 1.0 1.0
  8. 1 1.0 1.0 1.0
  9. 2 1.0 1.0 1.0

2. DataFrame的对齐运算

示例代码:

  1. # DataFrame对齐操作
  2. df1 + df2

运行结果:

  1. a b c
  2. 0 2.0 2.0 NaN
  3. 1 2.0 2.0 NaN
  4. 2 NaN NaN NaN

填充未对齐的数据进行运算

1. fill_value

使用addsubdivmul的同时,

通过fill_value指定填充值,未对齐的数据将和填充值做运算

示例代码:

  1. print(s1)
  2. print(s2)
  3. s1.add(s2, fill_value = -1)
  4. print(df1)
  5. print(df2)
  6. df1.sub(df2, fill_value = 2.)

运行结果:

  1. # print(s1)
  2. 0 10
  3. 1 11
  4. 2 12
  5. 3 13
  6. 4 14
  7. 5 15
  8. 6 16
  9. 7 17
  10. 8 18
  11. 9 19
  12. dtype: int64
  13. # print(s2)
  14. 0 20
  15. 1 21
  16. 2 22
  17. 3 23
  18. 4 24
  19. dtype: int64
  20. # s1.add(s2, fill_value = -1)
  21. 0 30.0
  22. 1 32.0
  23. 2 34.0
  24. 3 36.0
  25. 4 38.0
  26. 5 14.0
  27. 6 15.0
  28. 7 16.0
  29. 8 17.0
  30. 9 18.0
  31. dtype: float64
  32. # print(df1)
  33. a b
  34. 0 1.0 1.0
  35. 1 1.0 1.0
  36. # print(df2)
  37. a b c
  38. 0 1.0 1.0 1.0
  39. 1 1.0 1.0 1.0
  40. 2 1.0 1.0 1.0
  41. # df1.sub(df2, fill_value = 2.)
  42. a b c
  43. 0 0.0 0.0 1.0
  44. 1 0.0 0.0 1.0
  45. 2 1.0 1.0 1.0

Pandas的函数应用

apply 和 applymap

1. 可直接使用NumPy的函数

示例代码:

  1. # Numpy ufunc 函数
  2. df = pd.DataFrame(np.random.randn(5,4) - 1)
  3. print(df)
  4. print(np.abs(df))

运行结果:

  1. 0 1 2 3
  2. 0 -0.062413 0.844813 -1.853721 -1.980717
  3. 1 -0.539628 -1.975173 -0.856597 -2.612406
  4. 2 -1.277081 -1.088457 -0.152189 0.530325
  5. 3 -1.356578 -1.996441 0.368822 -2.211478
  6. 4 -0.562777 0.518648 -2.007223 0.059411
  7. 0 1 2 3
  8. 0 0.062413 0.844813 1.853721 1.980717
  9. 1 0.539628 1.975173 0.856597 2.612406
  10. 2 1.277081 1.088457 0.152189 0.530325
  11. 3 1.356578 1.996441 0.368822 2.211478
  12. 4 0.562777 0.518648 2.007223 0.059411

2. 通过apply将函数应用到列或行上

示例代码:

  1. # 使用apply应用行或列数据
  2. #f = lambda x : x.max()
  3. print(df.apply(lambda x : x.max()))

运行结果:

  1. 0 -0.062413
  2. 1 0.844813
  3. 2 0.368822
  4. 3 0.530325
  5. dtype: float64

注意指定轴的方向,默认axis=0,方向是列

示例代码:

  1. # 指定轴方向,axis=1,方向是行
  2. print(df.apply(lambda x : x.max(), axis=1))

运行结果:

  1. 0 0.844813
  2. 1 -0.539628
  3. 2 0.530325
  4. 3 0.368822
  5. 4 0.518648
  6. dtype: float64

3. 通过applymap将函数应用到每个数据上

示例代码:

  1. # 使用applymap应用到每个数据
  2. f2 = lambda x : '%.2f' % x
  3. print(df.applymap(f2))

运行结果:

  1. 0 1 2 3
  2. 0 -0.06 0.84 -1.85 -1.98
  3. 1 -0.54 -1.98 -0.86 -2.61
  4. 2 -1.28 -1.09 -0.15 0.53
  5. 3 -1.36 -2.00 0.37 -2.21
  6. 4 -0.56 0.52 -2.01 0.06

排序

1. 索引排序

sort_index()

排序默认使用升序排序,ascending=False 为降序排序

示例代码:

  1. # Series
  2. s4 = pd.Series(range(10, 15), index = np.random.randint(5, size=5))
  3. print(s4)
  4. # 索引排序
  5. s4.sort_index() # 0 0 1 3 3

运行结果:

  1. 0 10
  2. 3 11
  3. 1 12
  4. 3 13
  5. 0 14
  6. dtype: int64
  7. 0 10
  8. 0 14
  9. 1 12
  10. 3 11
  11. 3 13
  12. dtype: int64

对DataFrame操作时注意轴方向

示例代码:

  1. # DataFrame
  2. df4 = pd.DataFrame(np.random.randn(3, 5),
  3. index=np.random.randint(3, size=3),
  4. columns=np.random.randint(5, size=5))
  5. print(df4)
  6. df4_isort = df4.sort_index(axis=1, ascending=False)
  7. print(df4_isort) # 4 2 1 1 0

运行结果:

  1. 1 4 0 1 2
  2. 2 -0.416686 -0.161256 0.088802 -0.004294 1.164138
  3. 1 -0.671914 0.531256 0.303222 -0.509493 -0.342573
  4. 1 1.988321 -0.466987 2.787891 -1.105912 0.889082
  5. 4 2 1 1 0
  6. 2 -0.161256 1.164138 -0.416686 -0.004294 0.088802
  7. 1 0.531256 -0.342573 -0.671914 -0.509493 0.303222
  8. 1 -0.466987 0.889082 1.988321 -1.105912 2.787891

2. 按值排序

sort_values(by='column name')

根据某个唯一的列名进行排序,如果有其他相同列名则报错。

示例代码:

  1. # 按值排序
  2. df4_vsort = df4.sort_values(by=0, ascending=False)
  3. print(df4_vsort)

运行结果:

  1. 1 4 0 1 2
  2. 1 1.988321 -0.466987 2.787891 -1.105912 0.889082
  3. 1 -0.671914 0.531256 0.303222 -0.509493 -0.342573
  4. 2 -0.416686 -0.161256 0.088802 -0.004294 1.164138

处理缺失数据

示例代码:

  1. df_data = pd.DataFrame([np.random.randn(3), [1., 2., np.nan],
  2. [np.nan, 4., np.nan], [1., 2., 3.]])
  3. print(df_data.head())

运行结果:

  1. 0 1 2
  2. 0 -0.281885 -0.786572 0.487126
  3. 1 1.000000 2.000000 NaN
  4. 2 NaN 4.000000 NaN
  5. 3 1.000000 2.000000 3.000000

1. 判断是否存在缺失值:isnull()

示例代码:

  1. # isnull
  2. print(df_data.isnull())

运行结果:

  1. 0 1 2
  2. 0 False False False
  3. 1 False False True
  4. 2 True False True
  5. 3 False False False

2. 丢弃缺失数据:dropna()

根据axis轴方向,丢弃包含NaN的行或列。 示例代码:

  1. # dropna
  2. print(df_data.dropna())
  3. print(df_data.dropna(axis=1))

运行结果:

  1. 0 1 2
  2. 0 -0.281885 -0.786572 0.487126
  3. 3 1.000000 2.000000 3.000000
  4. 1
  5. 0 -0.786572
  6. 1 2.000000
  7. 2 4.000000
  8. 3 2.000000

3. 填充缺失数据:fillna()

示例代码:

  1. # fillna
  2. print(df_data.fillna(-100.))

运行结果:

  1. 0 1 2
  2. 0 -0.281885 -0.786572 0.487126
  3. 1 1.000000 2.000000 -100.000000
  4. 2 -100.000000 4.000000 -100.000000
  5. 3 1.000000 2.000000 3.000000

层级索引(hierarchical indexing)

下面创建一个Series, 在输入索引Index时,输入了由两个子list组成的list,第一个子list是外层索引,第二个list是内层索引。

示例代码:

  1. import pandas as pd
  2. import numpy as np
  3. ser_obj = pd.Series(np.random.randn(12),index=[
  4. ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'],
  5. [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]
  6. ])
  7. print(ser_obj)

运行结果:

  1. a 0 0.099174
  2. 1 -0.310414
  3. 2 -0.558047
  4. b 0 1.742445
  5. 1 1.152924
  6. 2 -0.725332
  7. c 0 -0.150638
  8. 1 0.251660
  9. 2 0.063387
  10. d 0 1.080605
  11. 1 0.567547
  12. 2 -0.154148
  13. dtype: float64

MultiIndex索引对象

  • 打印这个Series的索引类型,显示是MultiIndex

  • 直接将索引打印出来,可以看到有lavels,和labels两个信息。lavels表示两个层级中分别有那些标签,labels是每个位置分别是什么标签。

示例代码:

  1. print(type(ser_obj.index))
  2. print(ser_obj.index)

运行结果:

  1. <class 'pandas.indexes.multi.MultiIndex'>
  2. MultiIndex(levels=[['a', 'b', 'c', 'd'], [0, 1, 2]],
  3. labels=[[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])

选取子集

  • 根据索引获取数据。因为现在有两层索引,当通过外层索引获取数据的时候,可以直接利用外层索引的标签来获取。

  • 当要通过内层索引获取数据的时候,在list中传入两个元素,前者是表示要选取的外层索引,后者表示要选取的内层索引。

1. 外层选取:

ser_obj['outer_label']

示例代码:

  1. # 外层选取
  2. print(ser_obj['c'])

运行结果:

  1. 0 -1.362096
  2. 1 1.558091
  3. 2 -0.452313
  4. dtype: float64

2. 内层选取:

ser_obj[:, 'inner_label']

示例代码:

  1. # 内层选取
  2. print(ser_obj[:, 2])

运行结果:

  1. a 0.826662
  2. b 0.015426
  3. c -0.452313
  4. d -0.051063
  5. dtype: float64

常用于分组操作、透视表的生成等

交换分层顺序

1. swaplevel()

.swaplevel( )交换内层与外层索引。

示例代码:

print(ser_obj.swaplevel())

运行结果:

  1. 0 a 0.099174
  2. 1 a -0.310414
  3. 2 a -0.558047
  4. 0 b 1.742445
  5. 1 b 1.152924
  6. 2 b -0.725332
  7. 0 c -0.150638
  8. 1 c 0.251660
  9. 2 c 0.063387
  10. 0 d 1.080605
  11. 1 d 0.567547
  12. 2 d -0.154148
  13. dtype: float64

交换并排序分层

sortlevel()

.sortlevel( )先对外层索引进行排序,再对内层索引进行排序,默认是升序。

示例代码:

  1. # 交换并排序分层
  2. print(ser_obj.swaplevel().sortlevel())

运行结果:

  1. 0 a 0.099174
  2. b 1.742445
  3. c -0.150638
  4. d 1.080605
  5. 1 a -0.310414
  6. b 1.152924
  7. c 0.251660
  8. d 0.567547
  9. 2 a -0.558047
  10. b -0.725332
  11. c 0.063387
  12. d -0.154148
  13. dtype: float64

Pandas统计计算和描述

示例代码:

  1. import numpy as np
  2. import pandas as pd
  3. df_obj = pd.DataFrame(np.random.randn(5,4), columns = ['a', 'b', 'c', 'd'])
  4. print(df_obj)

运行结果:

  1. a b c d
  2. 0 1.469682 1.948965 1.373124 -0.564129
  3. 1 -1.466670 -0.494591 0.467787 -2.007771
  4. 2 1.368750 0.532142 0.487862 -1.130825
  5. 3 -0.758540 -0.479684 1.239135 1.073077
  6. 4 -0.007470 0.997034 2.669219 0.742070

常用的统计计算

sum, mean, max, min…

axis=0 按列统计,axis=1按行统计

skipna 排除缺失值, 默认为True

示例代码:

  1. df_obj.sum()
  2. df_obj.max()
  3. df_obj.min(axis=1, skipna=False)

运行结果:

  1. a 0.605751
  2. b 2.503866
  3. c 6.237127
  4. d -1.887578
  5. dtype: float64
  6. a 1.469682
  7. b 1.948965
  8. c 2.669219
  9. d 1.073077
  10. dtype: float64
  11. 0 -0.564129
  12. 1 -2.007771
  13. 2 -1.130825
  14. 3 -0.758540
  15. 4 -0.007470
  16. dtype: float64

常用的统计描述

describe 产生多个统计数据

示例代码:

print(df_obj.describe())

运行结果:

  1. a b c d
  2. count 5.000000 5.000000 5.000000 5.000000
  3. mean 0.180305 0.106488 0.244978 0.178046
  4. std 0.641945 0.454340 1.064356 1.144416
  5. min -0.677175 -0.490278 -1.164928 -1.574556
  6. 25% -0.064069 -0.182920 -0.464013 -0.089962
  7. 50% 0.231722 0.127846 0.355859 0.190482
  8. 75% 0.318854 0.463377 1.169750 0.983663
  9. max 1.092195 0.614413 1.328220 1.380601

常用的统计描述方法:

Pandas分组与聚合

分组 (groupby)

  • 对数据集进行分组,然后对每组进行统计分析

  • SQL能够对数据进行过滤,分组聚合

  • pandas能利用groupby进行更加复杂的分组运算

  • 分组运算过程:split->apply->combine

    1. 拆分:进行分组的根据

    2. 应用:每个分组运行的计算规则

    3. 合并:把每个分组的计算结果合并起来

示例代码:

  1. import pandas as pd
  2. import numpy as np
  3. dict_obj = {'key1' : ['a', 'b', 'a', 'b',
  4. 'a', 'b', 'a', 'a'],
  5. 'key2' : ['one', 'one', 'two', 'three',
  6. 'two', 'two', 'one', 'three'],
  7. 'data1': np.random.randn(8),
  8. 'data2': np.random.randn(8)}
  9. df_obj = pd.DataFrame(dict_obj)
  10. print(df_obj)

运行结果:

  1. data1 data2 key1 key2
  2. 0 0.974685 -0.672494 a one
  3. 1 -0.214324 0.758372 b one
  4. 2 1.508838 0.392787 a two
  5. 3 0.522911 0.630814 b three
  6. 4 1.347359 -0.177858 a two
  7. 5 -0.264616 1.017155 b two
  8. 6 -0.624708 0.450885 a one
  9. 7 -1.019229 -1.143825 a three

一、GroupBy对象:DataFrameGroupBy,SeriesGroupBy

1. 分组操作

groupby()进行分组,GroupBy对象没有进行实际运算,只是包含分组的中间数据

按列名分组:obj.groupby(‘label’)

示例代码:

  1. # dataframe根据key1进行分组
  2. print(type(df_obj.groupby('key1')))
  3. # dataframe的 data1 列根据 key1 进行分组
  4. print(type(df_obj['data1'].groupby(df_obj['key1'])))

运行结果:

  1. <class 'pandas.core.groupby.DataFrameGroupBy'>
  2. <class 'pandas.core.groupby.SeriesGroupBy'>

2. 分组运算

对GroupBy对象进行分组运算/多重分组运算,如mean()

非数值数据不进行分组运算

示例代码:

  1. # 分组运算
  2. grouped1 = df_obj.groupby('key1')
  3. print(grouped1.mean())
  4. grouped2 = df_obj['data1'].groupby(df_obj['key1'])
  5. print(grouped2.mean())

运行结果:

  1. data1 data2
  2. key1
  3. a 0.437389 -0.230101
  4. b 0.014657 0.802114
  5. key1
  6. a 0.437389
  7. b 0.014657
  8. Name: data1, dtype: float64

size() 返回每个分组的元素个数

示例代码:

  1. # size
  2. print(grouped1.size())
  3. print(grouped2.size())

运行结果:

  1. key1
  2. a 5
  3. b 3
  4. dtype: int64
  5. key1
  6. a 5
  7. b 3
  8. dtype: int64

3. 按自定义的key分组

obj.groupby(self_def_key)

自定义的key可为列表或多层列表

obj.groupby([‘label1’, ‘label2’])->多层dataframe

示例代码:

  1. # 按自定义key分组,列表
  2. self_def_key = [0, 1, 2, 3, 3, 4, 5, 7]
  3. print(df_obj.groupby(self_def_key).size())
  4. # 按自定义key分组,多层列表
  5. print(df_obj.groupby([df_obj['key1'], df_obj['key2']]).size())
  6. # 按多个列多层分组
  7. grouped2 = df_obj.groupby(['key1', 'key2'])
  8. print(grouped2.size())
  9. # 多层分组按key的顺序进行
  10. grouped3 = df_obj.groupby(['key2', 'key1'])
  11. print(grouped3.mean())
  12. # unstack可以将多层索引的结果转换成单层的dataframe
  13. print(grouped3.mean().unstack())

运行结果:

  1. 0 1
  2. 1 1
  3. 2 1
  4. 3 2
  5. 4 1
  6. 5 1
  7. 7 1
  8. dtype: int64
  9. key1 key2
  10. a one 2
  11. three 1
  12. two 2
  13. b one 1
  14. three 1
  15. two 1
  16. dtype: int64
  17. key1 key2
  18. a one 2
  19. three 1
  20. two 2
  21. b one 1
  22. three 1
  23. two 1
  24. dtype: int64
  25. data1 data2
  26. key2 key1
  27. one a 0.174988 -0.110804
  28. b -0.214324 0.758372
  29. three a -1.019229 -1.143825
  30. b 0.522911 0.630814
  31. two a 1.428099 0.107465
  32. b -0.264616 1.017155
  33. data1 data2
  34. key1 a b a b
  35. key2
  36. one 0.174988 -0.214324 -0.110804 0.758372
  37. three -1.019229 0.522911 -1.143825 0.630814
  38. two 1.428099 -0.264616 0.107465 1.017155

二、GroupBy对象支持迭代操作

每次迭代返回一个元组 (group_name, group_data)

可用于分组数据的具体运算

1. 单层分组

示例代码:

  1. # 单层分组,根据key1
  2. for group_name, group_data in grouped1:
  3. print(group_name)
  4. print(group_data)

运行结果:

  1. a
  2. data1 data2 key1 key2
  3. 0 0.974685 -0.672494 a one
  4. 2 1.508838 0.392787 a two
  5. 4 1.347359 -0.177858 a two
  6. 6 -0.624708 0.450885 a one
  7. 7 -1.019229 -1.143825 a three
  8. b
  9. data1 data2 key1 key2
  10. 1 -0.214324 0.758372 b one
  11. 3 0.522911 0.630814 b three
  12. 5 -0.264616 1.017155 b two

2. 多层分组

示例代码:

  1. # 多层分组,根据key1 和 key2
  2. for group_name, group_data in grouped2:
  3. print(group_name)
  4. print(group_data)

运行结果:

  1. ('a', 'one')
  2. data1 data2 key1 key2
  3. 0 0.974685 -0.672494 a one
  4. 6 -0.624708 0.450885 a one
  5. ('a', 'three')
  6. data1 data2 key1 key2
  7. 7 -1.019229 -1.143825 a three
  8. ('a', 'two')
  9. data1 data2 key1 key2
  10. 2 1.508838 0.392787 a two
  11. 4 1.347359 -0.177858 a two
  12. ('b', 'one')
  13. data1 data2 key1 key2
  14. 1 -0.214324 0.758372 b one
  15. ('b', 'three')
  16. data1 data2 key1 key2
  17. 3 0.522911 0.630814 b three
  18. ('b', 'two')
  19. data1 data2 key1 key2
  20. 5 -0.264616 1.017155 b two

三、GroupBy对象可以转换成列表或字典

示例代码:

  1. # GroupBy对象转换list
  2. print(list(grouped1))
  3. # GroupBy对象转换dict
  4. print(dict(list(grouped1)))

运行结果:

  1. [('a', data1 data2 key1 key2
  2. 0 0.974685 -0.672494 a one
  3. 2 1.508838 0.392787 a two
  4. 4 1.347359 -0.177858 a two
  5. 6 -0.624708 0.450885 a one
  6. 7 -1.019229 -1.143825 a three),
  7. ('b', data1 data2 key1 key2
  8. 1 -0.214324 0.758372 b one
  9. 3 0.522911 0.630814 b three
  10. 5 -0.264616 1.017155 b two)]
  11. {'a': data1 data2 key1 key2
  12. 0 0.974685 -0.672494 a one
  13. 2 1.508838 0.392787 a two
  14. 4 1.347359 -0.177858 a two
  15. 6 -0.624708 0.450885 a one
  16. 7 -1.019229 -1.143825 a three,
  17. 'b': data1 data2 key1 key2
  18. 1 -0.214324 0.758372 b one
  19. 3 0.522911 0.630814 b three
  20. 5 -0.264616 1.017155 b two}

1. 按列分组、按数据类型分组

示例代码:

  1. # 按列分组
  2. print(df_obj.dtypes)
  3. # 按数据类型分组
  4. print(df_obj.groupby(df_obj.dtypes, axis=1).size())
  5. print(df_obj.groupby(df_obj.dtypes, axis=1).sum())

运行结果:

  1. data1 float64
  2. data2 float64
  3. key1 object
  4. key2 object
  5. dtype: object
  6. float64 2
  7. object 2
  8. dtype: int64
  9. float64 object
  10. 0 0.302191 a one
  11. 1 0.544048 b one
  12. 2 1.901626 a two
  13. 3 1.153725 b three
  14. 4 1.169501 a two
  15. 5 0.752539 b two
  16. 6 -0.173823 a one
  17. 7 -2.163054 a three

2. 其他分组方法

示例代码:

  1. df_obj2 = pd.DataFrame(np.random.randint(1, 10, (5,5)),
  2. columns=['a', 'b', 'c', 'd', 'e'],
  3. index=['A', 'B', 'C', 'D', 'E'])
  4. df_obj2.ix[1, 1:4] = np.NaN
  5. print(df_obj2)

运行结果:

  1. a b c d e
  2. A 7 2.0 4.0 5.0 8
  3. B 4 NaN NaN NaN 1
  4. C 3 2.0 5.0 4.0 6
  5. D 3 1.0 9.0 7.0 3
  6. E 6 1.0 6.0 8.0 1

3. 通过字典分组

示例代码:

  1. # 通过字典分组
  2. mapping_dict = {'a':'Python', 'b':'Python', 'c':'Java', 'd':'C', 'e':'Java'}
  3. print(df_obj2.groupby(mapping_dict, axis=1).size())
  4. print(df_obj2.groupby(mapping_dict, axis=1).count()) # 非NaN的个数
  5. print(df_obj2.groupby(mapping_dict, axis=1).sum())

运行结果:

  1. C 1
  2. Java 2
  3. Python 2
  4. dtype: int64
  5. C Java Python
  6. A 1 2 2
  7. B 0 1 1
  8. C 1 2 2
  9. D 1 2 2
  10. E 1 2 2
  11. C Java Python
  12. A 5.0 12.0 9.0
  13. B NaN 1.0 4.0
  14. C 4.0 11.0 5.0
  15. D 7.0 12.0 4.0
  16. E 8.0 7.0 7.0

4. 通过函数分组,函数传入的参数为行索引或列索引

示例代码:

  1. # 通过函数分组
  2. df_obj3 = pd.DataFrame(np.random.randint(1, 10, (5,5)),
  3. columns=['a', 'b', 'c', 'd', 'e'],
  4. index=['AA', 'BBB', 'CC', 'D', 'EE'])
  5. #df_obj3
  6. def group_key(idx):
  7. """
  8. idx 为列索引或行索引
  9. """
  10. #return idx
  11. return len(idx)
  12. print(df_obj3.groupby(group_key).size())
  13. # 以上自定义函数等价于
  14. #df_obj3.groupby(len).size()

运行结果:

  1. 1 1
  2. 2 3
  3. 3 1
  4. dtype: int64

5. 通过索引级别分组

示例代码:

  1. # 通过索引级别分组
  2. columns = pd.MultiIndex.from_arrays([['Python', 'Java', 'Python', 'Java', 'Python'],
  3. ['A', 'A', 'B', 'C', 'B']], names=['language', 'index'])
  4. df_obj4 = pd.DataFrame(np.random.randint(1, 10, (5, 5)), columns=columns)
  5. print(df_obj4)
  6. # 根据language进行分组
  7. print(df_obj4.groupby(level='language', axis=1).sum())
  8. # 根据index进行分组
  9. print(df_obj4.groupby(level='index', axis=1).sum())

运行结果:

  1. language Python Java Python Java Python
  2. index A A B C B
  3. 0 2 7 8 4 3
  4. 1 5 2 6 1 2
  5. 2 6 4 4 5 2
  6. 3 4 7 4 3 1
  7. 4 7 4 3 4 8
  8. language Java Python
  9. 0 11 13
  10. 1 3 13
  11. 2 9 12
  12. 3 10 9
  13. 4 8 18
  14. index A B C
  15. 0 9 11 4
  16. 1 7 8 1
  17. 2 10 6 5
  18. 3 11 5 3
  19. 4 11 11 4

聚合 (aggregation)

  • 数组产生标量的过程,如mean()、count()等

  • 常用于对分组后的数据进行计算

示例代码:

  1. dict_obj = {'key1' : ['a', 'b', 'a', 'b',
  2. 'a', 'b', 'a', 'a'],
  3. 'key2' : ['one', 'one', 'two', 'three',
  4. 'two', 'two', 'one', 'three'],
  5. 'data1': np.random.randint(1,10, 8),
  6. 'data2': np.random.randint(1,10, 8)}
  7. df_obj5 = pd.DataFrame(dict_obj)
  8. print(df_obj5)

运行结果:

  1. data1 data2 key1 key2
  2. 0 3 7 a one
  3. 1 1 5 b one
  4. 2 7 4 a two
  5. 3 2 4 b three
  6. 4 6 4 a two
  7. 5 9 9 b two
  8. 6 3 5 a one
  9. 7 8 4 a three

1. 内置的聚合函数

sum(), mean(), max(), min(), count(), size(), describe()

示例代码:

  1. print(df_obj5.groupby('key1').sum())
  2. print(df_obj5.groupby('key1').max())
  3. print(df_obj5.groupby('key1').min())
  4. print(df_obj5.groupby('key1').mean())
  5. print(df_obj5.groupby('key1').size())
  6. print(df_obj5.groupby('key1').count())
  7. print(df_obj5.groupby('key1').describe())

运行结果:

  1. data1 data2
  2. key1
  3. a 27 24
  4. b 12 18
  5. data1 data2 key2
  6. key1
  7. a 8 7 two
  8. b 9 9 two
  9. data1 data2 key2
  10. key1
  11. a 3 4 one
  12. b 1 4 one
  13. data1 data2
  14. key1
  15. a 5.4 4.8
  16. b 4.0 6.0
  17. key1
  18. a 5
  19. b 3
  20. dtype: int64
  21. data1 data2 key2
  22. key1
  23. a 5 5 5
  24. b 3 3 3
  25. data1 data2
  26. key1
  27. a count 5.000000 5.000000
  28. mean 5.400000 4.800000
  29. std 2.302173 1.303840
  30. min 3.000000 4.000000
  31. 25% 3.000000 4.000000
  32. 50% 6.000000 4.000000
  33. 75% 7.000000 5.000000
  34. max 8.000000 7.000000
  35. b count 3.000000 3.000000
  36. mean 4.000000 6.000000
  37. std 4.358899 2.645751
  38. min 1.000000 4.000000
  39. 25% 1.500000 4.500000
  40. 50% 2.000000 5.000000
  41. 75% 5.500000 7.000000
  42. max 9.000000 9.000000

2. 可自定义函数,传入agg方法中

grouped.agg(func)

func的参数为groupby索引对应的记录

示例代码:

  1. # 自定义聚合函数
  2. def peak_range(df):
  3. """
  4. 返回数值范围
  5. """
  6. #print type(df) #参数为索引所对应的记录
  7. return df.max() - df.min()
  8. print(df_obj5.groupby('key1').agg(peak_range))
  9. print(df_obj.groupby('key1').agg(lambda df : df.max() - df.min()))

运行结果:

  1. data1 data2
  2. key1
  3. a 5 3
  4. b 8 5
  5. data1 data2
  6. key1
  7. a 2.528067 1.594711
  8. b 0.787527 0.386341
  9. In [25]:

3. 应用多个聚合函数

同时应用多个函数进行聚合操作,使用函数列表

示例代码:

  1. # 应用多个聚合函数
  2. # 同时应用多个聚合函数
  3. print(df_obj.groupby('key1').agg(['mean', 'std', 'count', peak_range])) # 默认列名为函数名
  4. print(df_obj.groupby('key1').agg(['mean', 'std', 'count', ('range', peak_range)])) # 通过元组提供新的列名

运行结果:

  1. data1 data2
  2. mean std count peak_range mean std count peak_range
  3. key1
  4. a 0.437389 1.174151 5 2.528067 -0.230101 0.686488 5 1.594711
  5. b 0.014657 0.440878 3 0.787527 0.802114 0.196850 3 0.386341
  6. data1 data2
  7. mean std count range mean std count range
  8. key1
  9. a 0.437389 1.174151 5 2.528067 -0.230101 0.686488 5 1.594711
  10. b 0.014657 0.440878 3 0.787527 0.802114 0.196850 3 0.386341

4. 对不同的列分别作用不同的聚合函数,使用dict

示例代码:

  1. # 每列作用不同的聚合函数
  2. dict_mapping = {'data1':'mean',
  3. 'data2':'sum'}
  4. print(df_obj.groupby('key1').agg(dict_mapping))
  5. dict_mapping = {'data1':['mean','max'],
  6. 'data2':'sum'}
  7. print(df_obj.groupby('key1').agg(dict_mapping))

运行结果:

  1. data1 data2
  2. key1
  3. a 0.437389 -1.150505
  4. b 0.014657 2.406341
  5. data1 data2
  6. mean max sum
  7. key1
  8. a 0.437389 1.508838 -1.150505
  9. b 0.014657 0.522911 2.406341

5. 常用的内置聚合函数

数据的分组运算

示例代码:

  1. import pandas as pd
  2. import numpy as np
  3. dict_obj = {'key1' : ['a', 'b', 'a', 'b',
  4. 'a', 'b', 'a', 'a'],
  5. 'key2' : ['one', 'one', 'two', 'three',
  6. 'two', 'two', 'one', 'three'],
  7. 'data1': np.random.randint(1, 10, 8),
  8. 'data2': np.random.randint(1, 10, 8)}
  9. df_obj = pd.DataFrame(dict_obj)
  10. print(df_obj)
  11. # 按key1分组后,计算data1,data2的统计信息并附加到原始表格中,并添加表头前缀
  12. k1_sum = df_obj.groupby('key1').sum().add_prefix('sum_')
  13. print(k1_sum)

运行结果:

  1. data1 data2 key1 key2
  2. 0 5 1 a one
  3. 1 7 8 b one
  4. 2 1 9 a two
  5. 3 2 6 b three
  6. 4 9 8 a two
  7. 5 8 3 b two
  8. 6 3 5 a one
  9. 7 8 3 a three
  10. sum_data1 sum_data2
  11. key1
  12. a 26 26
  13. b 17 17

聚合运算后会改变原始数据的形状,

如何保持原始数据的形状?

1. merge

使用merge的外连接,比较复杂

示例代码:

  1. # 方法1,使用merge
  2. k1_sum_merge = pd.merge(df_obj, k1_sum, left_on='key1', right_index=True)
  3. print(k1_sum_merge)

运行结果:

  1. data1 data2 key1 key2 sum_data1 sum_data2
  2. 0 5 1 a one 26 26
  3. 2 1 9 a two 26 26
  4. 4 9 8 a two 26 26
  5. 6 3 5 a one 26 26
  6. 7 8 3 a three 26 26
  7. 1 7 8 b one 17 17
  8. 3 2 6 b three 17 17
  9. 5 8 3 b two 17 17

2. transform

transform的计算结果和原始数据的形状保持一致,

如:grouped.transform(np.sum)

示例代码:

  1. # 方法2,使用transform
  2. k1_sum_tf = df_obj.groupby('key1').transform(np.sum).add_prefix('sum_')
  3. df_obj[k1_sum_tf.columns] = k1_sum_tf
  4. print(df_obj)

运行结果:

  1. data1 data2 key1 key2 sum_data1 sum_data2 sum_key2
  2. 0 5 1 a one 26 26 onetwotwoonethree
  3. 1 7 8 b one 17 17 onethreetwo
  4. 2 1 9 a two 26 26 onetwotwoonethree
  5. 3 2 6 b three 17 17 onethreetwo
  6. 4 9 8 a two 26 26 onetwotwoonethree
  7. 5 8 3 b two 17 17 onethreetwo
  8. 6 3 5 a one 26 26 onetwotwoonethree
  9. 7 8 3 a three 26 26 onetwotwoonethree

也可传入自定义函数,

示例代码:

  1. # 自定义函数传入transform
  2. def diff_mean(s):
  3. """
  4. 返回数据与均值的差值
  5. """
  6. return s - s.mean()
  7. print(df_obj.groupby('key1').transform(diff_mean))

运行结果:

  1. data1 data2 sum_data1 sum_data2
  2. 0 -0.200000 -4.200000 0 0
  3. 1 1.333333 2.333333 0 0
  4. 2 -4.200000 3.800000 0 0
  5. 3 -3.666667 0.333333 0 0
  6. 4 3.800000 2.800000 0 0
  7. 5 2.333333 -2.666667 0 0
  8. 6 -2.200000 -0.200000 0 0
  9. 7 2.800000 -2.200000 0 0

groupby.apply(func)

func函数也可以在各分组上分别调用,最后结果通过pd.concat组装到一起(数据合并)

示例代码:

  1. import pandas as pd
  2. import numpy as np
  3. dataset_path = './starcraft.csv'
  4. df_data = pd.read_csv(dataset_path, usecols=['LeagueIndex', 'Age', 'HoursPerWeek',
  5. 'TotalHours', 'APM'])
  6. def top_n(df, n=3, column='APM'):
  7. """
  8. 返回每个分组按 column 的 top n 数据
  9. """
  10. return df.sort_values(by=column, ascending=False)[:n]
  11. print(df_data.groupby('LeagueIndex').apply(top_n))

运行结果:

  1. LeagueIndex Age HoursPerWeek TotalHours APM
  2. LeagueIndex
  3. 1 2214 1 20.0 12.0 730.0 172.9530
  4. 2246 1 27.0 8.0 250.0 141.6282
  5. 1753 1 20.0 28.0 100.0 139.6362
  6. 2 3062 2 20.0 6.0 100.0 179.6250
  7. 3229 2 16.0 24.0 110.0 156.7380
  8. 1520 2 29.0 6.0 250.0 151.6470
  9. 3 1557 3 22.0 6.0 200.0 226.6554
  10. 484 3 19.0 42.0 450.0 220.0692
  11. 2883 3 16.0 8.0 800.0 208.9500
  12. 4 2688 4 26.0 24.0 990.0 249.0210
  13. 1759 4 16.0 6.0 75.0 229.9122
  14. 2637 4 23.0 24.0 650.0 227.2272
  15. 5 3277 5 18.0 16.0 950.0 372.6426
  16. 93 5 17.0 36.0 720.0 335.4990
  17. 202 5 37.0 14.0 800.0 327.7218
  18. 6 734 6 16.0 28.0 730.0 389.8314
  19. 2746 6 16.0 28.0 4000.0 350.4114
  20. 1810 6 21.0 14.0 730.0 323.2506
  21. 7 3127 7 23.0 42.0 2000.0 298.7952
  22. 104 7 21.0 24.0 1000.0 286.4538
  23. 1654 7 18.0 98.0 700.0 236.0316
  24. 8 3393 8 NaN NaN NaN 375.8664
  25. 3373 8 NaN NaN NaN 364.8504
  26. 3372 8 NaN NaN NaN 355.3518

1. 产生层级索引:外层索引是分组名,内层索引是df_obj的行索引

示例代码:

  1. # apply函数接收的参数会传入自定义的函数中
  2. print(df_data.groupby('LeagueIndex').apply(top_n, n=2, column='Age'))

运行结果:

  1. LeagueIndex Age HoursPerWeek TotalHours APM
  2. LeagueIndex
  3. 1 3146 1 40.0 12.0 150.0 38.5590
  4. 3040 1 39.0 10.0 500.0 29.8764
  5. 2 920 2 43.0 10.0 730.0 86.0586
  6. 2437 2 41.0 4.0 200.0 54.2166
  7. 3 1258 3 41.0 14.0 800.0 77.6472
  8. 2972 3 40.0 10.0 500.0 60.5970
  9. 4 1696 4 44.0 6.0 500.0 89.5266
  10. 1729 4 39.0 8.0 500.0 86.7246
  11. 5 202 5 37.0 14.0 800.0 327.7218
  12. 2745 5 37.0 18.0 1000.0 123.4098
  13. 6 3069 6 31.0 8.0 800.0 133.1790
  14. 2706 6 31.0 8.0 700.0 66.9918
  15. 7 2813 7 26.0 36.0 1300.0 188.5512
  16. 1992 7 26.0 24.0 1000.0 219.6690
  17. 8 3340 8 NaN NaN NaN 189.7404
  18. 3341 8 NaN NaN NaN 287.8128

2. 禁止层级索引, group_keys=False

示例代码:

print(df_data.groupby('LeagueIndex', group_keys=False).apply(top_n))

运行结果:

  1. LeagueIndex Age HoursPerWeek TotalHours APM
  2. 2214 1 20.0 12.0 730.0 172.9530
  3. 2246 1 27.0 8.0 250.0 141.6282
  4. 1753 1 20.0 28.0 100.0 139.6362
  5. 3062 2 20.0 6.0 100.0 179.6250
  6. 3229 2 16.0 24.0 110.0 156.7380
  7. 1520 2 29.0 6.0 250.0 151.6470
  8. 1557 3 22.0 6.0 200.0 226.6554
  9. 484 3 19.0 42.0 450.0 220.0692
  10. 2883 3 16.0 8.0 800.0 208.9500
  11. 2688 4 26.0 24.0 990.0 249.0210
  12. 1759 4 16.0 6.0 75.0 229.9122
  13. 2637 4 23.0 24.0 650.0 227.2272
  14. 3277 5 18.0 16.0 950.0 372.6426
  15. 93 5 17.0 36.0 720.0 335.4990
  16. 202 5 37.0 14.0 800.0 327.7218
  17. 734 6 16.0 28.0 730.0 389.8314
  18. 2746 6 16.0 28.0 4000.0 350.4114
  19. 1810 6 21.0 14.0 730.0 323.2506
  20. 3127 7 23.0 42.0 2000.0 298.7952
  21. 104 7 21.0 24.0 1000.0 286.4538
  22. 1654 7 18.0 98.0 700.0 236.0316
  23. 3393 8 NaN NaN NaN 375.8664
  24. 3373 8 NaN NaN NaN 364.8504
  25. 3372 8 NaN NaN NaN 355.3518

apply可以用来处理不同分组内的缺失数据填充,填充该分组的均值。

数据清洗

  • 数据清洗是数据分析关键的一步,直接影响之后的处理工作

  • 数据需要修改吗?有什么需要修改的吗?数据应该怎么调整才能适用于接下来的分析和挖掘?

  • 是一个迭代的过程,实际项目中可能需要不止一次地执行这些清洗操作

  • 处理缺失数据:pd.fillna(),pd.dropna()

数据连接(pd.merge)

  • pd.merge

  • 根据单个或多个键将不同DataFrame的行连接起来

  • 类似数据库的连接操作

示例代码:

  1. import pandas as pd
  2. import numpy as np
  3. df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
  4. 'data1' : np.random.randint(0,10,7)})
  5. df_obj2 = pd.DataFrame({'key': ['a', 'b', 'd'],
  6. 'data2' : np.random.randint(0,10,3)})
  7. print(df_obj1)
  8. print(df_obj2)

运行结果:

  1. data1 key
  2. data1 key
  3. 0 8 b
  4. 1 8 b
  5. 2 3 a
  6. 3 5 c
  7. 4 4 a
  8. 5 9 a
  9. 6 6 b
  10. data2 key
  11. 0 9 a
  12. 1 0 b
  13. 2 3 d

1. 默认将重叠列的列名作为“外键”进行连接

示例代码:

  1. # 默认将重叠列的列名作为“外键”进行连接
  2. print(pd.merge(df_obj1, df_obj2))

运行结果:

  1. data1 key data2
  2. 0 8 b 0
  3. 1 8 b 0
  4. 2 6 b 0
  5. 3 3 a 9
  6. 4 4 a 9
  7. 5 9 a 9

2. on显示指定“外键”

示例代码:

  1. # on显示指定“外键”
  2. print(pd.merge(df_obj1, df_obj2, on='key'))

运行结果:

  1. data1 key data2
  2. 0 8 b 0
  3. 1 8 b 0
  4. 2 6 b 0
  5. 3 3 a 9
  6. 4 4 a 9
  7. 5 9 a 9

3. left_on,左侧数据的“外键”,right_on,右侧数据的“外键”

示例代码:

  1. # left_on,right_on分别指定左侧数据和右侧数据的“外键”
  2. # 更改列名
  3. df_obj1 = df_obj1.rename(columns={'key':'key1'})
  4. df_obj2 = df_obj2.rename(columns={'key':'key2'})
  5. print(pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2'))

运行结果:

  1. data1 key1 data2 key2
  2. 0 8 b 0 b
  3. 1 8 b 0 b
  4. 2 6 b 0 b
  5. 3 3 a 9 a
  6. 4 4 a 9 a
  7. 5 9 a 9 a

默认是“内连接”(inner),即结果中的键是交集

how指定连接方式

4. “外连接”(outer),结果中的键是并集

示例代码:

  1. # “外连接”
  2. print(pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2', how='outer'))

运行结果:

  1. data1 key1 data2 key2
  2. 0 8.0 b 0.0 b
  3. 1 8.0 b 0.0 b
  4. 2 6.0 b 0.0 b
  5. 3 3.0 a 9.0 a
  6. 4 4.0 a 9.0 a
  7. 5 9.0 a 9.0 a
  8. 6 5.0 c NaN NaN
  9. 7 NaN NaN 3.0 d

5. “左连接”(left)

示例代码:

  1. # 左连接
  2. print(pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2', how='left'))

运行结果:

  1. data1 key1 data2 key2
  2. 0 8 b 0.0 b
  3. 1 8 b 0.0 b
  4. 2 3 a 9.0 a
  5. 3 5 c NaN NaN
  6. 4 4 a 9.0 a
  7. 5 9 a 9.0 a
  8. 6 6 b 0.0 b

6. “右连接”(right)

示例代码:

  1. # 右连接
  2. print(pd.merge(df_obj1, df_obj2, left_on='key1', right_on='key2', how='right'))

运行结果:

  1. data1 key1 data2 key2
  2. 0 8.0 b 0 b
  3. 1 8.0 b 0 b
  4. 2 6.0 b 0 b
  5. 3 3.0 a 9 a
  6. 4 4.0 a 9 a
  7. 5 9.0 a 9 a
  8. 6 NaN NaN 3 d

7. 处理重复列名

suffixes,默认为_x, _y

示例代码:

  1. # 处理重复列名
  2. df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
  3. 'data' : np.random.randint(0,10,7)})
  4. df_obj2 = pd.DataFrame({'key': ['a', 'b', 'd'],
  5. 'data' : np.random.randint(0,10,3)})
  6. print(pd.merge(df_obj1, df_obj2, on='key', suffixes=('_left', '_right')))

运行结果:

  1. data_left key data_right
  2. 0 9 b 1
  3. 1 5 b 1
  4. 2 1 b 1
  5. 3 2 a 8
  6. 4 2 a 8
  7. 5 5 a 8

8. 按索引连接

left_index=True或right_index=True

示例代码:

  1. # 按索引连接
  2. df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
  3. 'data1' : np.random.randint(0,10,7)})
  4. df_obj2 = pd.DataFrame({'data2' : np.random.randint(0,10,3)}, index=['a', 'b', 'd'])
  5. print(pd.merge(df_obj1, df_obj2, left_on='key', right_index=True))

运行结果:

  1. data1 key data2
  2. 0 3 b 6
  3. 1 4 b 6
  4. 6 8 b 6
  5. 2 6 a 0
  6. 4 3 a 0
  7. 5 0 a 0

数据合并(pd.concat)

  • 沿轴方向将多个对象合并到一起

1. NumPy的concat

np.concatenate

示例代码:

  1. import numpy as np
  2. import pandas as pd
  3. arr1 = np.random.randint(0, 10, (3, 4))
  4. arr2 = np.random.randint(0, 10, (3, 4))
  5. print(arr1)
  6. print(arr2)
  7. print(np.concatenate([arr1, arr2]))
  8. print(np.concatenate([arr1, arr2], axis=1))

运行结果:

  1. # print(arr1)
  2. [[3 3 0 8]
  3. [2 0 3 1]
  4. [4 8 8 2]]
  5. # print(arr2)
  6. [[6 8 7 3]
  7. [1 6 8 7]
  8. [1 4 7 1]]
  9. # print(np.concatenate([arr1, arr2]))
  10. [[3 3 0 8]
  11. [2 0 3 1]
  12. [4 8 8 2]
  13. [6 8 7 3]
  14. [1 6 8 7]
  15. [1 4 7 1]]
  16. # print(np.concatenate([arr1, arr2], axis=1))
  17. [[3 3 0 8 6 8 7 3]
  18. [2 0 3 1 1 6 8 7]
  19. [4 8 8 2 1 4 7 1]]

2. pd.concat

  • 注意指定轴方向,默认axis=0

  • join指定合并方式,默认为outer

  • Series合并时查看行索引有无重复

1) index 没有重复的情况

示例代码:

  1. # index 没有重复的情况
  2. ser_obj1 = pd.Series(np.random.randint(0, 10, 5), index=range(0,5))
  3. ser_obj2 = pd.Series(np.random.randint(0, 10, 4), index=range(5,9))
  4. ser_obj3 = pd.Series(np.random.randint(0, 10, 3), index=range(9,12))
  5. print(ser_obj1)
  6. print(ser_obj2)
  7. print(ser_obj3)
  8. print(pd.concat([ser_obj1, ser_obj2, ser_obj3]))
  9. print(pd.concat([ser_obj1, ser_obj2, ser_obj3], axis=1))

运行结果:

  1. # print(ser_obj1)
  2. 0 1
  3. 1 8
  4. 2 4
  5. 3 9
  6. 4 4
  7. dtype: int64
  8. # print(ser_obj2)
  9. 5 2
  10. 6 6
  11. 7 4
  12. 8 2
  13. dtype: int64
  14. # print(ser_obj3)
  15. 9 6
  16. 10 2
  17. 11 7
  18. dtype: int64
  19. # print(pd.concat([ser_obj1, ser_obj2, ser_obj3]))
  20. 0 1
  21. 1 8
  22. 2 4
  23. 3 9
  24. 4 4
  25. 5 2
  26. 6 6
  27. 7 4
  28. 8 2
  29. 9 6
  30. 10 2
  31. 11 7
  32. dtype: int64
  33. # print(pd.concat([ser_obj1, ser_obj2, ser_obj3], axis=1))
  34. 0 1 2
  35. 0 1.0 NaN NaN
  36. 1 5.0 NaN NaN
  37. 2 3.0 NaN NaN
  38. 3 2.0 NaN NaN
  39. 4 4.0 NaN NaN
  40. 5 NaN 9.0 NaN
  41. 6 NaN 8.0 NaN
  42. 7 NaN 3.0 NaN
  43. 8 NaN 6.0 NaN
  44. 9 NaN NaN 2.0
  45. 10 NaN NaN 3.0
  46. 11 NaN NaN 3.0

2) index 有重复的情况

示例代码:

  1. # index 有重复的情况
  2. ser_obj1 = pd.Series(np.random.randint(0, 10, 5), index=range(5))
  3. ser_obj2 = pd.Series(np.random.randint(0, 10, 4), index=range(4))
  4. ser_obj3 = pd.Series(np.random.randint(0, 10, 3), index=range(3))
  5. print(ser_obj1)
  6. print(ser_obj2)
  7. print(ser_obj3)
  8. print(pd.concat([ser_obj1, ser_obj2, ser_obj3]))

运行结果:

  1. # print(ser_obj1)
  2. 0 0
  3. 1 3
  4. 2 7
  5. 3 2
  6. 4 5
  7. dtype: int64
  8. # print(ser_obj2)
  9. 0 5
  10. 1 1
  11. 2 9
  12. 3 9
  13. dtype: int64
  14. # print(ser_obj3)
  15. 0 8
  16. 1 7
  17. 2 9
  18. dtype: int64
  19. # print(pd.concat([ser_obj1, ser_obj2, ser_obj3]))
  20. 0 0
  21. 1 3
  22. 2 7
  23. 3 2
  24. 4 5
  25. 0 5
  26. 1 1
  27. 2 9
  28. 3 9
  29. 0 8
  30. 1 7
  31. 2 9
  32. dtype: int64
  33. # print(pd.concat([ser_obj1, ser_obj2, ser_obj3], axis=1, join='inner'))
  34. # join='inner' 将去除NaN所在的行或列
  35. 0 1 2
  36. 0 0 5 8
  37. 1 3 1 7
  38. 2 7 9 9

3) DataFrame合并时同时查看行索引和列索引有无重复

示例代码:

  1. df_obj1 = pd.DataFrame(np.random.randint(0, 10, (3, 2)), index=['a', 'b', 'c'],
  2. columns=['A', 'B'])
  3. df_obj2 = pd.DataFrame(np.random.randint(0, 10, (2, 2)), index=['a', 'b'],
  4. columns=['C', 'D'])
  5. print(df_obj1)
  6. print(df_obj2)
  7. print(pd.concat([df_obj1, df_obj2]))
  8. print(pd.concat([df_obj1, df_obj2], axis=1, join='inner'))

运行结果:

  1. # print(df_obj1)
  2. A B
  3. a 3 3
  4. b 5 4
  5. c 8 6
  6. # print(df_obj2)
  7. C D
  8. a 1 9
  9. b 6 8
  10. # print(pd.concat([df_obj1, df_obj2]))
  11. A B C D
  12. a 3.0 3.0 NaN NaN
  13. b 5.0 4.0 NaN NaN
  14. c 8.0 6.0 NaN NaN
  15. a NaN NaN 1.0 9.0
  16. b NaN NaN 6.0 8.0
  17. # print(pd.concat([df_obj1, df_obj2], axis=1, join='inner'))
  18. A B C D
  19. a 3 3 1 9
  20. b 5 4 6 8

数据重构

1. stack

  • 将列索引旋转为行索引,完成层级索引

  • DataFrame->Series

示例代码:

  1. import numpy as np
  2. import pandas as pd
  3. df_obj = pd.DataFrame(np.random.randint(0,10, (5,2)), columns=['data1', 'data2'])
  4. print(df_obj)
  5. stacked = df_obj.stack()
  6. print(stacked)

运行结果:

  1. # print(df_obj)
  2. data1 data2
  3. 0 7 9
  4. 1 7 8
  5. 2 8 9
  6. 3 4 1
  7. 4 1 2
  8. # print(stacked)
  9. 0 data1 7
  10. data2 9
  11. 1 data1 7
  12. data2 8
  13. 2 data1 8
  14. data2 9
  15. 3 data1 4
  16. data2 1
  17. 4 data1 1
  18. data2 2
  19. dtype: int64

2. unstack

  • 将层级索引展开

  • Series->DataFrame

  • 认操作内层索引,即level=-1

示例代码:

  1. # 默认操作内层索引
  2. print(stacked.unstack())
  3. # 通过level指定操作索引的级别
  4. print(stacked.unstack(level=0))

运行结果:

  1. # print(stacked.unstack())
  2. data1 data2
  3. 0 7 9
  4. 1 7 8
  5. 2 8 9
  6. 3 4 1
  7. 4 1 2
  8. # print(stacked.unstack(level=0))
  9. 0 1 2 3 4
  10. data1 7 7 8 4 1
  11. data2 9 8 9 1 2

数据转换

一、 处理重复数据

duplicated() 返回布尔型Series表示每行是否为重复行

示例代码:

  1. import numpy as np
  2. import pandas as pd
  3. df_obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4,
  4. 'data2' : np.random.randint(0, 4, 8)})
  5. print(df_obj)
  6. print(df_obj.duplicated())

运行结果:

  1. # print(df_obj)
  2. data1 data2
  3. 0 a 3
  4. 1 a 2
  5. 2 a 3
  6. 3 a 3
  7. 4 b 1
  8. 5 b 0
  9. 6 b 3
  10. 7 b 0
  11. # print(df_obj.duplicated())
  12. 0 False
  13. 1 False
  14. 2 True
  15. 3 True
  16. 4 False
  17. 5 False
  18. 6 False
  19. 7 True
  20. dtype: bool

drop_duplicates() 过滤重复行

默认判断全部列

可指定按某些列判断

示例代码:

  1. print(df_obj.drop_duplicates())
  2. print(df_obj.drop_duplicates('data2'))

运行结果:

  1. # print(df_obj.drop_duplicates())
  2. data1 data2
  3. 0 a 3
  4. 1 a 2
  5. 4 b 1
  6. 5 b 0
  7. 6 b 3
  8. # print(df_obj.drop_duplicates('data2'))
  9. data1 data2
  10. 0 a 3
  11. 1 a 2
  12. 4 b 1
  13. 5 b 0

3. 根据map传入的函数对每行或每列进行转换

  • Series根据map传入的函数对每行或每列进行转换

示例代码:

  1. ser_obj = pd.Series(np.random.randint(0,10,10))
  2. print(ser_obj)
  3. print(ser_obj.map(lambda x : x ** 2))

运行结果:

  1. # print(ser_obj)
  2. 0 1
  3. 1 4
  4. 2 8
  5. 3 6
  6. 4 8
  7. 5 6
  8. 6 6
  9. 7 4
  10. 8 7
  11. 9 3
  12. dtype: int64
  13. # print(ser_obj.map(lambda x : x ** 2))
  14. 0 1
  15. 1 16
  16. 2 64
  17. 3 36
  18. 4 64
  19. 5 36
  20. 6 36
  21. 7 16
  22. 8 49
  23. 9 9
  24. dtype: int64

二、数据替换

replace根据值的内容进行替换

示例代码:

  1. # 单个值替换单个值
  2. print(ser_obj.replace(1, -100))
  3. # 多个值替换一个值
  4. print(ser_obj.replace([6, 8], -100))
  5. # 多个值替换多个值
  6. print(ser_obj.replace([4, 7], [-100, -200]))

运行结果:

  1. # print(ser_obj.replace(1, -100))
  2. 0 -100
  3. 1 4
  4. 2 8
  5. 3 6
  6. 4 8
  7. 5 6
  8. 6 6
  9. 7 4
  10. 8 7
  11. 9 3
  12. dtype: int64
  13. # print(ser_obj.replace([6, 8], -100))
  14. 0 1
  15. 1 4
  16. 2 -100
  17. 3 -100
  18. 4 -100
  19. 5 -100
  20. 6 -100
  21. 7 4
  22. 8 7
  23. 9 3
  24. dtype: int64
  25. # print(ser_obj.replace([4, 7], [-100, -200]))
  26. 0 1
  27. 1 -100
  28. 2 8
  29. 3 6
  30. 4 8
  31. 5 6
  32. 6 6
  33. 7 -100
  34. 8 -200
  35. 9 3
  36. dtype: int64

聚类模型:K-Means

  • 聚类(clustering)属于无监督学习(unsupervised learning)

  • 无类别标记

  • 在线 demo:http:///kmeans.js

K-Means算法

  • 数据挖掘十大经典算法之一

  • 算法接收参数k;然后将样本点划分为k个聚类;同一聚类中的样本相似度较高;不同聚类中的样本相似度较小

算法思想:

以空间中k个样本点为中心进行聚类,对最靠近它们的样本点归类。通过迭 代的方法,逐步更新各聚类中心,直至达到最好的聚类效果

算法描述:

  1. 选择k个聚类的初始中心
  2. 在第n次迭代中,对任意一个样本点,求其到k个聚类中心的距离,将该 样本点归类到距离最小的中心所在的聚类
  3. 利用均值等方法更新各类的中心值
  4. 对所有的k个聚类中心,如果利用2,3步的迭代更新后,达到稳定,则迭代 结束。

优缺点:

  • 优点:速度快,简单

  • 缺点:最终结果和初始点的选择相关,容易陷入局部最优,需要给定k值

全球食品数据分析

项目参考:https://www./bhouwens/d/openfoodfacts/world-food-facts/how-much-sugar-do-we-eat/discussion

  1. # -*- coding : utf-8 -*-
  2. # 处理zip压缩文件
  3. import zipfile
  4. import os
  5. import pandas as pd
  6. import matplotlib.pyplot as plt
  7. def unzip(zip_filepath, dest_path):
  8. """
  9. 解压zip文件
  10. """
  11. with zipfile.ZipFile(zip_filepath) as zf:
  12. zf.extractall(path=dest_path)
  13. def get_dataset_filename(zip_filepath):
  14. """
  15. 获取数据集文件名
  16. """
  17. with zipfile.ZipFile(zip_filepath) as zf:
  18. return zf.namelist()[0]
  19. def run_main():
  20. """
  21. 主函数
  22. """
  23. # 声明变量
  24. dataset_path = './data' # 数据集路径
  25. zip_filename = 'open-food-facts.zip' # zip文件名
  26. zip_filepath = os.path.join(dataset_path, zip_filename) # zip文件路径
  27. dataset_filename = get_dataset_filename(zip_filepath) # 数据集文件名(在zip中)
  28. dataset_filepath = os.path.join(dataset_path, dataset_filename) # 数据集文件路径
  29. print('解压zip...', end='')
  30. unzip(zip_filepath, dataset_path)
  31. print('完成.')
  32. # 读取数据
  33. data = pd.read_csv(dataset_filepath, usecols=['countries_en', 'additives_n'])
  34. # 分析各国家食物中的食品添加剂种类个数
  35. # 1. 数据清理
  36. # 去除缺失数据
  37. data = data.dropna() # 或者data.dropna(inplace=True)
  38. # 将国家名称转换为小写
  39. # 课后练习:经过观察发现'countries_en'中的数值不是单独的国家名称,
  40. # 有的是多个国家名称用逗号隔开,如 Albania,Belgium,France,Germany,Italy,Netherlands,Spain
  41. # 正确的统计应该是将这些值拆开成多个行记录,然后进行分组统计
  42. data['countries_en'] = data['countries_en'].str.lower()
  43. # 2. 数据分组统计
  44. country_additives = data['additives_n'].groupby(data['countries_en']).mean()
  45. # 3. 按值从大到小排序
  46. result = country_additives.sort_values(ascending=False)
  47. # 4. pandas可视化top10
  48. result.iloc[:10].plot.bar()
  49. plt.show()
  50. # 5. 保存处理结果
  51. result.to_csv('./country_additives.csv')
  52. # 删除解压数据,清理空间
  53. if os.path.exists(dataset_filepath):
  54. os.remove(dataset_filepath)
  55. if __name__ == '__main__':
  56. run_main()

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多