import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df1 = pd.DataFrame(np.arange(1000, 1100, 4).reshape(5,5), index=['a'+str(i) for i in range(5)], columns=['b'+str(j) for j in range(5)])
df1
|
b0 |
b1 |
b2 |
b3 |
b4 |
a0 |
1000 |
1004 |
1008 |
1012 |
1016 |
a1 |
1020 |
1024 |
1028 |
1032 |
1036 |
a2 |
1040 |
1044 |
1048 |
1052 |
1056 |
a3 |
1060 |
1064 |
1068 |
1072 |
1076 |
a4 |
1080 |
1084 |
1088 |
1092 |
1096 |
df2 = pd.Series([1, 2, 3, np.nan, 5], index=list('abcde'))
df2
a 1.0
b 2.0
c 3.0
d NaN
e 5.0
dtype: float64
使用传递的numpy数组创建数据帧,并使用日期索引和标记列.
dates = pd.date_range('20190524',periods=6)
dates
print('-'*30)
df3 = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))
df3
------------------------------
|
A |
B |
C |
D |
2019-05-24 |
-0.860206 |
-0.549105 |
-1.357905 |
-0.847048 |
2019-05-25 |
1.913799 |
-0.655915 |
-0.638752 |
-0.459323 |
2019-05-26 |
0.249178 |
-1.658453 |
-2.278093 |
-0.745429 |
2019-05-27 |
0.452118 |
0.527087 |
-0.298735 |
-1.872822 |
2019-05-28 |
-1.472450 |
0.124642 |
1.554257 |
-0.085878 |
2019-05-29 |
-2.175467 |
-0.611948 |
-0.062950 |
-0.709390 |
使用传递的可转换序列的字典对象创建数据帧.
df4 = pd.DataFrame({
'id' : np.arange(4),
'date' : pd.Timestamp('20190524'),
'type' : pd.Series(1,index=list(range(4)),dtype='float32'),
'D' : np.array([3] * 4,dtype='int32'),
'E' : pd.Categorical(["test","train","test","train"]),
'F' : 'foo'
})
df4
|
id |
date |
type |
D |
E |
F |
0 |
0 |
2019-05-24 |
1.0 |
3 |
test |
foo |
1 |
1 |
2019-05-24 |
1.0 |
3 |
train |
foo |
2 |
2 |
2019-05-24 |
1.0 |
3 |
test |
foo |
3 |
3 |
2019-05-24 |
1.0 |
3 |
train |
foo |
单看index, columns, values
df4.index, df4.columns
(Int64Index([0, 1, 2, 3], dtype='int64'),
Index(['id', 'date', 'type', 'D', 'E', 'F'], dtype='object'))
df3.values
array([[-0.86020569, -0.5491055 , -1.3579045 , -0.84704786],
[ 1.91379872, -0.65591487, -0.63875153, -0.4593228 ],
[ 0.24917803, -1.65845292, -2.27809285, -0.74542856],
[ 0.45211825, 0.52708701, -0.29873468, -1.87282174],
[-1.47245001, 0.12464238, 1.55425716, -0.08587762],
[-2.17546674, -0.61194779, -0.06294959, -0.70938972]])
显示数据快速统计摘要
df3.describe()
|
A |
B |
C |
D |
count |
6.000000 |
6.000000 |
6.000000 |
6.000000 |
mean |
-0.315505 |
-0.470615 |
-0.513696 |
-0.786648 |
std |
1.481390 |
0.751155 |
1.293618 |
0.598216 |
min |
-2.175467 |
-1.658453 |
-2.278093 |
-1.872822 |
25% |
-1.319389 |
-0.644923 |
-1.178116 |
-0.821643 |
50% |
-0.305514 |
-0.580527 |
-0.468743 |
-0.727409 |
75% |
0.401383 |
-0.043795 |
-0.121896 |
-0.521840 |
max |
1.913799 |
0.527087 |
1.554257 |
-0.085878 |
df4.describe()
|
id |
type |
D |
count |
4.000000 |
4.0 |
4.0 |
mean |
1.500000 |
1.0 |
3.0 |
std |
1.290994 |
0.0 |
0.0 |
min |
0.000000 |
1.0 |
3.0 |
25% |
0.750000 |
1.0 |
3.0 |
50% |
1.500000 |
1.0 |
3.0 |
75% |
2.250000 |
1.0 |
3.0 |
max |
3.000000 |
1.0 |
3.0 |
转置
df4.T
|
0 |
1 |
2 |
3 |
id |
0 |
1 |
2 |
3 |
date |
2019-05-24 00:00:00 |
2019-05-24 00:00:00 |
2019-05-24 00:00:00 |
2019-05-24 00:00:00 |
type |
1 |
1 |
1 |
1 |
D |
3 |
3 |
3 |
3 |
E |
test |
train |
test |
train |
F |
foo |
foo |
foo |
foo |
按值排序
df3.sort_values(by='B')
|
A |
B |
C |
D |
2019-05-26 |
0.249178 |
-1.658453 |
-2.278093 |
-0.745429 |
2019-05-25 |
1.913799 |
-0.655915 |
-0.638752 |
-0.459323 |
2019-05-29 |
-2.175467 |
-0.611948 |
-0.062950 |
-0.709390 |
2019-05-24 |
-0.860206 |
-0.549105 |
-1.357905 |
-0.847048 |
2019-05-28 |
-1.472450 |
0.124642 |
1.554257 |
-0.085878 |
2019-05-27 |
0.452118 |
0.527087 |
-0.298735 |
-1.872822 |
按轴排序
df3.sort_index(axis=1, ascending=False)
|
D |
C |
B |
A |
2019-05-24 |
-0.847048 |
-1.357905 |
-0.549105 |
-0.860206 |
2019-05-25 |
-0.459323 |
-0.638752 |
-0.655915 |
1.913799 |
2019-05-26 |
-0.745429 |
-2.278093 |
-1.658453 |
0.249178 |
2019-05-27 |
-1.872822 |
-0.298735 |
0.527087 |
0.452118 |
2019-05-28 |
-0.085878 |
1.554257 |
0.124642 |
-1.472450 |
2019-05-29 |
-0.709390 |
-0.062950 |
-0.611948 |
-2.175467 |
选择-按标签选择 df.loc[]
# 切片 索引
print(df3['A'])
print('-'*30)
print(df4['E'])
print('-'*30)
print(df3[1:3])
print('-'*30)
print(df3['20190524':'20190525'])
2019-05-24 -0.860206
2019-05-25 1.913799
2019-05-26 0.249178
2019-05-27 0.452118
2019-05-28 -1.472450
2019-05-29 -2.175467
Freq: D, Name: A, dtype: float64
------------------------------
0 test
1 train
2 test
3 train
Name: E, dtype: category
Categories (2, object): [test, train]
------------------------------
A B C D
2019-05-25 1.913799 -0.655915 -0.638752 -0.459323
2019-05-26 0.249178 -1.658453 -2.278093 -0.745429
------------------------------
A B C D
2019-05-24 -0.860206 -0.549105 -1.357905 -0.847048
2019-05-25 1.913799 -0.655915 -0.638752 -0.459323
# 使用标签获取横截面,参考以下示例
dates = pd.date_range('20130101', periods=6)
df = pd.DataFrame(np.arange(1, 25).reshape(6,4), index=dates, columns=list('ABCD'))
df
|
A |
B |
C |
D |
2013-01-01 |
1 |
2 |
3 |
4 |
2013-01-02 |
5 |
6 |
7 |
8 |
2013-01-03 |
9 |
10 |
11 |
12 |
2013-01-04 |
13 |
14 |
15 |
16 |
2013-01-05 |
17 |
18 |
19 |
20 |
2013-01-06 |
21 |
22 |
23 |
24 |
# 使用标签获取横截面
print(df.loc[dates[0]])
A 1
B 2
C 3
D 4
Name: 2013-01-01 00:00:00, dtype: int32
# 索引切片-选择指定若干列
df.loc[:,['A','B']]
|
A |
B |
2013-01-01 |
1 |
2 |
2013-01-02 |
5 |
6 |
2013-01-03 |
9 |
10 |
2013-01-04 |
13 |
14 |
2013-01-05 |
17 |
18 |
2013-01-06 |
21 |
22 |
# 选取区域-行列同时切片索引
df.loc['20130102':'20130104', ['A', 'B']]
|
A |
B |
2013-01-02 |
5 |
6 |
2013-01-03 |
9 |
10 |
2013-01-04 |
13 |
14 |
# 由于切片索引自动降维
df.loc['20130102', ['A', 'B']]
A 5
B 6
Name: 2013-01-02 00:00:00, dtype: int32
# 取单个标量值-两种结果完全一样的方法loc位置, at位于
print(df.loc[dates[4], 'C'])
print(df.at[dates[4],'C'])
19
19
选择-按位置选择 df.iloc[]
# 选第三行。第三条。第三条记录
df.iloc[3]
A 13
B 14
C 15
D 16
Name: 2013-01-04 00:00:00, dtype: int32
# 选取3到5行,1到3列的区域形成新DataFrame
df.iloc[3:5, 1:3]
|
B |
C |
2013-01-04 |
14 |
15 |
2013-01-05 |
18 |
19 |
# 使用整数偏移定位列表,隔行选择, 可以多选,可以自定义重复
df.iloc[[1,2,2,4],[0,2]]
|
A |
C |
2013-01-02 |
5 |
7 |
2013-01-03 |
9 |
11 |
2013-01-03 |
9 |
11 |
2013-01-05 |
17 |
19 |
# 灵活使用列表生成条件表达式-疯狂复读重复某一行限定区块
df.iloc[[3 for i in range(5)],[0,2]]
|
A |
C |
2013-01-04 |
13 |
15 |
2013-01-04 |
13 |
15 |
2013-01-04 |
13 |
15 |
2013-01-04 |
13 |
15 |
2013-01-04 |
13 |
15 |
------------------------学习蚂蚁 pandas----------------------
快速开始-基本使用
import pandas as pd
fpath = './datas/ml-latest-small/ratings.csv'
# 使用 pd.read_csv 读取 csv 数据
ratings = pd.read_csv(fpath)
# 使用 df.head() 查看 dataframe 的前几行
ratings.head()
|
userId |
movieId |
rating |
timestamp |
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 |
# 使用 df.shape() 查看数据表的形状
ratings.shape # 看起来好像挺大的样子
(100836, 4)
# 列名列表
ratings.columns
Index(['userId', 'movieId', 'rating', 'timestamp'], dtype='object')
# 索引列表
ratings.index # 0-100836 步长1
RangeIndex(start=0, stop=100836, step=1)
# 每一列的数据类型
ratings.dtypes
userId int64
movieId int64
rating float64
timestamp int64
dtype: object
1、读取 txt 文件
path1 = './datas/crazyant/access_pvuv.txt'
df1 = pd.read_csv(
path1, # 源文件路径
sep='\t', # 以制表符为分隔符分割源文件
header=None, # 没有字段行,所以要设置 names
names=['pdata', 'pv', 'uv'] # 自定义列名列表
)
df1
|
pdata |
pv |
uv |
0 |
2019-09-10 |
139 |
92 |
1 |
2019-09-09 |
185 |
153 |
2 |
2019-09-08 |
123 |
59 |
3 |
2019-09-07 |
65 |
40 |
4 |
2019-09-06 |
157 |
98 |
5 |
2019-09-05 |
205 |
151 |
6 |
2019-09-04 |
196 |
167 |
7 |
2019-09-03 |
216 |
176 |
8 |
2019-09-02 |
227 |
148 |
9 |
2019-09-01 |
105 |
61 |
读取 excel 文件
path2 = './datas/crazyant/access_pvuv.xlsx'
df2 = pd.read_excel(path2)
df2
|
日期 |
PV |
UV |
0 |
2019-09-10 |
139 |
92 |
1 |
2019-09-09 |
185 |
153 |
2 |
2019-09-08 |
123 |
59 |
3 |
2019-09-07 |
65 |
40 |
4 |
2019-09-06 |
157 |
98 |
5 |
2019-09-05 |
205 |
151 |
6 |
2019-09-04 |
196 |
167 |
7 |
2019-09-03 |
216 |
176 |
8 |
2019-09-02 |
227 |
148 |
9 |
2019-09-01 |
105 |
61 |
读取 sql 数据库数据
import pymysql
# pandas 从数据库读取数据表需要有 mysql 连接
conn = pymysql.connect(
host='127.0.0.1',
user='root',
password='root',
database='stock',
charset='utf8'
)
# 从 数据库连接中通过执行原生sql读取数据表
df_sql = pd.read_sql('select * from k_goods', conn)
df_sql
|
ID |
PRODUCTNO |
PRODUCTNAME |
PRODUCTTYPE |
PRODUCTSTANDARD |
UNIT |
PRICE |
REMARK |
0 |
1 |
pdno_0001 |
计算器 |
桌面文具 |
00 |
个 |
20 |
None |
1 |
2 |
pdno_0002 |
回形针 |
桌面文具 |
00 |
个 |
5 |
None |
2 |
3 |
pdno_0003 |
中性笔 |
桌面文具 |
00 |
支 |
5 |
None |
3 |
4 |
pdno_0004 |
复印纸 |
纸制品 |
00 |
盒 |
10 |
None |
4 |
5 |
pdno_0005 |
账本 |
纸制品 |
00 |
本 |
2 |
None |
5 |
6 |
pdno_0006 |
拖布 |
办公生活用品 |
00 |
个 |
20 |
None |
6 |
7 |
pdno_0007 |
小蜜蜂扩音器 |
授课设备 |
00 |
个 |
25 |
None |
7 |
8 |
pdno_0008 |
纸杯 |
办公生活用品 |
00 |
个 |
5 |
None |
8 |
9 |
pdno_0009 |
白板 |
桌面文具 |
00 |
块 |
50 |
None |
9 |
10 |
pdno_0010 |
软面炒 |
纸制品 |
00 |
本 |
1 |
None |
10 |
11 |
pdno_0011 |
双面胶 |
桌面文具 |
00 |
个 |
2 |
None |
11 |
12 |
pdno_0012 |
文件夹 |
桌面文具 |
00 |
把 |
3 |
None |
12 |
13 |
pdno_0013 |
剪刀 |
文件管理用品 |
00 |
个 |
8 |
None |
13 |
14 |
pdno_0014 |
档案盒 |
文件管理用品 |
00 |
个 |
10 |
None |
14 |
15 |
pdno_0015 |
电脑 |
办公集写 |
00 |
个 |
2000 |
None |
pandas 数据集结构
- Series
- DataFrame
- 从DataFrame中查询出Series
Series 序列/一维/字典
给定values列表创建Series,默认 index 是range序列
s1 = pd.Series([1,'a',5.2,7])
s1 # 类似字典
0 1
1 a
2 5.2
3 7
dtype: object
# 索引列表 dict.keys()
s1.index
RangeIndex(start=0, stop=4, step=1)
# 值列表 dict.values()
s1.values
array([1, 'a', 5.2, 7], dtype=object)
给定 values列表和index列表创建Series
### 给定 key 和 vlu
s21 = pd.Series(range(5), index=['a','b','c','d','e'])
s22 = pd.Series([x - 2 for x in range(5, 14, 2)], index=['a','b','c','d','e'])
s23 = pd.Series([1, 'a', 5.2, 7, 0.14], ['a','b','c','d','e'])
print(s21)
print(s22)
print(s23)
a 0
b 1
c 2
d 3
e 4
dtype: int64
a 3
b 5
c 7
d 9
e 11
dtype: int64
a 1
b a
c 5.2
d 7
e 0.14
dtype: object
使用字典创建 Series
sdata={
'Ohio':35000,
'Texas':72000,
'Oregon':16000,
'Utah':5000
}
s3=pd.Series(sdata)
s3
Ohio 35000
Texas 72000
Oregon 16000
Utah 5000
dtype: int64
根据索引查询数据
print(s3['Ohio'], '\n')
# 给定指定索引列表来索引
print(s3[['Ohio', 'Texas']], '\n') # 只要不是一个都仍是个Series
# 切片索引
print(s3['Ohio':'Utah'])
35000
Ohio 35000
Texas 72000
dtype: int64
Ohio 35000
Texas 72000
Oregon 16000
Utah 5000
dtype: int64
DataFrame 表格/二维/数据表
2. DataFrame
DataFrame是一个表格型的数据结构
- 每列可以是不同的值类型(数值、字符串、布尔值等)
- 既有行索引index,也有列索引columns
- 可以被看做由Series组成的字典
创建dataframe最常用的方法,见02节读取纯文本文件、excel、mysql数据库
根据嵌套的字典创建DataFrame 类似与golang 的 map[string][]interface{}
data={
'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
'year':[2000,2001,2002,2001,2002],
'pop':[1.5,1.7,3.6,2.4,2.9]
}
df3 = pd.DataFrame(data)
df3
|
state |
year |
pop |
0 |
Ohio |
2000 |
1.5 |
1 |
Ohio |
2001 |
1.7 |
2 |
Ohio |
2002 |
3.6 |
3 |
Nevada |
2001 |
2.4 |
4 |
Nevada |
2002 |
2.9 |
# 列名列表
df3.columns
Index(['state', 'year', 'pop'], dtype='object')
# 索引列表
df3.index
RangeIndex(start=0, stop=5, step=1)
# 形状/维度
df3.shape
(5, 3)
# 每一列的数据类型
df3.dtypes
state object
year int64
pop float64
dtype: object
# 值
df3.values
array([['Ohio', 2000, 1.5],
['Ohio', 2001, 1.7],
['Ohio', 2002, 3.6],
['Nevada', 2001, 2.4],
['Nevada', 2002, 2.9]], dtype=object)
从DataFrame中查询出Series
- 如果只查询一行、一列,返回的是pd.Series
- 如果查询多行、多列,返回的是pd.DataFrame
# 索引一列 返回一个Series
df3['year']
0 2000
1 2001
2 2002
3 2001
4 2002
Name: year, dtype: int64
# 索引多列 返回一个DataFrame
df3[['year', 'pop']]
|
year |
pop |
0 |
2000 |
1.5 |
1 |
2001 |
1.7 |
2 |
2002 |
3.6 |
3 |
2001 |
2.4 |
4 |
2002 |
2.9 |
# 查询一列 返回Series
df3.loc[1]
state Ohio
year 2001
pop 1.7
Name: 1, dtype: object
# 查询指定多列 返回DataFrame
df3.loc[[1:3]]
# 查询范围多列 返回DataFrame
df3.loc[[1, 3]]
|
state |
year |
pop |
1 |
Ohio |
2001 |
1.7 |
3 |
Nevada |
2001 |
2.4 |
pandas 数据查询
Pandas查询数据的几种方法
- df.loc方法,根据行、列的标签值查询
- df.iloc方法,根据行、列的数字位置查询
- df.where方法
- df.query方法
.loc既能查询,又能覆盖写入,强烈推荐!
Pandas使用df.loc查询数据的方法
- 使用单个label值查询数据
- 使用值列表批量查询
- 使用数值区间进行范围查询
- 使用条件表达式查询
- 调用函数查询
注意
- 以上查询方法,既适用于行,也适用于列
- 注意观察降维dataFrame>Series>值
0、读取数据
数据为北京2018年全年天气预报
该数据的爬虫教程参见我的Python爬虫系列视频课程
dff = pd.read_csv('./datas/beijing_tianqi/beijing_tianqi_2018.csv')
dff.head()
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
0 |
2018-01-01 |
3℃ |
-6℃ |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
1 |
2018-01-02 |
2℃ |
-5℃ |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
2 |
2018-01-03 |
2℃ |
-5℃ |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
3 |
2018-01-04 |
0℃ |
-8℃ |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
4 |
2018-01-05 |
3℃ |
-6℃ |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
# 设定指定列为列【日期】,方便按日期筛选
dff.set_index('ymd', inplace=True)
# 按字符串处理
dff.head()
|
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
ymd |
|
|
|
|
|
|
|
|
2018-01-01 |
3℃ |
-6℃ |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
2018-01-02 |
2℃ |
-5℃ |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
2018-01-03 |
2℃ |
-5℃ |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
2018-01-04 |
0℃ |
-8℃ |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
2018-01-05 |
3℃ |
-6℃ |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
# 替换掉温度的后缀℃
dff.loc[:, "bWendu"] = dff["bWendu"].str.replace("℃", "").astype('int32')
dff.loc[:, "yWendu"] = dff["yWendu"].str.replace("℃", "").astype('int32')
# 再查看,温度列已经转换成了防便计算的数据类型
dff.head()
bWendu int32
yWendu int32
tianqi object
fengxiang object
fengli object
aqi int64
aqiInfo object
aqiLevel int64
dtype: object
dff.head()
|
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
ymd |
|
|
|
|
|
|
|
|
2018-01-01 |
3 |
-6 |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
2018-01-02 |
2 |
-5 |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
2018-01-03 |
2 |
-5 |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
2018-01-04 |
0 |
-8 |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
2018-01-05 |
3 |
-6 |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
1、使用单个label值查询数据
行或者列,都可以只传入单个值,实现精确匹配
# 查询指定行的指定列 得到单个数据
dff.loc['2018-01-03', 'bWendu']
2
# 查询指定行的部分列 得到一个Series
dff.loc['2018-01-03', ['bWendu', 'yWendu']]
bWendu 2
yWendu -5
Name: 2018-01-03, dtype: object
2、使用值列表批量查询
# 查询部分指定行的指定列 得到Series
df.loc[['2018-01-03','2018-01-04','2018-01-05'], 'bWendu']
bWendu 2
yWendu -5
Name: 2018-01-03, dtype: object
# 查询区块 得到一个DataFrame
dff.loc[['2018-01-03','2018-01-04','2018-01-05'], ['bWendu', 'yWendu']]
|
bWendu |
yWendu |
ymd |
|
|
2018-01-03 |
2 |
-5 |
2018-01-04 |
0 |
-8 |
2018-01-05 |
3 |
-6 |
3、使用数值区间进行范围查询
注意:区间既包含开始,也包含结束
# 查询行区间的指定列 得到Series
dff.loc['2018-01-03':'2018-01-05', 'bWendu']
ymd
2018-01-03 2
2018-01-04 0
2018-01-05 3
Name: bWendu, dtype: int32
# 查寻指定行的列区间 得到Series
dff.loc['2018-01-03', 'bWendu':'fengxiang']
bWendu 2
yWendu -5
tianqi 多云
fengxiang 北风
Name: 2018-01-03, dtype: object
# 行和列都按区间查询 得到DaTaFrame
dff.loc['2018-01-03':'2018-01-05', 'bWendu':'fengxiang']
|
bWendu |
yWendu |
tianqi |
fengxiang |
ymd |
|
|
|
|
2018-01-03 |
2 |
-5 |
多云 |
北风 |
2018-01-04 |
0 |
-8 |
阴 |
东北风 |
2018-01-05 |
3 |
-6 |
多云~晴 |
西北风 |
4、使用条件表达式查询
bool列表的长度得等于行数或者列数
# 观察一下boolean条件 返回布尔对应关系表
bool_map = (dff["yWendu"]<-10)
bool_map.head() # 【单一条件查询,最低温度低于-10度的列表】
ymd
2018-01-01 False
2018-01-02 False
2018-01-03 False
2018-01-04 False
2018-01-05 False
Name: yWendu, dtype: bool
# 根据布尔关系对应表 查询10°C一下的天
dff.loc[bool_map, :]
|
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
ymd |
|
|
|
|
|
|
|
|
2018-01-23 |
-4 |
-12 |
晴 |
西北风 |
3-4级 |
31 |
优 |
1 |
2018-01-24 |
-4 |
-11 |
晴 |
西南风 |
1-2级 |
34 |
优 |
1 |
2018-01-25 |
-3 |
-11 |
多云 |
东北风 |
1-2级 |
27 |
优 |
1 |
2018-12-26 |
-2 |
-11 |
晴~多云 |
东北风 |
2级 |
26 |
优 |
1 |
2018-12-27 |
-5 |
-12 |
多云~晴 |
西北风 |
3级 |
48 |
优 |
1 |
2018-12-28 |
-3 |
-11 |
晴 |
西北风 |
3级 |
40 |
优 |
1 |
2018-12-29 |
-3 |
-12 |
晴 |
西北风 |
2级 |
29 |
优 |
1 |
2018-12-30 |
-2 |
-11 |
晴~多云 |
东北风 |
1级 |
31 |
优 |
1 |
# 观察一下boolean条件 返回布尔对应关系表 【多个布尔对应关系表结合成目标布尔关系对应表】
# 【查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据】
bool_map1 = (dff["bWendu"]<=30) & (dff["yWendu"]>=15) & (dff["tianqi"]=='晴') & (dff["aqiLevel"]==1)
bool_map1.head()
ymd
2018-01-01 False
2018-01-02 False
2018-01-03 False
2018-01-04 False
2018-01-05 False
dtype: bool
# 根据布尔关系对应表 查询10°C一下的天查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据
dff.loc[bool_map1, :] # 看起来只有两天
|
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
ymd |
|
|
|
|
|
|
|
|
2018-08-24 |
30 |
20 |
晴 |
北风 |
1-2级 |
40 |
优 |
1 |
2018-09-07 |
27 |
16 |
晴 |
西北风 |
3-4级 |
22 |
优 |
1 |
5、调用函数查询
# 直接写lambda表达式
dff.loc[lambda dff : (dff["bWendu"]<=30) & (dff["yWendu"]>=15), :]
# 编写自己的函数,查询9月份,空气质量好的数据
def query_my_data(dff):
return dff.index.str.startswith("2018-09") & df["aqiLevel"]==1
dff.loc[query_my_data, :]
pandas 新增数据列
- 直接赋值
- df.apply
- df.assign
- 按条件选择分组分别赋值
0、读取csv数据
dfm = pd.read_csv('./datas/beijing_tianqi/beijing_tianqi_2018.csv')
dfm.head()
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
0 |
2018-01-01 |
3℃ |
-6℃ |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
1 |
2018-01-02 |
2℃ |
-5℃ |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
2 |
2018-01-03 |
2℃ |
-5℃ |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
3 |
2018-01-04 |
0℃ |
-8℃ |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
4 |
2018-01-05 |
3℃ |
-6℃ |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
1、直接赋值的方法
清理温度列变成数字类型
# 替换掉温度的后缀℃
dfm.loc[:, "bWendu"] = dfm["bWendu"].str.replace("℃", "").astype('int32')
dfm.loc[:, "yWendu"] = dfm["yWendu"].str.replace("℃", "").astype('int32')
dfm.head()
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
0 |
2018-01-01 |
3 |
-6 |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
1 |
2018-01-02 |
2 |
-5 |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
2 |
2018-01-03 |
2 |
-5 |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
3 |
2018-01-04 |
0 |
-8 |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
4 |
2018-01-05 |
3 |
-6 |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
dfm.loc[:, 'wencha'] = dfm['bWendu'] - dfm['yWendu']
dfm.head()
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
wencha |
0 |
2018-01-01 |
3 |
-6 |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
9 |
1 |
2018-01-02 |
2 |
-5 |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
7 |
2 |
2018-01-03 |
2 |
-5 |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
7 |
3 |
2018-01-04 |
0 |
-8 |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
8 |
4 |
2018-01-05 |
3 |
-6 |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
9 |
2、df.apply 方法
def get_wendu_type(x):
if x["bWendu"] > 33:
return '高温'
if x["yWendu"] < -10:
return '低温'
return '常温'
# 注意需要设置axis==1,这是series的index是columns
dfm.loc[:, "wendu_type"] = dfm.apply(get_wendu_type, axis=1) # 传入函数引用,会自动使用函数
# 统计温度类型
dfm["wendu_type"].value_counts()
常温 328
高温 29
低温 8
Name: wendu_type, dtype: int64
3、df.assign 方法
# 可以同时添加多个新的列
dfm = dfm.assign( # assign 方法不会修改 dfm 而是会返回一个新的 DataFrame 对象
f_yWendu = lambda x : x["yWendu"] * 9 / 5 + 32,
# 摄氏度转华氏度
f_bWendu = lambda x : x["bWendu"] * 9 / 5 + 32
)
dfm.head(5)
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
wencha |
wendu_type |
f_yWendu |
f_bWendu |
0 |
2018-01-01 |
3 |
-6 |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
9 |
常温 |
21.2 |
37.4 |
1 |
2018-01-02 |
2 |
-5 |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
7 |
常温 |
23.0 |
35.6 |
2 |
2018-01-03 |
2 |
-5 |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
7 |
常温 |
23.0 |
35.6 |
3 |
2018-01-04 |
0 |
-8 |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
8 |
常温 |
17.6 |
32.0 |
4 |
2018-01-05 |
3 |
-6 |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
9 |
常温 |
21.2 |
37.4 |
4、按条件选择分组分别赋值
按条件先选择数据,然后对这部分数据赋值新列
实例:高低温差大于10度,则认为温差大
# 先创建空列(这是第一种创建新列的方法)
dfm['wencha_type'] = '' # 广播的方式,指定所有行的指定列的值都是给定的那个值
# 必须先覆盖全,然后进行分组分配值,不然会造成该列的有的位置缺失值
dfm.loc[dfm['bWendu']-dfm['yWendu'] > 10, 'wencha_type'] = '温差大'
dfm.loc[dfm['bWendu']-dfm['yWendu'] <= 10, 'wencha_type'] = '温差正常'
# 统计温差类型列每种类型数量
dfm['wencha_type'].value_counts()
温差正常 187
温差大 178
Name: wencha_type, dtype: int64
pandas 的数据统计方法
- 汇总类统计
- 唯一去重和按值计数
- 相关系数和协方差
# 先看一下前4行
dfm.head(4)
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
wencha |
wendu_type |
f_yWendu |
f_bWendu |
wencha_type |
0 |
2018-01-01 |
3 |
-6 |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
9 |
常温 |
21.2 |
37.4 |
温差正常 |
1 |
2018-01-02 |
2 |
-5 |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
7 |
常温 |
23.0 |
35.6 |
温差正常 |
2 |
2018-01-03 |
2 |
-5 |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
7 |
常温 |
23.0 |
35.6 |
温差正常 |
3 |
2018-01-04 |
0 |
-8 |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
8 |
常温 |
17.6 |
32.0 |
温差正常 |
1、汇总类统计
# 一下子提取所有数字列的各种数字特征的统计结果,更只管把控全局
dfm.describe()
|
bWendu |
yWendu |
aqi |
aqiLevel |
wencha |
f_yWendu |
f_bWendu |
count |
365.000000 |
365.000000 |
365.000000 |
365.000000 |
365.000000 |
365.000000 |
365.000000 |
mean |
18.665753 |
8.358904 |
82.183562 |
2.090411 |
10.306849 |
47.046027 |
65.598356 |
std |
11.858046 |
11.755053 |
51.936159 |
1.029798 |
2.781233 |
21.159096 |
21.344482 |
min |
-5.000000 |
-12.000000 |
21.000000 |
1.000000 |
2.000000 |
10.400000 |
23.000000 |
25% |
8.000000 |
-3.000000 |
46.000000 |
1.000000 |
8.000000 |
26.600000 |
46.400000 |
50% |
21.000000 |
8.000000 |
69.000000 |
2.000000 |
10.000000 |
46.400000 |
69.800000 |
75% |
29.000000 |
19.000000 |
104.000000 |
3.000000 |
12.000000 |
66.200000 |
84.200000 |
max |
38.000000 |
27.000000 |
387.000000 |
6.000000 |
18.000000 |
80.600000 |
100.400000 |
# 查看单个数字特征-均值
dfm['bWendu'].mean()
18.665753424657535
# 查看单个数字特征-最大值
dfm[['bWendu', 'yWendu']].max()
bWendu 38
yWendu 27
dtype: int32
# 查看单个数字特征-最小值
dfm['wencha'].min()
2
2、唯一去重和按值计数
唯一去重,适合列出有哪些,不多的枚举
dfm["fengxiang"].unique()
array(['东北风', '北风', '西北风', '西南风', '南风', '东南风', '东风', '西风'], dtype=object)
dfm["tianqi"].unique()
array(['晴~多云', '阴~多云', '多云', '阴', '多云~晴', '多云~阴', '晴', '阴~小雪', '小雪~多云',
'小雨~阴', '小雨~雨夹雪', '多云~小雨', '小雨~多云', '大雨~小雨', '小雨', '阴~小雨',
'多云~雷阵雨', '雷阵雨~多云', '阴~雷阵雨', '雷阵雨', '雷阵雨~大雨', '中雨~雷阵雨', '小雨~大雨',
'暴雨~雷阵雨', '雷阵雨~中雨', '小雨~雷阵雨', '雷阵雨~阴', '中雨~小雨', '小雨~中雨', '雾~多云',
'霾'], dtype=object)
dfm["fengli"].unique()
array(['1-2级', '4-5级', '3-4级', '2级', '1级', '3级'], dtype=object)
按值计数
dfm["fengxiang"].value_counts()
南风 92
西南风 64
北风 54
西北风 51
东南风 46
东北风 38
东风 14
西风 6
Name: fengxiang, dtype: int64
dfm["tianqi"].value_counts()
晴 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
dfm["fengli"].value_counts()
1-2级 236
3-4级 68
1级 21
4-5级 20
2级 13
3级 7
Name: fengli, dtype: int64
3、相关系数和协方差
用途(超级厉害):
- 两只股票,是不是同涨同跌?程度多大?正相关还是负相关?
- 产品销量的波动,跟哪些因素正相关、负相关,程度有多大?
来自知乎,对于两个变量X、Y:
- 协方差:衡量同向反向程度,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高。
- 相关系数:衡量相似度程度,当他们的相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为-1时,说明两个变量变化的反向相似度最大
# 协方差矩阵:
dfm.cov()
|
bWendu |
yWendu |
aqi |
aqiLevel |
wencha |
f_yWendu |
f_bWendu |
bWendu |
140.613247 |
135.529633 |
47.462622 |
0.879204 |
5.083614 |
243.953339 |
253.103845 |
yWendu |
135.529633 |
138.181274 |
16.186685 |
0.264165 |
-2.651641 |
248.726292 |
243.953339 |
aqi |
47.462622 |
16.186685 |
2697.364564 |
50.749842 |
31.275937 |
29.136033 |
85.432720 |
aqiLevel |
0.879204 |
0.264165 |
50.749842 |
1.060485 |
0.615038 |
0.475498 |
1.582567 |
wencha |
5.083614 |
-2.651641 |
31.275937 |
0.615038 |
7.735255 |
-4.772953 |
9.150506 |
f_yWendu |
243.953339 |
248.726292 |
29.136033 |
0.475498 |
-4.772953 |
447.707326 |
439.116010 |
f_bWendu |
253.103845 |
243.953339 |
85.432720 |
1.582567 |
9.150506 |
439.116010 |
455.586920 |
# 单独查看空气质量和最高温度的相关系数
dfm["aqi"].corr(dfm["bWendu"])
0.07706705916811067
dfm["aqi"].corr(dfm["yWendu"])
0.026513282672968895
# 空气质量和温差的相关系数-看到了明显提升的相关系数-数据挖掘出了信息-空气质量和温差有关系
dfm["aqi"].corr(dfm["bWendu"] - dfm["yWendu"])
0.2165225757638205
# !! 这就是特征工程对于机器学习重要性的一个例子
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 : 按行还是列填充,
- inplace : 如果为True则修改当前df,否则返回新的df
读取excel的时候,忽略前几个空行 skiprows 参数控制
studf = pd.read_excel('./datas/student_excel/student_excel.xlsx', skiprows=2)
studf.head(10)
|
Unnamed: 0 |
姓名 |
科目 |
分数 |
0 |
NaN |
小明 |
语文 |
85.0 |
1 |
NaN |
NaN |
数学 |
80.0 |
2 |
NaN |
NaN |
英语 |
90.0 |
3 |
NaN |
NaN |
NaN |
NaN |
4 |
NaN |
小王 |
语文 |
85.0 |
5 |
NaN |
NaN |
数学 |
NaN |
6 |
NaN |
NaN |
英语 |
90.0 |
7 |
NaN |
NaN |
NaN |
NaN |
8 |
NaN |
小刚 |
语文 |
85.0 |
9 |
NaN |
NaN |
数学 |
80.0 |
检测空值
studf.isnull().head()
|
Unnamed: 0 |
姓名 |
科目 |
分数 |
0 |
True |
False |
False |
False |
1 |
True |
True |
False |
False |
2 |
True |
True |
False |
False |
3 |
True |
True |
True |
True |
4 |
True |
False |
False |
False |
# 查看单列的空缺情况
studf['分数'].isnull().head()
0 False
1 False
2 False
3 True
4 False
Name: 分数, dtype: bool
# 使用notnull查看非空的
studf['分数'].notnull().head()
0 True
1 True
2 True
3 False
4 True
Name: 分数, dtype: bool
# 筛选没有空分的行-这一步的目的是大致观察清晰的数据
studf.loc[studf['分数'].notnull(), :].head(10)
|
Unnamed: 0 |
姓名 |
科目 |
分数 |
0 |
NaN |
小明 |
语文 |
85.000000 |
1 |
NaN |
NaN |
数学 |
80.000000 |
2 |
NaN |
NaN |
英语 |
90.000000 |
4 |
NaN |
小王 |
语文 |
85.000000 |
6 |
NaN |
NaN |
英语 |
90.000000 |
8 |
NaN |
小刚 |
语文 |
85.000000 |
9 |
NaN |
NaN |
数学 |
80.000000 |
10 |
NaN |
NaN |
英语 |
90.000000 |
11 |
NaN |
小啊 |
语文 |
86.507353 |
12 |
NaN |
NaN |
数学 |
86.654412 |
删除全是空值的列
studf.dropna(axis=1,how='all' ,inplace=True)
studf.head(10)
|
姓名 |
科目 |
分数 |
0 |
小明 |
语文 |
85.0 |
1 |
NaN |
数学 |
80.0 |
2 |
NaN |
英语 |
90.0 |
3 |
NaN |
NaN |
NaN |
4 |
小王 |
语文 |
85.0 |
5 |
NaN |
数学 |
NaN |
6 |
NaN |
英语 |
90.0 |
7 |
NaN |
NaN |
NaN |
8 |
小刚 |
语文 |
85.0 |
9 |
NaN |
数学 |
80.0 |
删除全是空值的行
studf.dropna(axis=0, how='all', inplace=True)
studf.head(10)
|
姓名 |
科目 |
分数 |
0 |
小明 |
语文 |
85.000000 |
1 |
NaN |
数学 |
80.000000 |
2 |
NaN |
英语 |
90.000000 |
4 |
小王 |
语文 |
85.000000 |
5 |
NaN |
数学 |
NaN |
6 |
NaN |
英语 |
90.000000 |
8 |
小刚 |
语文 |
85.000000 |
9 |
NaN |
数学 |
80.000000 |
10 |
NaN |
英语 |
90.000000 |
11 |
小啊 |
语文 |
86.507353 |
把分数为空的填充为0
studf['分数'].fillna(0, inplace=True) # 无返回df,直接操作源内村
# studf.fillna({'分数': 0}, inplace=True) # 无返回df,直接操作原内存
# studf.loc[:, '分数'] = studf.fillna({'分数': 0}) # 有返回df
# studf.loc[:, '分数'] = studf['分数'].fillna(0) # 有返回df
# 以上为等效的方法
studf.head(10)
|
姓名 |
科目 |
分数 |
0 |
小明 |
语文 |
85.000000 |
1 |
NaN |
数学 |
80.000000 |
2 |
NaN |
英语 |
90.000000 |
4 |
小王 |
语文 |
85.000000 |
5 |
NaN |
数学 |
0.000000 |
6 |
NaN |
英语 |
90.000000 |
8 |
小刚 |
语文 |
85.000000 |
9 |
NaN |
数学 |
80.000000 |
10 |
NaN |
英语 |
90.000000 |
11 |
小啊 |
语文 |
86.507353 |
将姓名的缺失值填充为上一个
# 参数 ffill代表用上面的值填充,dfill代表用下面的值填充
studf.loc[:, '姓名'] = studf['姓名'].fillna(method="ffill") # 返回填充后的列,赋值给原来的列
# studf['姓名'] = studf['姓名'].fillna(method='ffill')
# studf['姓名'].fillna(method='ffill', inplace=True)
# 以上三种形式等效
studf.head(10)
|
姓名 |
科目 |
分数 |
0 |
小明 |
语文 |
85.000000 |
1 |
小明 |
数学 |
80.000000 |
2 |
小明 |
英语 |
90.000000 |
4 |
小王 |
语文 |
85.000000 |
5 |
小王 |
数学 |
0.000000 |
6 |
小王 |
英语 |
90.000000 |
8 |
小刚 |
语文 |
85.000000 |
9 |
小刚 |
数学 |
80.000000 |
10 |
小刚 |
英语 |
90.000000 |
11 |
小啊 |
语文 |
86.507353 |
将清洗好的数据写入excel文件
studf.to_excel('./datas/student_excel/student_excel_clean.xlsx', index=False) # 舍弃索引列
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
df4 = pd.read_csv('./datas/beijing_tianqi/beijing_tianqi_2018.csv')
# 替换掉温度的后缀℃
df4.loc[:, 'bWendu'] = df4['bWendu'].str.replace('℃', '').astype('int32')
df4.loc[:, 'yWendu'] = df4['yWendu'].str.replace('℃', '').astype('int32')
df4.head()
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
0 |
2018-01-01 |
3 |
-6 |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
1 |
2018-01-02 |
2 |
-5 |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
2 |
2018-01-03 |
2 |
-5 |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
3 |
2018-01-04 |
0 |
-8 |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
4 |
2018-01-05 |
3 |
-6 |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
Series 的排序
按照空气质量排序
# 默认ascending为True代表升序
df4['aqi'].sort_values().head(10) # 也可以指定inplace=True代表在源内存上改
271 21
281 21
249 22
272 22
301 22
246 24
35 24
33 24
10 24
273 25
Name: aqi, dtype: int64
# 下面我们按照降序排序
df4['aqi'].sort_values(ascending=False).head(10) # sort_values 返回结果副本,也可指定inplace
86 387
72 293
91 287
71 287
317 266
329 245
85 243
335 234
57 220
316 219
Name: aqi, dtype: int64
# 按照内部机制排序
df4['tianqi'].sort_values().head(10)
225 中雨~小雨
230 中雨~小雨
197 中雨~雷阵雨
196 中雨~雷阵雨
112 多云
108 多云
232 多云
234 多云
241 多云
94 多云
Name: tianqi, dtype: object
DataFrame 的排序
单列排序
df4.sort_values(by='aqi').head(7) # 按照空气质量升序
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
271 |
2018-09-29 |
22 |
11 |
晴 |
北风 |
3-4级 |
21 |
优 |
1 |
281 |
2018-10-09 |
15 |
4 |
多云~晴 |
西北风 |
4-5级 |
21 |
优 |
1 |
249 |
2018-09-07 |
27 |
16 |
晴 |
西北风 |
3-4级 |
22 |
优 |
1 |
272 |
2018-09-30 |
19 |
13 |
多云 |
西北风 |
4-5级 |
22 |
优 |
1 |
301 |
2018-10-29 |
15 |
3 |
晴 |
北风 |
3-4级 |
22 |
优 |
1 |
246 |
2018-09-04 |
31 |
18 |
晴 |
西南风 |
3-4级 |
24 |
优 |
1 |
35 |
2018-02-05 |
0 |
-10 |
晴 |
北风 |
3-4级 |
24 |
优 |
1 |
df4.sort_values(by='aqi', ascending=False).head(7) # 按照空气质量降序
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
86 |
2018-03-28 |
25 |
9 |
多云~晴 |
东风 |
1-2级 |
387 |
严重污染 |
6 |
72 |
2018-03-14 |
15 |
6 |
多云~阴 |
东北风 |
1-2级 |
293 |
重度污染 |
5 |
71 |
2018-03-13 |
17 |
5 |
晴~多云 |
南风 |
1-2级 |
287 |
重度污染 |
5 |
91 |
2018-04-02 |
26 |
11 |
多云 |
北风 |
1-2级 |
287 |
重度污染 |
5 |
317 |
2018-11-14 |
13 |
5 |
多云 |
南风 |
1-2级 |
266 |
重度污染 |
5 |
329 |
2018-11-26 |
10 |
0 |
多云 |
东南风 |
1级 |
245 |
重度污染 |
5 |
85 |
2018-03-27 |
27 |
11 |
晴 |
南风 |
1-2级 |
243 |
重度污染 |
5 |
多列排序------显然返回的是df
# 优先按照空气质量等级,次按照最高温排序,默认ascending=True 即[两列都是升序]
df4.sort_values(by=['aqiLevel', 'bWendu']).head(7)
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
360 |
2018-12-27 |
-5 |
-12 |
多云~晴 |
西北风 |
3级 |
48 |
优 |
1 |
22 |
2018-01-23 |
-4 |
-12 |
晴 |
西北风 |
3-4级 |
31 |
优 |
1 |
23 |
2018-01-24 |
-4 |
-11 |
晴 |
西南风 |
1-2级 |
34 |
优 |
1 |
340 |
2018-12-07 |
-4 |
-10 |
晴 |
西北风 |
3级 |
33 |
优 |
1 |
21 |
2018-01-22 |
-3 |
-10 |
小雪~多云 |
东风 |
1-2级 |
47 |
优 |
1 |
24 |
2018-01-25 |
-3 |
-11 |
多云 |
东北风 |
1-2级 |
27 |
优 |
1 |
25 |
2018-01-26 |
-3 |
-10 |
晴~多云 |
南风 |
1-2级 |
39 |
优 |
1 |
# [两列都是降序]
df4.sort_values(by=['aqiLevel', 'bWendu']).head(7)
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
360 |
2018-12-27 |
-5 |
-12 |
多云~晴 |
西北风 |
3级 |
48 |
优 |
1 |
22 |
2018-01-23 |
-4 |
-12 |
晴 |
西北风 |
3-4级 |
31 |
优 |
1 |
23 |
2018-01-24 |
-4 |
-11 |
晴 |
西南风 |
1-2级 |
34 |
优 |
1 |
340 |
2018-12-07 |
-4 |
-10 |
晴 |
西北风 |
3级 |
33 |
优 |
1 |
21 |
2018-01-22 |
-3 |
-10 |
小雪~多云 |
东风 |
1-2级 |
47 |
优 |
1 |
24 |
2018-01-25 |
-3 |
-11 |
多云 |
东北风 |
1-2级 |
27 |
优 |
1 |
25 |
2018-01-26 |
-3 |
-10 |
晴~多云 |
南风 |
1-2级 |
39 |
优 |
1 |
# [分别指定升序和降序] ascending传入列表[True, None] None等效False
df4.sort_values(by=['aqiLevel', 'bWendu'], ascending=[True, False]).head(7)
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
178 |
2018-06-28 |
35 |
24 |
多云~晴 |
北风 |
1-2级 |
33 |
优 |
1 |
149 |
2018-05-30 |
33 |
18 |
晴 |
西风 |
1-2级 |
46 |
优 |
1 |
206 |
2018-07-26 |
33 |
25 |
多云~雷阵雨 |
东北风 |
1-2级 |
40 |
优 |
1 |
158 |
2018-06-08 |
32 |
19 |
多云~雷阵雨 |
西南风 |
1-2级 |
43 |
优 |
1 |
205 |
2018-07-25 |
32 |
25 |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
226 |
2018-08-15 |
32 |
24 |
多云 |
东北风 |
3-4级 |
33 |
优 |
1 |
231 |
2018-08-20 |
32 |
23 |
多云~晴 |
北风 |
1-2级 |
41 |
优 |
1 |
Pandas字符串处理
使用.str
转换之后就可以使用python内置的各种字符串处理方法,当然这是pandas封装的,甚至还比标准库多
前面我们已经使用了字符串的处理函数:
df["bWendu"].str.replace("℃", "").astype('int32')
Pandas的字符串处理:
- 使用方法:先获取Series的str属性,然后在属性上调用函数;
- 只能在字符串列上使用,不能数字列上使用;
- Dataframe上没有str属性和处理方法
- Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似;
Series.str字符串方法列表参考文档:
https://pandas.pydata.org/pandas-docs/stable/reference/series.html#string-handling
本节演示内容:
- 获取Series的str属性,然后使用各种字符串处理函数
- 使用str的startswith、contains等bool类Series可以做条件查询
- 需要多次str处理的链式操作
- 使用正则表达式的处理
df5 = pd.read_csv("./datas/beijing_tianqi/beijing_tianqi_2018.csv")
df5.head(7)
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
0 |
2018-01-01 |
3℃ |
-6℃ |
晴~多云 |
东北风 |
1-2级 |
59 |
良 |
2 |
1 |
2018-01-02 |
2℃ |
-5℃ |
阴~多云 |
东北风 |
1-2级 |
49 |
优 |
1 |
2 |
2018-01-03 |
2℃ |
-5℃ |
多云 |
北风 |
1-2级 |
28 |
优 |
1 |
3 |
2018-01-04 |
0℃ |
-8℃ |
阴 |
东北风 |
1-2级 |
28 |
优 |
1 |
4 |
2018-01-05 |
3℃ |
-6℃ |
多云~晴 |
西北风 |
1-2级 |
50 |
优 |
1 |
5 |
2018-01-06 |
2℃ |
-5℃ |
多云~阴 |
西南风 |
1-2级 |
32 |
优 |
1 |
6 |
2018-01-07 |
2℃ |
-4℃ |
阴~多云 |
西南风 |
1-2级 |
59 |
良 |
2 |
df5.dtypes
ymd object
bWendu object
yWendu object
tianqi object
fengxiang object
fengli object
aqi int64
aqiInfo object
aqiLevel int64
dtype: object
1、获取Series的str属性,使用各种字符串处理函数
# 判断是不是数字的
df5['bWendu'].str.isnumeric().value_counts()
False 365
Name: bWendu, dtype: int64
df5['bWendu'].str.isnumeric().head()
0 False
1 False
2 False
3 False
4 False
Name: bWendu, dtype: bool
# 不可以使用这样的 df5['aqi'].str.len()
2、使用str的startswith、contains等得到bool的Series可以做条件查询
# 条件是以'2018-03'开头 也就是查询了2018年3月的
condition = df5["ymd"].str.startswith("2018-03")
condition.head() # 前面都是False 到了2018-03就是True了 bool对应关系图
0 False
1 False
2 False
3 False
4 False
Name: ymd, dtype: bool
df5.loc[condition, :].head(7) # 查询三月的
# df5.loc[condition].head(7) # 等效方法
# df5[condition].head(7) # 等效方法
|
ymd |
bWendu |
yWendu |
tianqi |
fengxiang |
fengli |
aqi |
aqiInfo |
aqiLevel |
59 |
2018-03-01 |
8℃ |
-3℃ |
多云 |
西南风 |
1-2级 |
46 |
优 |
1 |
60 |
2018-03-02 |
9℃ |
-1℃ |
晴~多云 |
北风 |
1-2级 |
95 |
良 |
2 |
61 |
2018-03-03 |
13℃ |
3℃ |
多云~阴 |
北风 |
1-2级 |
214 |
重度污染 |
5 |
62 |
2018-03-04 |
7℃ |
-2℃ |
阴~多云 |
东南风 |
1-2级 |
144 |
轻度污染 |
3 |
63 |
2018-03-05 |
8℃ |
-3℃ |
晴 |
南风 |
1-2级 |
94 |
良 |
2 |
64 |
2018-03-06 |
6℃ |
-3℃ |
多云~阴 |
东南风 |
3-4级 |
67 |
良 |
2 |
65 |
2018-03-07 |
6℃ |
-2℃ |
阴~多云 |
北风 |
1-2级 |
65 |
良 |
2 |
3、需要多次str处理的链式操作
怎样提取201803这样的数字月份?
1、replace 先将日期2018-03-31替换成20180331的形式
2、提取月份字符串201803
df5['ymd'].str.replace('-', '').head(7)
0 20180101
1 20180102
2 20180103
3 20180104
4 20180105
5 20180106
6 20180107
Name: ymd, dtype: object
# 每次调用函数,都返回一个新Series,需要再次用 `.str`操作才能继续使用字符串操作方法
# df5["ymd"].str.replace("-", "").slice(0, 6) # 将会报错
df5['ymd'].str.replace('-', '').str.slice(0, 6).head()
# slice方法其实就是切片语法,直接[::]就可
# df5['ymd'].str.replace('-', '').str[0:6]
0 201801
1 201801
2 201801
3 201801
4 201801
Name: ymd, dtype: object
4、使用正则表达式的处理
首先不使用的情况是这样的
# 添加新列-如 2018年03月14日
def get_nianyueri(x):
year, month, day = x["ymd"].split("-")
return f"{year}年{month}月{day}日"
df5["中文日期"] = df5.apply(get_nianyueri, axis=1)
df5["中文日期"].head()
0 2018年01月01日
1 2018年01月02日
2 2018年01月03日
3 2018年01月04日
4 2018年01月05日
Name: 中文日期, dtype: object
# 链式操作,每次调用字符串处理方法都要先 `.str`
df5['中文日期'].str.replace('年', '').str.replace('月', '').str.replace('日', '').head()
0 20180101
1 20180102
2 20180103
3 20180104
4 20180105
Name: 中文日期, dtype: object
然后是Series.str默认就开启了正则表达式模式的情况是这样的
# 正则表达式匹配替换-'[年月日]'中括号内每一个字符都匹配
df5['中文日期'].str.replace('[年月日]', '').head()
0 20180101
1 20180102
2 20180103
3 20180104
4 20180105
Name: 中文日期, dtype: object
理解axis参数
axis=0或'index' 跨行梳出
axis=1或'columns' 跨列梳出
后续篇目