-: | :-----: | :----: | :-------: |
| 0 | 1 | 1 | 4.0 | 964982703 |
| 1 | 1 | 3 | 4.0 | 964981247 |
| 2 | 1 | 6 | 4.0 | 964982224 |
| 3 | 1 | 47 | 5.0 | 964983815 |
| 4 | 1 | 50 | 5.0 | 964982931 |

In [5]:

# 查看数据的形状,返回(行数、列数)
ratings.shape

Out[5]:

(100836, 4)

In [6]:

# 查看列名列表
ratings.columns

Out[6]:

Index(['userId', 'movieId', 'rating', 'timestamp'], dtype='object')

In [7]:

# 查看索引列
ratings.index

Out[7]:

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

In [8]:

# 查看每列的数据类型
ratings.dtypes

Out[8]:

userId         int64
movieId        int64
rating       float64
timestamp      int64
dtype: object

1.2 读取txt文件,自己指定分隔符、列名

In [9]:

fpath = "./datas/crazyant/access_pvuv.txt"

In [10]:

pvuv = pd.read_csv(
    fpath,
    sep="\t",
    header=None,
    names=['pdate', 'pv', 'uv']
)

In [11]:

pvuv

Out[11]:

pdatepvuv
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

2、读取excel文件

In [12]:

fpath = "./datas/crazyant/access_pvuv.xlsx"
pvuv = pd.read_excel(fpath)

In [13]:

pvuv

Out[13]:

日期PVUV
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

3、读取MySQL数据库

In [14]:

import pymysql
conn = pymysql.connect(
        host='127.0.0.1',
        user='root',
        password='12345678',
        database='test',
        charset='utf8'
    )

In [15]:

mysql_page = pd.read_sql("select * from crazyant_pvuv", con=conn)

In [16]:

mysql_page

Out[16]:

pdatepvuv
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

03. Pandas数据结构

  1. Series
  2. DataFrame
  3. 从DataFrame中查询出Series

In [1]:

import pandas as pd
import numpy as np

1. Series

Series是一种类似于一维数组的对象,它由一组数据(不同数据类型)以及一组与之相关的数据标签(即索引)组成。

1.1 仅有数据列表即可产生最简单的Series

In [2]:

s1 = pd.Series([1,'a',5.2,7])

In [3]:

# 左侧为索引,右侧是数据
s1

Out[3]:

0      1
1      a
2    5.2
3      7
dtype: object

In [4]:

# 获取索引
s1.index

Out[4]:

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

In [5]:

# 获取数据
s1.values

Out[5]:

array([1, 'a', 5.2, 7], dtype=object)

1.2 创建一个具有标签索引的Series

In [6]:

s2 = pd.Series([1, 'a', 5.2, 7], index=['d','b','a','c'])

In [7]:

s2

Out[7]:

d      1
b      a
a    5.2
c      7
dtype: object

In [8]:

s2.index

Out[8]:

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

1.3 使用Python字典创建Series

In [9]:

sdata={'Ohio':35000,'Texas':72000,'Oregon':16000,'Utah':5000}

In [10]:

s3=pd.Series(sdata)

In [11]:

s3

Out[11]:

Ohio      35000
Texas     72000
Oregon    16000
Utah       5000
dtype: int64

1.4 根据标签索引查询数据

类似Python的字典dict

In [12]:

s2

Out[12]:

d      1
b      a
a    5.2
c      7
dtype: object

In [13]:

s2['a']

Out[13]:

5.2

In [14]:

type(s2['a'])

Out[14]:

float

In [15]:

s2[['b','a']]

Out[15]:

b      a
a    5.2
dtype: object

In [16]:

type(s2[['b','a']])

Out[16]:

pandas.core.series.Series

2. DataFrame

DataFrame是一个表格型的数据结构

  • 每列可以是不同的值类型(数值、字符串、布尔值等)
  • 既有行索引index,也有列索引columns
  • 可以被看做由Series组成的字典

创建dataframe最常用的方法,见02节读取纯文本文件、excel、mysql数据库

2.1 根据多个字典序列创建dataframe

In [17]:

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

In [18]:

df

Out[18]:

stateyearpop
0Ohio20001.5
1Ohio20011.7
2Ohio20023.6
3Nevada20012.4
4Nevada20022.9

In [19]:

df.dtypes

Out[19]:

state     object
year       int64
pop      float64
dtype: object

In [20]:

df.columns

Out[20]:

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

In [21]:

df.index

Out[21]:

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

3. 从DataFrame中查询出Series

  • 如果只查询一行、一列,返回的是pd.Series
  • 如果查询多行、多列,返回的是pd.DataFrame

In [22]:

df

Out[22]:

stateyearpop
0Ohio20001.5
1Ohio20011.7
2Ohio20023.6
3Nevada20012.4
4Nevada20022.9

3.1 查询一列,结果是一个pd.Series

In [23]:

df['year']

Out[23]:

0    2000
1    2001
2    2002
3    2001
4    2002
Name: year, dtype: int64

In [24]:

type(df['year'])

Out[24]:

pandas.core.series.Series

3.2 查询多列,结果是一个pd.DataFrame

In [25]:

df[['year', 'pop']]

Out[25]:

yearpop
020001.5
120011.7
220023.6
320012.4
420022.9

In [26]:

type(df[['year', 'pop']])

Out[26]:

pandas.core.frame.DataFrame

3.3 查询一行,结果是一个pd.Series

In [27]:

df.loc[1]

Out[27]:

state    Ohio
year     2001
pop       1.7
Name: 1, dtype: object

In [28]:

type(df.loc[1])

Out[28]:

pandas.core.series.Series

3.4 查询多行,结果是一个pd.DataFrame

In [29]:

df.loc[1:3]

Out[29]:

stateyearpop
1Ohio20011.7
2Ohio20023.6
3Nevada20012.4

In [30]:

type(df.loc[1:3])

Out[30]:

pandas.core.frame.DataFrame

04、Pandas查询数据

Pandas查询数据的几种方法

  1. df.loc方法,根据行、列的标签值查询
  2. df.iloc方法,根据行、列的数字位置查询
  3. df.where方法
  4. df.query方法

.loc既能查询,又能覆盖写入,强烈推荐!

Pandas使用df.loc查询数据的方法

  1. 使用单个label值查询数据
  2. 使用值列表批量查询
  3. 使用数值区间进行范围查询
  4. 使用条件表达式查询
  5. 调用函数查询

注意

  • 以上查询方法,既适用于行,也适用于列
  • 注意观察降维dataFrame>Series>值

In [23]:

import pandas as pd
print(pd.__version__)
1.0.1

0、读取数据

数据为北京2018年全年天气预报
该数据的爬虫教程参见我的Python爬虫系列视频课程

In [2]:

df = pd.read_csv("./datas/beijing_tianqi/beijing_tianqi_2018.csv")

In [3]:

df.head()

Out[3]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013℃-6℃晴~多云东北风1-2级592
12018-01-022℃-5℃阴~多云东北风1-2级491
22018-01-032℃-5℃多云北风1-2级281
32018-01-040℃-8℃东北风1-2级281
42018-01-053℃-6℃多云~晴西北风1-2级501

In [4]:

# 设定索引为日期,方便按日期筛选
df.set_index('ymd', inplace=True)

In [5]:

# 时间序列见后续课程,本次按字符串处理
df.index

Out[5]:

Index(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', '2018-01-05',
       '2018-01-06', '2018-01-07', '2018-01-08', '2018-01-09', '2018-01-10',
       ...
       '2018-12-22', '2018-12-23', '2018-12-24', '2018-12-25', '2018-12-26',
       '2018-12-27', '2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31'],
      dtype='object', name='ymd', length=365)

In [6]:

df.head()

Out[6]:

bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-01-013℃-6℃晴~多云东北风1-2级592
2018-01-022℃-5℃阴~多云东北风1-2级491
2018-01-032℃-5℃多云北风1-2级281
2018-01-040℃-8℃东北风1-2级281
2018-01-053℃-6℃多云~晴西北风1-2级501

In [7]:

# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')

In [8]:

df.dtypes

Out[8]:

bWendu        int32
yWendu        int32
tianqi       object
fengxiang    object
fengli       object
aqi           int64
aqiInfo      object
aqiLevel      int64
dtype: object

In [9]:

df.head()

Out[9]:

bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-01-013-6晴~多云东北风1-2级592
2018-01-022-5阴~多云东北风1-2级491
2018-01-032-5多云北风1-2级281
2018-01-040-8东北风1-2级281
2018-01-053-6多云~晴西北风1-2级501

1、使用单个label值查询数据

行或者列,都可以只传入单个值,实现精确匹配

In [10]:

# 得到单个值
df.loc['2018-01-03', 'bWendu']

Out[10]:

2

In [11]:

# 得到一个Series
df.loc['2018-01-03', ['bWendu', 'yWendu']]

Out[11]:

bWendu     2
yWendu    -5
Name: 2018-01-03, dtype: object

2、使用值列表批量查询

In [12]:

# 得到Series
df.loc[['2018-01-03','2018-01-04','2018-01-05'], 'bWendu']

Out[12]:

ymd
2018-01-03    2
2018-01-04    0
2018-01-05    3
Name: bWendu, dtype: int32

In [13]:

# 得到DataFrame
df.loc[['2018-01-03','2018-01-04','2018-01-05'], ['bWendu', 'yWendu']]

Out[13]:

bWenduyWendu
ymd
2018-01-032-5
2018-01-040-8
2018-01-053-6

3、使用数值区间进行范围查询

注意:区间既包含开始,也包含结束

In [14]:

# 行index按区间
df.loc['2018-01-03':'2018-01-05', 'bWendu']

Out[14]:

ymd
2018-01-03    2
2018-01-04    0
2018-01-05    3
Name: bWendu, dtype: int32

In [15]:

# 列index按区间
df.loc['2018-01-03', 'bWendu':'fengxiang']

Out[15]:

bWendu        2
yWendu       -5
tianqi       多云
fengxiang    北风
Name: 2018-01-03, dtype: object

In [16]:

# 行和列都按区间查询
df.loc['2018-01-03':'2018-01-05', 'bWendu':'fengxiang']

Out[16]:

bWenduyWendutianqifengxiang
ymd
2018-01-032-5多云北风
2018-01-040-8东北风
2018-01-053-6多云~晴西北风

4、使用条件表达式查询

bool列表的长度得等于行数或者列数

简单条件查询,最低温度低于-10度的列表

In [17]:

df.loc[df["yWendu"]<-10, :]

Out[17]:

bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-01-23-4-12西北风3-4级311
2018-01-24-4-11西南风1-2级341
2018-01-25-3-11多云东北风1-2级271
2018-12-26-2-11晴~多云东北风2级261
2018-12-27-5-12多云~晴西北风3级481
2018-12-28-3-11西北风3级401
2018-12-29-3-12西北风2级291
2018-12-30-2-11晴~多云东北风1级311

In [18]:

# 观察一下这里的boolean条件
df["yWendu"]<-10

Out[18]:

ymd
2018-01-01    False
2018-01-02    False
2018-01-03    False
2018-01-04    False
2018-01-05    False
              ...  
2018-12-27     True
2018-12-28     True
2018-12-29     True
2018-12-30     True
2018-12-31    False
Name: yWendu, Length: 365, dtype: bool

复杂条件查询,查一下我心中的完美天气

注意,组合条件用&符号合并,每个条件判断都得带括号

In [19]:

## 查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据
df.loc[(df["bWendu"]<=30) & (df["yWendu"]>=15) & (df["tianqi"]=='晴') & (df["aqiLevel"]==1), :]

Out[19]:

bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-08-243020北风1-2级401
2018-09-072716西北风3-4级221

我哭,北京好天气这么稀少!!

In [20]:

# 再次观察这里的boolean条件
(df["bWendu"]<=30) & (df["yWendu"]>=15) & (df["tianqi"]=='晴') & (df["aqiLevel"]==1)

Out[20]:

ymd
2018-01-01    False
2018-01-02    False
2018-01-03    False
2018-01-04    False
2018-01-05    False
              ...  
2018-12-27    False
2018-12-28    False
2018-12-29    False
2018-12-30    False
2018-12-31    False
Length: 365, dtype: bool

5、调用函数查询

In [21]:

# 直接写lambda表达式
df.loc[lambda df : (df["bWendu"]<=30) & (df["yWendu"]>=15), :]

Out[21]:

bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-04-282717西南风3-4级125轻度污染3
2018-04-293016多云南风3-4级193中度污染4
2018-05-042716晴~多云西南风1-2级862
2018-05-092917晴~多云西南风3-4级792
2018-05-102618多云南风3-4级118轻度污染3
...........................
2018-09-152615多云北风3-4级421
2018-09-172717多云~阴北风1-2级371
2018-09-182517阴~多云西南风1-2级501
2018-09-192617多云南风1-2级522
2018-09-202716多云西南风1-2级632

64 rows × 8 columns

In [22]:

# 编写自己的函数,查询9月份,空气质量好的数据
def query_my_data(df):
    return df.index.str.startswith("2018-09") & (df["aqiLevel"]==1)
    
df.loc[query_my_data, :]

Out[22]:

bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-09-012719阴~小雨南风1-2级501
2018-09-043118西南风3-4级241
2018-09-053119晴~多云西南风3-4级341
2018-09-062718多云~晴西北风4-5级371
2018-09-072716西北风3-4级221
2018-09-082715多云~晴北风1-2级281
2018-09-152615多云北风3-4级421
2018-09-162514多云~晴北风1-2级291
2018-09-172717多云~阴北风1-2级371
2018-09-182517阴~多云西南风1-2级501
2018-09-212514西北风3-4级501
2018-09-222413西北风3-4级281
2018-09-232312西北风4-5级281
2018-09-242311北风1-2级281
2018-09-252412晴~多云南风1-2级441
2018-09-292211北风3-4级211
2018-09-301913多云西北风4-5级221

05、Pandas怎样新增数据列?

在进行数据分析时,经常需要按照一定条件创建新的数据列,然后进行进一步分析。

  1. 直接赋值
  2. df.apply方法
  3. df.assign方法
  4. 按条件选择分组分别赋值 微信公众号:蚂蚁学Python

In [1]:

import pandas as pd

0、读取csv数据到dataframe

In [2]:

fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)

In [3]:

df.head()

Out[3]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013℃-6℃晴~多云东北风1-2级592
12018-01-022℃-5℃阴~多云东北风1-2级491
22018-01-032℃-5℃多云北风1-2级281
32018-01-040℃-8℃东北风1-2级281
42018-01-053℃-6℃多云~晴西北风1-2级501

1、直接赋值的方法

实例:清理温度列,变成数字类型

In [4]:

# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')

In [6]:

df.head()

Out[6]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013-6晴~多云东北风1-2级592
12018-01-022-5阴~多云东北风1-2级491
22018-01-032-5多云北风1-2级281
32018-01-040-8东北风1-2级281
42018-01-053-6多云~晴西北风1-2级501

实例:计算温差

In [9]:

# 注意,df["bWendu"]其实是一个Series,后面的减法返回的是Series
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]

In [10]:

df.head()

Out[10]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwencha
02018-01-013-6晴~多云东北风1-2级5929
12018-01-022-5阴~多云东北风1-2级4917
22018-01-032-5多云北风1-2级2817
32018-01-040-8东北风1-2级2818
42018-01-053-6多云~晴西北风1-2级5019

2、df.apply方法

Apply a function along an axis of the DataFrame.

Objects passed to the function are Series objects whose index is either the DataFrame’s index (axis=0) or the DataFrame’s columns (axis=1).

实例:添加一列温度类型:

  1. 如果最高温度大于33度就是高温
  2. 低于-10度是低温
  3. 否则是常温

In [11]:

def get_wendu_type(x):
    if x["bWendu"] > 33:
        return '高温'
    if x["yWendu"] < -10:
        return '低温'
    return '常温'

# 注意需要设置axis==1,这是series的index是columns
df.loc[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)

In [12]:

# 查看温度类型的计数
df["wendu_type"].value_counts()

Out[12]:

常温    328
高温     29
低温      8
Name: wendu_type, dtype: int64

3、df.assign方法

Assign new columns to a DataFrame.

Returns a new object with all original columns in addition to new ones.

实例:将温度从摄氏度变成华氏度

In [13]:

# 可以同时添加多个新的列
df.assign(
    yWendu_huashi = lambda x : x["yWendu"] * 9 / 5 + 32,
    # 摄氏度转华氏度
    bWendu_huashi = lambda x : x["bWendu"] * 9 / 5 + 32
)

Out[13]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwenchawendu_typeyWendu_huashibWendu_huashi
02018-01-013-6晴~多云东北风1-2级5929常温21.237.4
12018-01-022-5阴~多云东北风1-2级4917常温23.035.6
22018-01-032-5多云北风1-2级2817常温23.035.6
32018-01-040-8东北风1-2级2818常温17.632.0
42018-01-053-6多云~晴西北风1-2级5019常温21.237.4
..........................................
3602018-12-27-5-12多云~晴西北风3级4817低温10.423.0
3612018-12-28-3-11西北风3级4018低温12.226.6
3622018-12-29-3-12西北风2级2919低温10.426.6
3632018-12-30-2-11晴~多云东北风1级3119低温12.228.4
3642018-12-31-2-10多云东北风1级5628常温14.028.4

365 rows × 13 columns

4、按条件选择分组分别赋值

按条件先选择数据,然后对这部分数据赋值新列
实例:高低温差大于10度,则认为温差大

In [14]:

# 先创建空列(这是第一种创建新列的方法)
df['wencha_type'] = ''

df.loc[df["bWendu"]-df["yWendu"]>10, "wencha_type"] = "温差大"

df.loc[df["bWendu"]-df["yWendu"]<=10, "wencha_type"] = "温差正常"

In [15]:

df["wencha_type"].value_counts()

Out[15]:

温差正常    187
温差大     178
Name: wencha_type, dtype: int64

06、Pandas数据统计函数

  1. 汇总类统计
  2. 唯一去重和按值计数
  3. 相关系数和协方差

In [1]:

import pandas as pd

0、读取csv数据

In [2]:

fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)

In [3]:

df.head(3)

Out[3]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013℃-6℃晴~多云东北风1-2级592
12018-01-022℃-5℃阴~多云东北风1-2级491
22018-01-032℃-5℃多云北风1-2级281

In [4]:

# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')

In [5]:

df.head(3)

Out[5]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013-6晴~多云东北风1-2级592
12018-01-022-5阴~多云东北风1-2级491
22018-01-032-5多云北风1-2级281

1、汇总类统计

In [6]:

# 一下子提取所有数字列统计结果
df.describe()

Out[6]:

bWenduyWenduaqiaqiLevel
count365.000000365.000000365.000000365.000000
mean18.6657538.35890482.1835622.090411
std11.85804611.75505351.9361591.029798
min-5.000000-12.00000021.0000001.000000
25%8.000000-3.00000046.0000001.000000
50%21.0000008.00000069.0000002.000000
75%29.00000019.000000104.0000003.000000
max38.00000027.000000387.0000006.000000

In [7]:

## 查看单个Series的数据
df["bWendu"].mean()

Out[7]:

18.665753424657535

In [8]:

# 最高温
df["bWendu"].max()

Out[8]:

38

In [9]:

# 最低温
df["bWendu"].min()

Out[9]:

-5

2、唯一去重和按值计数

2.1 唯一性去重

一般不用于数值列,而是枚举、分类列

In [10]:

df["fengxiang"].unique()

Out[10]:

array(['东北风', '北风', '西北风', '西南风', '南风', '东南风', '东风', '西风'], dtype=object)

In [11]:

df["tianqi"].unique()

Out[11]:

array(['晴~多云', '阴~多云', '多云', '阴', '多云~晴', '多云~阴', '晴', '阴~小雪', '小雪~多云',
       '小雨~阴', '小雨~雨夹雪', '多云~小雨', '小雨~多云', '大雨~小雨', '小雨', '阴~小雨',
       '多云~雷阵雨', '雷阵雨~多云', '阴~雷阵雨', '雷阵雨', '雷阵雨~大雨', '中雨~雷阵雨', '小雨~大雨',
       '暴雨~雷阵雨', '雷阵雨~中雨', '小雨~雷阵雨', '雷阵雨~阴', '中雨~小雨', '小雨~中雨', '雾~多云',
       '霾'], dtype=object)

In [12]:

df["fengli"].unique()

Out[12]:

array(['1-2级', '4-5级', '3-4级', '2级', '1级', '3级'], dtype=object)

2.2 按值计数

In [13]:

df["fengxiang"].value_counts()

Out[13]:

南风     92
西南风    64
北风     54
西北风    51
东南风    46
东北风    38
东风     14
西风      6
Name: fengxiang, dtype: int64

In [14]:

df["tianqi"].value_counts()

Out[14]:

晴         101
多云         95
多云~晴       40
晴~多云       34
多云~雷阵雨     14
多云~阴       10
阴~多云        8
小雨~多云       8
雷阵雨         8
雷阵雨~多云      7
小雨          6
多云~小雨       5
阴           4
雷阵雨~中雨      4
中雨~小雨       2
中雨~雷阵雨      2
阴~小雨        2
霾           2
阴~小雪        1
小雪~多云       1
大雨~小雨       1
小雨~雷阵雨      1
小雨~中雨       1
小雨~雨夹雪      1
雾~多云        1
雷阵雨~阴       1
暴雨~雷阵雨      1
小雨~阴        1
雷阵雨~大雨      1
阴~雷阵雨       1
小雨~大雨       1
Name: tianqi, dtype: int64

In [15]:

df["fengli"].value_counts()

Out[15]:

1-2级    236
3-4级     68
1级       21
4-5级     20
2级       13
3级        7
Name: fengli, dtype: int64

3、相关系数和协方差

用途(超级厉害):

  1. 两只股票,是不是同涨同跌?程度多大?正相关还是负相关?
  2. 产品销量的波动,跟哪些因素正相关、负相关,程度有多大?

来自知乎,对于两个变量X、Y:

  1. 协方差:*衡量同向反向程度*,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高。
  2. 相关系数:*衡量相似度程度*,当他们的相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为-1时,说明两个变量变化的反向相似度最大

In [16]:

# 协方差矩阵:
df.cov()

Out[16]:

bWenduyWenduaqiaqiLevel
bWendu140.613247135.52963347.4626220.879204
yWendu135.529633138.18127416.1866850.264165
aqi47.46262216.1866852697.36456450.749842
aqiLevel0.8792040.26416550.7498421.060485

In [17]:

# 相关系数矩阵
df.corr()

Out[17]:

bWenduyWenduaqiaqiLevel
bWendu1.0000000.9722920.0770670.071999
yWendu0.9722921.0000000.0265130.021822
aqi0.0770670.0265131.0000000.948883
aqiLevel0.0719990.0218220.9488831.000000

In [18]:

# 单独查看空气质量和最高温度的相关系数
df["aqi"].corr(df["bWendu"])

Out[18]:

0.07706705916811077

In [19]:

df["aqi"].corr(df["yWendu"])

Out[19]:

0.02651328267296879

In [20]:

# 空气质量和温差的相关系数
df["aqi"].corr(df["bWendu"]-df["yWendu"])

Out[20]:

0.21652257576382047

In [ ]:

# !! 这就是特征工程对于机器学习重要性的一个例子

In [21]:

0.21/0.02

Out[21]:

10.5

07、Pandas对缺失值的处理

Pandas使用这些函数处理缺失值:

  • isnull和notnull:检测是否是空值,可用于df和series
  • dropna:丢弃、删除缺失值
    • axis : 删除行还是列,{0 or ‘index’, 1 or ‘columns’}, default 0
    • how : 如果等于any则任何值为空都删除,如果等于all则所有值都为空才删除
    • inplace : 如果为True则修改当前df,否则返回新的df
  • fillna:填充空值
    • value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
    • method : 等于ffill使用前一个不为空的值填充forword fill;等于bfill使用后一个不为空的值填充backword fill
    • axis : 按行还是列填充,{0 or ‘index’, 1 or ‘columns’}
    • inplace : 如果为True则修改当前df,否则返回新的df

In [1]:

import pandas as pd

实例:特殊Excel的读取、清洗、处理

步骤1:读取excel的时候,忽略前几个空行

In [2]:

studf = pd.read_excel("./datas/student_excel/student_excel.xlsx", skiprows=2)

In [3]:

studf

Out[3]:

Unnamed: 0姓名科目分数
0NaN小明语文85.0
1NaNNaN数学80.0
2NaNNaN英语90.0
3NaNNaNNaNNaN
4NaN小王语文85.0
5NaNNaN数学NaN
6NaNNaN英语90.0
7NaNNaNNaNNaN
8NaN小刚语文85.0
9NaNNaN数学80.0
10NaNNaN英语90.0

步骤2:检测空值

In [4]:

studf.isnull()

Out[4]:

Unnamed: 0姓名科目分数
0TrueFalseFalseFalse
1TrueTrueFalseFalse
2TrueTrueFalseFalse
3TrueTrueTrueTrue
4TrueFalseFalseFalse
5TrueTrueFalseTrue
6TrueTrueFalseFalse
7TrueTrueTrueTrue
8TrueFalseFalseFalse
9TrueTrueFalseFalse
10TrueTrueFalseFalse

In [5]:

studf["分数"].isnull()

Out[5]:

0     False
1     False
2     False
3      True
4     False
5      True
6     False
7      True
8     False
9     False
10    False
Name: 分数, dtype: bool

In [6]:

studf["分数"].notnull()

Out[6]:

0      True
1      True
2      True
3     False
4      True
5     False
6      True
7     False
8      True
9      True
10     True
Name: 分数, dtype: bool

In [7]:

# 筛选没有空分数的所有行
studf.loc[studf["分数"].notnull(), :]

Out[7]:

Unnamed: 0姓名科目分数
0NaN小明语文85.0
1NaNNaN数学80.0
2NaNNaN英语90.0
4NaN小王语文85.0
6NaNNaN英语90.0
8NaN小刚语文85.0
9NaNNaN数学80.0
10NaNNaN英语90.0

步骤3:删除掉全是空值的列

In [8]:

studf.dropna(axis="columns", how='all', inplace=True)

In [9]:

studf

Out[9]:

姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
3NaNNaNNaN
4小王语文85.0
5NaN数学NaN
6NaN英语90.0
7NaNNaNNaN
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0

步骤4:删除掉全是空值的行

In [10]:

studf.dropna(axis="index", how='all', inplace=True)

In [11]:

studf

Out[11]:

姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
4小王语文85.0
5NaN数学NaN
6NaN英语90.0
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0

步骤5:将分数列为空的填充为0分

In [12]:

studf.fillna({"分数":0})

Out[12]:

姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
4小王语文85.0
5NaN数学0.0
6NaN英语90.0
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0

In [13]:

# 等同于
studf.loc[:, '分数'] = studf['分数'].fillna(0)

In [14]:

studf

Out[14]:

姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
4小王语文85.0
5NaN数学0.0
6NaN英语90.0
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0

步骤6:将姓名的缺失值填充

使用前面的有效值填充,用ffill:forward fill

In [15]:

studf.loc[:, '姓名'] = studf['姓名'].fillna(method="ffill")

In [16]:

studf

Out[16]:

姓名科目分数
0小明语文85.0
1小明数学80.0
2小明英语90.0
4小王语文85.0
5小王数学0.0
6小王英语90.0
8小刚语文85.0
9小刚数学80.0
10小刚英语90.0

步骤7:将清洗好的excel保存

In [17]:

studf.to_excel("./datas/student_excel/student_excel_clean.xlsx", index=False)

08、Pandas的SettingWithCopyWarning报警

0、读取数据

In [1]:

import pandas as pd

In [2]:

fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)

In [3]:

df.head()

Out[3]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013℃-6℃晴~多云东北风1-2级592
12018-01-022℃-5℃阴~多云东北风1-2级491
22018-01-032℃-5℃多云北风1-2级281
32018-01-040℃-8℃东北风1-2级281
42018-01-053℃-6℃多云~晴西北风1-2级501

In [4]:

# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')

In [5]:

df.head()

Out[5]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013-6晴~多云东北风1-2级592
12018-01-022-5阴~多云东北风1-2级491
22018-01-032-5多云北风1-2级281
32018-01-040-8东北风1-2级281
42018-01-053-6多云~晴西北风1-2级501

1、复现

In [6]:

# 只选出3月份的数据用于分析
condition = df["ymd"].str.startswith("2018-03")

In [7]:

# 设置温差
df[condition]["wen_cha"] = df["bWendu"]-df["yWendu"]
d:\appdata\python37\lib\site-packages\ipykernel_launcher.py:2: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  

In [8]:

# 查看是否修改成功
df[condition].head()

Out[8]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
592018-03-018-3多云西南风1-2级461
602018-03-029-1晴~多云北风1-2级952
612018-03-03133多云~阴北风1-2级214重度污染5
622018-03-047-2阴~多云东南风1-2级144轻度污染3
632018-03-058-3南风1-2级942

2、原因

发出警告的代码 df[condition]["wen_cha"] = df["bWendu"]-df["yWendu"]

相当于:df.get(condition).set(wen_cha),第一步骤的get发出了报警

*链式操作其实是两个步骤,先get后set,get得到的dataframe可能是view也可能是copy,pandas发出警告*

官网文档: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

核心要诀:pandas的dataframe的修改写操作,只允许在源dataframe上进行,一步到位

3、解决方法1

将get+set的两步操作,改成set的一步操作

In [9]:

df.loc[condition, "wen_cha"] = df["bWendu"]-df["yWendu"]

In [10]:

df[condition].head()

Out[10]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwen_cha
592018-03-018-3多云西南风1-2级46111.0
602018-03-029-1晴~多云北风1-2级95210.0
612018-03-03133多云~阴北风1-2级214重度污染510.0
622018-03-047-2阴~多云东南风1-2级144轻度污染39.0
632018-03-058-3南风1-2级94211.0

4、解决方法2

如果需要预筛选数据做后续的处理分析,使用copy复制dataframe

In [11]:

df_month3 = df[condition].copy()

In [12]:

df_month3.head()

Out[12]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwen_cha
592018-03-018-3多云西南风1-2级46111.0
602018-03-029-1晴~多云北风1-2级95210.0
612018-03-03133多云~阴北风1-2级214重度污染510.0
622018-03-047-2阴~多云东南风1-2级144轻度污染39.0
632018-03-058-3南风1-2级94211.0

In [13]:

df_month3["wen_cha"] = df["bWendu"]-df["yWendu"]

In [14]:

df_month3.head()

Out[14]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwen_cha
592018-03-018-3多云西南风1-2级46111
602018-03-029-1晴~多云北风1-2级95210
612018-03-03133多云~阴北风1-2级214重度污染510
622018-03-047-2阴~多云东南风1-2级144轻度污染39
632018-03-058-3南风1-2级94211

*总之,pandas不允许先筛选子dataframe,再进行修改写入*
要么使用.loc实现一个步骤直接修改源dataframe
要么先复制一个子dataframe再一个步骤执行修改

09、Pandas数据排序

Series的排序:
*Series.sort_values(ascending=True, inplace=False)*
参数说明:

  • ascending:默认为True升序排序,为False降序排序
  • inplace:是否修改原始Series

DataFrame的排序:
*DataFrame.sort_values(by, ascending=True, inplace=False)*
参数说明:

  • by:字符串或者List<字符串>,单列排序或者多列排序
  • ascending:bool或者List,升序还是降序,如果是list对应by的多列
  • inplace:是否修改原始DataFrame

In [2]:

import pandas as pd

0、读取数据

In [3]:

fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)

# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')

In [4]:

df.head()

Out[4]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013-6晴~多云东北风1-2级592
12018-01-022-5阴~多云东北风1-2级491
22018-01-032-5多云北风1-2级281
32018-01-040-8东北风1-2级281
42018-01-053-6多云~晴西北风1-2级501

1、Series的排序

In [5]:

df["aqi"].sort_values()

Out[5]:

271     21
281     21
249     22
272     22
301     22
      ... 
317    266
71     287
91     287
72     293
86     387
Name: aqi, Length: 365, dtype: int64

In [6]:

df["aqi"].sort_values(ascending=False)

Out[6]:

86     387
72     293
91     287
71     287
317    266
      ... 
301     22
272     22
249     22
281     21
271     21
Name: aqi, Length: 365, dtype: int64

In [8]:

df["tianqi"].sort_values()

Out[8]:

225     中雨~小雨
230     中雨~小雨
197    中雨~雷阵雨
196    中雨~雷阵雨
112        多云
        ...  
191    雷阵雨~大雨
219     雷阵雨~阴
335      雾~多云
353         霾
348         霾
Name: tianqi, Length: 365, dtype: object

2、DataFrame的排序

2.1 单列排序

In [9]:

df.sort_values(by="aqi")

Out[9]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
2712018-09-292211北风3-4级211
2812018-10-09154多云~晴西北风4-5级211
2492018-09-072716西北风3-4级221
2722018-09-301913多云西北风4-5级221
3012018-10-29153北风3-4级221
..............................
3172018-11-14135多云南风1-2级266重度污染5
712018-03-13175晴~多云南风1-2级287重度污染5
912018-04-022611多云北风1-2级287重度污染5
722018-03-14156多云~阴东北风1-2级293重度污染5
862018-03-28259多云~晴东风1-2级387严重污染6

365 rows × 9 columns

In [10]:

df.sort_values(by="aqi", ascending=False)

Out[10]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
862018-03-28259多云~晴东风1-2级387严重污染6
722018-03-14156多云~阴东北风1-2级293重度污染5
712018-03-13175晴~多云南风1-2级287重度污染5
912018-04-022611多云北风1-2级287重度污染5
3172018-11-14135多云南风1-2级266重度污染5
..............................
2492018-09-072716西北风3-4级221
3012018-10-29153北风3-4级221
2722018-09-301913多云西北风4-5级221
2712018-09-292211北风3-4级211
2812018-10-09154多云~晴西北风4-5级211

365 rows × 9 columns

2.2 多列排序

In [11]:

# 按空气质量等级、最高温度排序,默认升序
df.sort_values(by=["aqiLevel", "bWendu"])

Out[11]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
3602018-12-27-5-12多云~晴西北风3级481
222018-01-23-4-12西北风3-4级311
232018-01-24-4-11西南风1-2级341
3402018-12-07-4-10西北风3级331
212018-01-22-3-10小雪~多云东风1-2级471
..............................
712018-03-13175晴~多云南风1-2级287重度污染5
902018-04-012511晴~多云南风1-2级218重度污染5
912018-04-022611多云北风1-2级287重度污染5
852018-03-272711南风1-2级243重度污染5
862018-03-28259多云~晴东风1-2级387严重污染6

365 rows × 9 columns

In [12]:

# 两个字段都是降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=False)

Out[12]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
862018-03-28259多云~晴东风1-2级387严重污染6
852018-03-272711南风1-2级243重度污染5
912018-04-022611多云北风1-2级287重度污染5
902018-04-012511晴~多云南风1-2级218重度污染5
712018-03-13175晴~多云南风1-2级287重度污染5
..............................
3622018-12-29-3-12西北风2级291
222018-01-23-4-12西北风3-4级311
232018-01-24-4-11西南风1-2级341
3402018-12-07-4-10西北风3级331
3602018-12-27-5-12多云~晴西北风3级481

365 rows × 9 columns

In [13]:

# 分别指定升序和降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=[True, False])

Out[13]:

ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
1782018-06-283524多云~晴北风1-2级331
1492018-05-303318西风1-2级461
2062018-07-263325多云~雷阵雨东北风1-2级401
1582018-06-083219多云~雷阵雨西南风1-2级431
2052018-07-253225多云北风1-2级281
..............................
3172018-11-14135多云南风1-2级266重度污染5
3292018-11-26100多云东南风1级245重度污染5
3352018-12-0292雾~多云东北风1级234重度污染5
572018-02-2770东风1-2级220重度污染5
862018-03-28259多云~晴东风1-2级387严重污染6

365 rows × 9 columns