python学习笔记37-pandas
内容来自https://www.runoob.com/pandas/pandas-tutorial.html
1. Series
1.1 Series特点
- 索引: 每个Series都有一个索引, 它可以是整数, 字符串, 日期等类型.
如果没有显式指定索引, Pandas会自动创建一个默认的整数索引. - 数据类型: Series可以容纳不同数据类型的元素, 包括整数, 浮点数, 字符串等.
创建方法:
pandas.Series(data, index, dtype, name, copy)
##Series
#>>> import pandas as pd
#>>> a = [1,2,3]
#>>> myvar = pd.Series(a) #通过list创建Series
#>>> print(myvar) #打印series
#0 1
#1 2
#2 3
#dtype: int64
#>>>
#>>> print(myvar[1]) #利用索引读取数据
#2
Series->指定索引值
>>> import pandas as pd
>>> a = ['Google', 'Runnob', 'Wiki',]
>>> myvar = pd.Series(a, index=['x', 'y', 'z'])
>>> print(myvar)
x Google
y Runnob
z Wiki
dtype: object
>>> print(myvar['y']) #根据索引值读取数据
Runnob
Series->通过dict创建Series
>>> sites = {1:"Google", 2:"Runoob", 3:"Wiki"}
>>> myvar = pd.Series(sites)
>>> print(myvar)
1 Google
2 Runoob
3 Wiki
dtype: object
# index指定需要的数据, 其余index的数据丢掉:
>>> myvar = pd.Series(sites, index=[1,2])
>>> print(myvar)
1 Google
2 Runoob
dtype: object
1.2 更多Series说明
1.2.1 基本操作
>>> a = ['Google', 'Runnob', 'Wiki',]
>>> b = ['x', 'y', 'z']
>>>
>>> myvar = pd.Series(a, index=b)
>>>
>>> # 在自定义索引后, 数字索引仍然有效
>>> myvar[1] # 数字索引
'Runnob'
>>> myvar['y'] # 自定义索引
'Runnob'
>>>
>>> # 获取多个值, 超出范围的索引忽略
>>> myvar[1:4]
y Runnob
z Wiki
dtype: object
>>>
>>> 遍历Series的key和value
>>> for k, v in myvar.items():
... print(f'{k} -> {v}')
...
x -> Google
y -> Runnob
z -> Wiki
>>>
1.2.2 基本运算
#算术运算
>>> myvar = pd.Series([9, 5, 8])
>>> myvar2 = myvar * 2 # 所有元素乘以2
>>> myvar # 原series不变
0 9
1 5
2 8
dtype: int64
>>> myvar2 # 返回的series为乘以2的Series.
0 18
1 10
2 16
dtype: int64
#过滤
>>> myvar3 = myvar[myvar>6] #只取大于6的元素
>>> myvar3 # 注意原本的idx会保留, 不会重新排.
0 9
2 8
dtype: int64
#数据函数
>>> import numpy as np
>>> myvar4 = np.sqrt(myvar) # 每个元素取平方根, myvar不变, 返回新series.
>>> myvar4 # 注意, 数据类型自动转换为float64
0 3.000000
1 2.236068
2 2.828427
dtype: float64
1.2.3 属性和方法
#获取索引
>>> myvar = pd.Series(['Google', 'Runnob', 'Wiki',])
>>> idx = myvar.index
>>> idx #默认索引返回的是RangeIndex
RangeIndex(start=0, stop=3, step=1)
>>>
>>> myvar = pd.Series(['Google', 'Runnob', 'Wiki',], index=['x', 'y', 'z'])
>>> idx = myvar.index
>>> idx #自定义索引返回的是Index
Index(['x', 'y', 'z'], dtype='object')
>>> myvar.values # 获取值数组
array(['Google', 'Runnob', 'Wiki'], dtype=object)
2. DataFrame
2.1 DataFrame特点
是二维表格.
构造方法:
pandas.DataFrame(data, index, columns, dtype, copy)
参数:
data: 一组数据(ndarray, series, map, list, dict等类型).
index: 索引值, 也可以称为行标签.
columns: 列标签, 默认为RangeIndex(0, 1, 2, ..., n).
dtype: 数据类型.
copy: 拷贝数据, 默认为False.
使用列表创建:
>>> import pandas as pd
>>>
>>> data = [['Google', 10], ['Runoob', 12], ['Wiki', 13]]
>>> df = pd.DataFrame(data, columns=['Site', 'Age'])
>>>
>>> print(df)
Site Age
0 Google 10
1 Runoob 12
2 Wiki 13
>>>
>>> # 设置每列的数据类型
>>> df['Site'] = df['Site'].astype(str)
>>> df['Age'] = df['Age'].astype(float)
>>> df #可以看到Age列的数据类型变了.
Site Age
0 Google 10.0
1 Runoob 12.0
2 Wiki 13.0
使用ndarrays创建:
>>> # 第一维是dict, 第二维是list.
>>> # 第一维的dict的key做列索引, RangeIndex作为行索引.
>>> data = {'Site':['Google', 'Runoob', 'Wiki'], 'Age':[10, 12, 13]}
>>> df = pd.DataFrame(data)
>>> df
Site Age
0 Google 10
1 Runoob 12
2 Wiki 13
>>>
使用dict创建:
>>> # 第一维是list, 第二维是dict.
>>> # 第二维的key做列索引,
>>> # 第二维的value, 每个dict中的值做一行数据, 如果缺少对应的key, 则value为NaN.
>>> data = [{'a': 1, 'b': 2},{'a': 5, 'b': 10, 'c': 20}]
>>> df = pd.DataFrame(data)
>>> df
a b c
0 1 2 NaN
1 5 10 20.0
>>>
使用loc函数返回指定行的数据, 注意loc后是中括号, 不是小括号.
>>> import pandas as pd
>>>
>>> data = {
... "calories": [420, 380, 390],
... "duration": [50, 40, 45],
... }
>>>
>>> df = pd.DataFrame(data)
>>>
>>> print(df.loc[0]) #第0行数据, 是Series类型
calories 420
duration 50
Name: 0, dtype: int64
>>> print(df.loc[1]) #第1行数据, 是Series类型
calories 380
duration 40
Name: 1, dtype: int64
>>>
>>> print(df.loc[[0, 1]]) # 使用[[...]] 返回多行数据, 是DataFrame类型
calories duration
0 420 50
1 380 40
>>>
指定索引值(行索引), 使用loc[行索引]获取对应行数据:
>>> import pandas as pd
>>>
>>> data = {
... "calories": [420, 380, 390],
... "duration": [50, 40, 45]
... }
>>>
>>> df = pd.DataFrame(data, index = ["day1", "day2", "day3"])
>>>
>>> print(df)
calories duration
day1 420 50
day2 380 40
day3 390 45
>>>
>>> print(df.loc["day2"])
calories 380
duration 40
Name: day2, dtype: int64
>>>
2.2 更多DataFrame说明
2.2.1 基本操作
#获取列
name_column = df['Name']
#获取行
first_row = df.loc[0]
#选择多列
subset = df[['Name', 'Age']]
#过滤行
filtered_rows = df[df['Age']>30]
2.2.2 属性和方法
>>> df
calories duration
day1 420 50
day2 380 40
day3 390 45
>>>
>>> #获取列名
>>> columns = df.columns
>>> columns
Index(['calories', 'duration'], dtype='object')
>>>
>>> #获取形状(行数和列数)
>>> shape = df.shape
>>> shape
(3, 2)
>>>
>>> #获取索引
>>> index = df.index
>>> index
Index(['day1', 'day2', 'day3'], dtype='object')
>>>
>>> #获取描述统计信息
>>> stats = df.describe()
>>> stats
calories duration
count 3.000000 3.0
mean 396.666667 45.0
std 20.816660 5.0
min 380.000000 40.0
25% 385.000000 42.5
50% 390.000000 45.0
75% 405.000000 47.5
max 420.000000 50.0
>>>
2.2.3 数据操作
>>> df
calories duration
day1 420 50
day2 380 40
day3 390 45
>>>
>>> # 添加新列
>>> df['Salary'] = [50000, 60000, 70000]
>>> df
calories duration Salary
day1 420 50 50000
day2 380 40 60000
day3 390 45 70000
>>>
>>> # 删除列
>>> df.drop('duration', axis=1, inplace=True)
>>> df
calories Salary
day1 420 50000
day2 380 60000
day3 390 70000
>>>
>>> # 排序
>>> df.sort_values(by='calories', ascending=False, inplace=True)
>>> df
calories Salary
day1 420 50000
day3 390 70000
day2 380 60000
>>>
>>> # 列重命名, inplace是替换原有df, 否则会返回修改后的df, 原df不改变.
>>> df.rename(columns={'Salary': '工资'}, inplace=True)
>>> df
calories 工资
day1 420 50000
day3 390 70000
day2 380 60000
>>>
>>>
2.2.4 从外部数据源创建DataFrame
df_csv = pd.read_csv('example.csv') # 从csv文件创建DataFrame
df_excel = pd.read_excel('example.xlsx') # 从excel文件创建DataFrame
3. Pandas CSV文件
3.1 基本使用
>>> df = pd.read_csv('nba.csv')
>>> df # 或print(df), 文件太长时会打印不全.
Name Team Number ... Weight College Salary
0 Avery Bradley Boston Celtics 0.0 ... 180.0 Texas 7730337.0
1 Jae Crowder Boston Celtics 99.0 ... 235.0 Marquette 6796117.0
2 John Holland Boston Celtics 30.0 ... 205.0 Boston University NaN
3 R.J. Hunter Boston Celtics 28.0 ... 185.0 Georgia State 1148640.0
4 Jonas Jerebko Boston Celtics 8.0 ... 231.0 NaN 5000000.0
.. ... ... ... ... ... ... ...
453 Shelvin Mack Utah Jazz 8.0 ... 203.0 Butler 2433333.0
454 Raul Neto Utah Jazz 25.0 ... 179.0 NaN 900000.0
455 Tibor Pleiss Utah Jazz 21.0 ... 256.0 NaN 2900000.0
456 Jeff Withey Utah Jazz 24.0 ... 231.0 Kansas 947276.0
457 NaN NaN NaN ... NaN NaN NaN
[458 rows x 9 columns]
>>> # to_string()函数把df内容转为字符串, 就可以打印全了.
>>> print(df.to_string())
Name Team Number Position Age Height Weight College Salary
0 Avery Bradley Boston Celtics 0.0 PG 25.0 6-2 180.0 Texas 7730337.0
1 Jae Crowder Boston Celtics 99.0 SF 25.0 6-6 235.0 Marquette 6796117.0
2 John Holland Boston Celtics 30.0 SG 27.0 6-5 205.0 Boston University NaN
3 R.J. Hunter Boston Celtics 28.0 SG 22.0 6-5 185.0 Georgia State 1148640.0
#手工省略后续文本, 太长了.
>>>
使用to_csv()方法, 把DataFrame存储为csv文件
>>> import pandas as pd
>>>
>>> # 三个字段 name, site, age
>>> nme = ["Google", "Runoob", "Taobao", "Wiki"]
>>> st = ["www.google.com", "www.runoob.com", "www.taobao.com", "www.wikipedia.org"]
>>> ag = [90, 40, 80, 98]
>>>
>>> # 字典
>>> dict = {'name': nme, 'site': st, 'age': ag}
>>>
>>> df = pd.DataFrame(dict)
>>>
>>> df.to_csv('site.csv')
>>>
site.csv文件内容如下:
,name,site,age
0,Google,www.google.com,90
1,Runoob,www.runoob.com,40
2,Taobao,www.taobao.com,80
3,Wiki,www.wikipedia.org,98
3.2 数据处理
head(n)
tail(n)
info()
>>> df = pd.read_csv('nba.csv')
>>>
>>> # head(n), 读取前面的n行, 不填参数n, 默认返回5行(数据少于5行时返回实际行)
>>> df.head()
Name Team Number ... Weight College Salary
0 Avery Bradley Boston Celtics 0.0 ... 180.0 Texas 7730337.0
1 Jae Crowder Boston Celtics 99.0 ... 235.0 Marquette 6796117.0
2 John Holland Boston Celtics 30.0 ... 205.0 Boston University NaN
3 R.J. Hunter Boston Celtics 28.0 ... 185.0 Georgia State 1148640.0
4 Jonas Jerebko Boston Celtics 8.0 ... 231.0 NaN 5000000.0
[5 rows x 9 columns]
>>>
>>> # df.tail(n) #读取尾部的n行, 默认是5行.
>>>
>>> # info(), 返回表格的一些基本信息
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 458 entries, 0 to 457
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Name 457 non-null object
1 Team 457 non-null object
2 Number 457 non-null float64
3 Position 457 non-null object
4 Age 457 non-null float64
5 Height 457 non-null object
6 Weight 457 non-null float64
7 College 373 non-null object
8 Salary 446 non-null float64
dtypes: float64(4), object(5)
memory usage: 32.3+ KB
>>>
>>>
4. Pandas JSON
4.1 基本使用
>>> import pandas as pd
>>>
>>> df = pd.read_json('sites.json')
>>> df
id name url likes
0 A001 菜鸟教程 www.runoob.com 61
1 A002 Google www.google.com 124
2 A003 淘宝 www.taobao.com 45
>>>
4.2 内嵌JSON数据
json_normalize()
nested_list.json文件, 它一级key的value的维数不统一, school_name对应的是str, students对应的是dict.
{
"school_name": "ABC primary school",
"class": "Year 1",
"students": [
{
"id": "A001",
"name": "Tom",
"math": 60,
"physics": 66,
"chemistry": 61
},
{
"id": "A002",
"name": "James",
"math": 89,
"physics": 76,
"chemistry": 51
},
{
"id": "A003",
"name": "Jenny",
"math": 79,
"physics": 90,
"chemistry": 78
}]
}
>>> import pandas as pd
>>> import json
>>>
>>> #直接解析维数不同的json, students对应的value没解析完全, 还有嵌套数据.
>>> df = pd.read_json('nested_list.json')
>>> df
school_name class students
0 ABC primary school Year 1 {'id': 'A001', 'name': 'Tom', 'math': 60, 'phy...
1 ABC primary school Year 1 {'id': 'A002', 'name': 'James', 'math': 89, 'p...
2 ABC primary school Year 1 {'id': 'A003', 'name': 'Jenny', 'math': 79, 'p...
>>>
>>> #单独解析student对应的数据
>>> with open('nested_list.json','r') as f:
... data = json.loads(f.read())
...
>>> df_nested_list = pd.json_normalize(
... data,
... record_path =['students'], #展开内嵌的student数据
... meta=['school_name', 'class'] #school_name和class也展示出来.(公共数据?)
... )
>>> df_nested_list
id name math physics chemistry school_name class
0 A001 Tom 60 66 61 ABC primary school Year 1
1 A002 James 89 76 51 ABC primary school Year 1
2 A003 Jenny 79 90 78 ABC primary school Year 1
>>>
更复杂json数据的解析
nested_mix.json
{
"school_name": "local primary school",
"class": "Year 1",
"info": {
"president": "John Kasich",
"address": "ABC road, London, UK",
"contacts": {
"email": "admin@e.com",
"tel": "123456789"
}
},
"students": [
{
"id": "A001",
"name": "Tom",
"math": 60,
"physics": 66,
"chemistry": 61
},
{
"id": "A002",
"name": "James",
"math": 89,
"physics": 76,
"chemistry": 51
},
{
"id": "A003",
"name": "Jenny",
"math": 79,
"physics": 90,
"chemistry": 78
}]
}
解析方法:
>>> import pandas as pd
>>> import json
>>>
>>> with open('nested_mix.json', 'r') as fid:
... data = json.loads(fid.read())
...
>>> df = pd.json_normalize(
... data,
... record_path = ['students'],
... meta = ['class', ['info', 'president'], ['info', 'contacts', 'email']],
... )
>>> df
id name math physics chemistry class info.president info.contacts.email
0 A001 Tom 60 66 61 Year 1 John Kasich admin@e.com
1 A002 James 89 76 51 Year 1 John Kasich admin@e.com
2 A003 Jenny 79 90 78 Year 1 John Kasich admin@e.com
>>>
4.3 读取内嵌数据中的一组数据
nested_deep.json
{
"school_name": "local primary school",
"class": "Year 1",
"students": [
{
"id": "A001",
"name": "Tom",
"grade": {
"math": 60,
"physics": 66,
"chemistry": 61
}
},
{
"id": "A002",
"name": "James",
"grade": {
"math": 89,
"physics": 76,
"chemistry": 51
}
},
{
"id": "A003",
"name": "Jenny",
"grade": {
"math": 79,
"physics": 90,
"chemistry": 78
}
}]
}
需要使用glom模块处理数据嵌套,
先案安装这个模块: pip3 install glom
>>> import pandas as pd
>>> from glom import glom
>>>
>>> df = pd.read_json('nested_deep.json')
>>>
>>> # 只读取内嵌中的math字段
>>> data = df['students'].apply(lambda row: glom(row, 'grade.math'))
>>> data
0 60
1 89
2 79
Name: students, dtype: int64
>>>
5. Pandas数据清洗
对没用的数据进行处理的过程:
5.1 清洗空值
DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
参数:
axis: 0, 默认值, 逢空值剔除整行,
1, 逢空值剔除整列.
how: any, 默认值, 行(或列)中任何一个数据出现NA就去掉整行(或列).
all, 一行(或列)中所有值都是NA, 才会去掉这行(或列).
thresh: 设置需要多少非空值才可以保留下来. ???
subset: 设置想要检查的列, 如果是多个列, 可以使用列名的list作为参数.
inplace: False, 默认值, 原df不变, 返回修改后的df.
True, 计算得到的值直接覆盖之前的值, 源数据会被修改, 并返回None.
判断一列中各个单元格是否为空
>>> import pandas as pd
>>> df = pd.read_csv('property-data.csv')
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 NaN LEXINGTON N NaN 1 850
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
6 100007000.0 NaN WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>> df['NUM_BEDROOMS']
0 3
1 3
2 NaN
3 1
4 3
5 NaN
6 2
7 1
8 na # <-- 结合下面isnull()函数,可以看出na没有被认为是空值.
Name: NUM_BEDROOMS, dtype: object
>>> df['NUM_BEDROOMS'].isnull()
0 False
1 False
2 True
3 False
4 False
5 True
6 False
7 False
8 False
Name: NUM_BEDROOMS, dtype: bool
>>>
可以指定空数据类型
>>> import pandas as pd
>>>
>>>
>>> missing_values = ["n/a", "na", "--"]
>>> # 使用na_valuesr指定空数据类型,
>>> df = pd.read_csv('property-data.csv', na_values = missing_values)
>>> # 可以看出原本的n/a, na, NA, 都被转成了NaN.
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0
1 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN
2 100003000.0 NaN LEXINGTON N NaN 1 850.0
3 100004000.0 201.0 BERKELEY 12 1.0 NaN 700.0
4 NaN 203.0 BERKELEY Y 3.0 2 1600.0
5 100006000.0 207.0 BERKELEY Y NaN 1 800.0
6 100007000.0 NaN WASHINGTON NaN 2.0 HURLEY 950.0
7 100008000.0 213.0 TREMONT Y 1.0 1 NaN
8 100009000.0 215.0 TREMONT Y NaN 2 1800.0
>>> df['NUM_BEDROOMS']
0 3.0
1 3.0
2 NaN
3 1.0
4 3.0
5 NaN
6 2.0
7 1.0
8 NaN
Name: NUM_BEDROOMS, dtype: float64
>>> df['NUM_BEDROOMS'].isnull()
0 False
1 False
2 True
3 False
4 False
5 True
6 False
7 False
8 True
Name: NUM_BEDROOMS, dtype: bool
>>>
标记好空值后, 下面来清洗空值:
>>> import pandas as pd
>>>
>>> df = pd.read_csv('property-data.csv')
>>>
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 NaN LEXINGTON N NaN 1 850
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
6 100007000.0 NaN WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>>
>>> new_df = df.dropna()
>>> new_df # 清洗后, 只有idx为0,1,8的数据保留下来.
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
8 100009000.0 215.0 TREMONT Y na 2 1800
>>>
上面的操作中, 只要一行中任意一列为空, 该行就会被移除.
使用subset参数, 可以指定列, 这些列为空时, 移除该行, 其它列为空时, 不移除.
>>> import pandas as pd
>>> df = pd.read_csv('property-data.csv')
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 NaN LEXINGTON N NaN 1 850
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
6 100007000.0 NaN WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>> df.dropna(subset=['ST_NUM'], inplace = True)
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>>
使用fillna()方法来替换空字段:
>>> import pandas as pd
>>> df = pd.read_csv('property-data.csv')
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 NaN LEXINGTON N NaN 1 850
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
6 100007000.0 NaN WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>> df.fillna(12345, inplace = True)
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 12345.0 LEXINGTON N 12345 1 850
3 100004000.0 201.0 BERKELEY 12 1 12345 700
4 12345.0 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y 12345 1 800
6 100007000.0 12345.0 WASHINGTON 12345 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 12345
8 100009000.0 215.0 TREMONT Y na 2 1800
>>>
使用fillna()方法来替换指定列的空字段:
>>> import pandas as pd
>>> df = pd.read_csv('property-data.csv')
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 NaN LEXINGTON N NaN 1 850
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
6 100007000.0 NaN WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>> df['PID'].fillna(12345, inplace = True)
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 NaN LEXINGTON N NaN 1 850
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 12345.0 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
6 100007000.0 NaN WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>>
用均值/中位数/众数(mean(), median(), mode())填充空字段:
>>> import pandas as pd
>>> df = pd.read_csv('property-data.csv')
>>> x = df["ST_NUM"].mean()
>>>
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.0 PUTNAM Y 3 1 1000
1 100002000.0 197.0 LEXINGTON N 3 1.5 --
2 100003000.0 NaN LEXINGTON N NaN 1 850
3 100004000.0 201.0 BERKELEY 12 1 NaN 700
4 NaN 203.0 BERKELEY Y 3 2 1600
5 100006000.0 207.0 BERKELEY Y NaN 1 800
6 100007000.0 NaN WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.0 TREMONT Y 1 1 NaN
8 100009000.0 215.0 TREMONT Y na 2 1800
>>> df["ST_NUM"].fillna(x, inplace = True)
>>> df
PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0 100001000.0 104.000000 PUTNAM Y 3 1 1000
1 100002000.0 197.000000 LEXINGTON N 3 1.5 --
2 100003000.0 191.428571 LEXINGTON N NaN 1 850
3 100004000.0 201.000000 BERKELEY 12 1 NaN 700
4 NaN 203.000000 BERKELEY Y 3 2 1600
5 100006000.0 207.000000 BERKELEY Y NaN 1 800
6 100007000.0 191.428571 WASHINGTON NaN 2 HURLEY 950
7 100008000.0 213.000000 TREMONT Y 1 1 NaN
8 100009000.0 215.000000 TREMONT Y na 2 1800
>>>
5.2 Pandas清洗格式错误数据
>>>
>>> import pandas as pd
>>> # 第三个日期格式错误
>>> data = {
... "Date": ['2020/12/01', '2020/12/02' , '20201226'],
... "duration": [50, 40, 45]
... }
>>> df = pd.DataFrame(data, index = ["day1", "day2", "day3"])
>>> df
Date duration
day1 2020/12/01 50
day2 2020/12/02 40
day3 20201226 45
>>> df['Date'] = pd.to_datetime(df['Date']) #格式错误日期转为正常格式
>>> df
Date duration
day1 2020-12-01 50
day2 2020-12-02 40
day3 2020-12-26 45
>>>
5.3 Pandas清洗错误数据
直接修改错误数据
>>> import pandas as pd
>>> person = {
... "name": ['Google', 'Runoob' , 'Taobao'],
... "age": [50, 40, 12345],
... }
>>> df = pd.DataFrame(person)
>>> df
name age
0 Google 50
1 Runoob 40
2 Taobao 12345 # age=12345是错误的
>>> df.loc[2, 'age'] = 30 # 直接修改这个数据.
>>> df
name age
0 Google 50
1 Runoob 40
2 Taobao 30
>>>
通过条件语句修改:
>>> import pandas as pd
>>> person = {
... "name": ['Google', 'Runoob' , 'Taobao'],
... "age": [50, 200, 12345],
... }
>>> df = pd.DataFrame(person)
>>> df
name age
0 Google 50
1 Runoob 200
2 Taobao 12345
>>>
>>> for x in df.index:
... if df.loc[x, "age"] > 120:
... df.loc[x, "age"] = 120
...
>>> df
name age
0 Google 50
1 Runoob 120
2 Taobao 120
>>>
通过条件语句删除错误数据:
>>> import pandas as pd
>>> person = {
... "name": ['Google', 'Runoob' , 'Taobao'],
... "age": [50, 40, 12345],
... }
>>> df = pd.DataFrame(person)
>>> df
name age
0 Google 50
1 Runoob 40
2 Taobao 12345 # age=12345是错误的
>>>
>>> for x in df.index:
... if df.loc[x, "age"] > 120:
... df.drop(x, inplace = True) # 删除错误数据
...
>>> df
name age
0 Google 50
1 Runoob 40
>>>
5.4 Pandas清洗重复数据
两个方法:
duplicated(): 如果数据有重复的, 返回True.
drop_duplicated(): 删除重复数据
>>> import pandas as pd
>>> person = {
... "name": ['Google', 'Runoob', 'Runoob', 'Taobao'],
... "age": [50, 40, 40, 23],
... }
>>> df = pd.DataFrame(person)
>>> df
name age
0 Google 50
1 Runoob 40
2 Runoob 40 # 这是一行重复
3 Taobao 23
>>> df.duplicated()
0 False
1 False
2 True # 会返回True
3 False
dtype: bool
>>>
>>> df.drop_duplicates(inplace = True) # 删除第2行的重复数据.
>>> df
name age
0 Google 50
1 Runoob 40
3 Taobao 23
>>>
6. Pandas常用函数
6.1 读取数据
函数 | 说明 |
---|---|
pd.read_csv(file_name) | 读取CSV文件 |
pd.read_excel(file_name) | 读取Excel文件 |
pd.read_sql(query, connection_object) | 从SQL数据库中读取数据 |
pd.read_json(json_string) | 从JSON字符串中读取数据 |
pd.read_html(url) | 从HTML页面中读取数据 |
import pandas as pd
df = pd.read_csv('data.csv')
df = pd.read_excel('data.xlsx')
import sqlite3
conn = sqlite3.connect('database.db')
df = pd.read_sql('SELECT * FROM table_name', conn)
json_string = '{"name": "John", "age": 30, "city": "New York"}'
df = pd.read_json(json_string)
url = 'https://www.runoob.com'
dfs = pd.read_html(url)
df = dfs[0] # 选择第一个数据框
6.2 查看数据
函数 | 说明 |
---|---|
df.head(n) | 显示前n行数据 |
df.tail(n) | 显示后n行数据 |
df.info() | 显示数据的信息: 列名, 数据类型, 缺失值等 |
df.describe() | 显示数据的基本统计信息: 均值, 方差, 最大值, 最小值等 |
df.shape() | 显示数据的行数和列数 |
6.3 数据清洗
函数 | 说明 |
---|---|
df.dropna() | 删除包含缺失值的行或列 |
df.fillna(value) | 将缺失值替换为指定的值 |
df.replace(old_value, new_value) | 将指定值替换为新值 |
df.duplicated() | 检查是否有重复的数据 |
df.drop_duplicated() | 删除重复的数据 |
6.4 数据选择和切片
函数 | 说明 |
---|---|
df[column_name] | 选择指定的列 |
df.loc[row_index, column_name] | 通过标签选择数据 |
df.loc[row_index, column_index] | 通过位置择数据 |
df.ix[row_index, column_name] | 通过行标签或位置选择数据 |
df.filter(items=[col_name1, col_name2]) | 选择指定的列 |
df.filter(regex='regex') | 选择列名匹配正则表达式的列 |
df.sample(n) | 随机选择n行数据 |
6.5 数据排序
函数 | 说明 |
---|---|
df.sort_values(column_name) | 按照指定列的值排序 |
df.sort_values([col_name1, col_name2], ascending=[True, False]) | 按照多个列的值排序 |
df.sort_index() | 按照索引排序 |
6.6 数据分组和聚合
函数 | 说明 |
---|---|
df.groupby(column_name) | 按照指定列进行分组 |
df.aggregate(function_name) | 对分组后的数据进行聚合操作 |
df.pivot_table(values, index, columns, aggfunc) | 生成透视表 |
6.7 数据合并
函数 | 说明 |
---|---|
pd.concat([df1, df2]) | 将多个数据框按行或列合并 |
pd.mearge(df1, df2, on=column_name) | 将多个数据框按指定列进行合并 |
6.8 数据选择和过滤
函数 | 说明 |
---|---|
df.loc(row_indexer, column_indexer) | 按标签选择行或列 |
df.iloc(row_indexer, column_indexer) | 按位置选择行或列 |
df[df[column_name] > value] | 选择列中满足条件的行 |
df.query('column_name > value') | 使用字符串表达式选择列中满足条件的列 |
6.9 数据统计和描述
函数 | 说明 |
---|---|
df.describe() | 计算基本统计信息, 如均值, 标准差, 最小值, 最大值等 |
df.mean() | 计算每列的平均值 |
df.median() | 计算每列的中位数 |
df.mode() | 计算每列的众数 |
df.count() | 计算每列非缺失值的数量 |
6.10 例子:
>>> import pandas as pd
>>> df = pd.read_json('data.json')
>>> df
name age gender score
0 Alice 25.0 female 80.0
1 Bob NaN male 90.0
2 Charlie 30.0 male NaN
3 David 35.0 male 70.0
>>>
>>> # 删除缺失值
>>> df1 = df.dropna()
>>> df1
name age gender score
0 Alice 25.0 female 80.0
3 David 35.0 male 70.0
>>>
>>> # 重命名列名
>>> df2 = df.rename(columns={'name': '姓名', 'age': '年龄', 'gender': '性别', 'score': '
成绩'})
>>> df2
姓名 年龄 性别 成绩
0 Alice 25.0 female 80.0
1 Bob NaN male 90.0
2 Charlie 30.0 male NaN
3 David 35.0 male 70.0
>>>
>>> # 按成绩排序
>>> df3 = df.sort_values(by='score', ascending=False)
>>> df3
name age gender score
1 Bob NaN male 90.0
0 Alice 25.0 female 80.0
3 David 35.0 male 70.0
2 Charlie 30.0 male NaN
>>>
>>> # 按性别分组并计算平均年龄和成绩
>>> df4 = df.groupby('gender').agg({'age': 'mean', 'score': 'mean'})
>>> df4
age score
gender
female 25.0 80.0
male 32.5 80.0
>>>
>>> # 选择成绩大于等于90的行,并只保留姓名和成绩两列
>>> df5 = df.loc[df['score'] >= 80, ['name', 'score']]
>>> df5
name score
0 Alice 80.0
1 Bob 90.0
>>>
>>> # 计算每列的基本统计信息, 由于只有age和score的类型是数值, 所以只统计age和score两列.
>>> stats = df.describe()
>>> stats
age score
count 3.0 3.0
mean 30.0 80.0
std 5.0 10.0
min 25.0 70.0
25% 27.5 75.0
50% 30.0 80.0
75% 32.5 85.0
max 35.0 90.0
>>>
>>> # 计算每列的平均值, 由于只有age和score的类型是数值, 所以只对age和score两列计算平均值.
>>> mean = df.mean()
>>> type(mean)
<class 'pandas.core.series.Series'>
>>> mean
age 30.0
score 80.0
dtype: float64
>>>
>>> # 计算每列的中位数
>>> median = df.median()
>>> median
age 30.0
score 80.0
dtype: float64
>>>
>>> # 计算每列的众数. 结果看着有点怪.
>>> mode = df.mode()
>>> type(mode)
<class 'pandas.core.frame.DataFrame'>
>>> mode
name age gender score
0 Alice 25.0 male 70.0
1 Bob 30.0 NaN 80.0
2 Charlie 35.0 NaN 90.0
3 David NaN NaN NaN
>>>
>>> # 计算每列非缺失值的数量
>>> count = df.count()
>>> type(count)
<class 'pandas.core.series.Series'>
>>> count
name 4
age 3
gender 4
score 3
dtype: int64
>>>
7. 数据检索
https://blog.csdn.net/Gefangenes/article/details/131340259
7.1 数据
>>> import pandas as pd
>>>
>>> fp = "http://databook.top:8888/pandas/cn-people.csv"
>>>
>>> df = pd.read_csv(fp)
>>> df
年份 指标编码 指标中文 value
0 2021 A030101 年末总人口 14
1 2020 A030101 年末总人口 14
2 2019 A030101 年末总人口 14
3 2018 A030101 年末总人口 14
4 2017 A030101 年末总人口 14
.. ... ... ... ...
215 1982 A030105 乡村人口 8
216 1981 A030105 乡村人口 7
217 1980 A030105 乡村人口 7
218 1979 A030105 乡村人口 7
219 1978 A030105 乡村人口 7
[220 rows x 4 columns]
>>>
7.2 行列过滤
7.2.1 loc函数
在一个语句中同时指定行和列的条件
>>> # 选择第1到5行的所有列
>>> df.loc[1:5, :]
年份 指标编码 指标中文 value
1 2020 A030101 年末总人口 14
2 2019 A030101 年末总人口 14
3 2018 A030101 年末总人口 14
4 2017 A030101 年末总人口 14
5 2016 A030101 年末总人口 13
>>>
>>> # 选择第1和第5行的所有列
>>> df.loc[[1,5], :]
年份 指标编码 指标中文 value
1 2020 A030101 年末总人口 14
5 2016 A030101 年末总人口 13
>>>
>>> # 选择指定列范围, 注意, 也是使用:表示范围
>>> df.loc[:, '年份':'指标中文']
年份 指标编码 指标中文
0 2021 A030101 年末总人口
1 2020 A030101 年末总人口
2 2019 A030101 年末总人口
3 2018 A030101 年末总人口
4 2017 A030101 年末总人口
.. ... ... ...
215 1982 A030105 乡村人口
216 1981 A030105 乡村人口
217 1980 A030105 乡村人口
218 1979 A030105 乡村人口
219 1978 A030105 乡村人口
[220 rows x 3 columns]
>>>
>>> # 选择指定列
>>> df.loc[:, ['年份','指标中文']]
年份 指标中文
0 2021 年末总人口
1 2020 年末总人口
2 2019 年末总人口
3 2018 年末总人口
4 2017 年末总人口
.. ... ...
215 1982 乡村人口
216 1981 乡村人口
217 1980 乡村人口
218 1979 乡村人口
219 1978 乡村人口
[220 rows x 2 columns]
>>>
>>> # 同时选择行和列
>>> df.loc[1:3, ['年份','指标中文']]
年份 指标中文
1 2020 年末总人口
2 2019 年末总人口
3 2018 年末总人口
7.2.2 iloc函数
通过整数位置索引选择行列数据.
与loc方法类似, 不过iloc使用的索引是整数而不是标签.
>>> #选择第1到4行, 与df.loc[1:5, :]的区别是loc[1:5, :]包括第5行.
>>> df.iloc[1:5, :]
年份 指标编码 指标中文 value
1 2020 A030101 年末总人口 14
2 2019 A030101 年末总人口 14
3 2018 A030101 年末总人口 14
4 2017 A030101 年末总人口 14
>>>
>>> #选择第一和第5行, 与df.loc[[1,5], :]结果相同
>>> df.iloc[[1,5], :]
年份 指标编码 指标中文 value
1 2020 A030101 年末总人口 14
5 2016 A030101 年末总人口 13
>>>
>>> #按范围选择列
>>> df.iloc[:, 0:3] # 选择第0到2列, 1) 只能使用整数索引, 2) 不包括第3列.
年份 指标编码 指标中文
0 2021 A030101 年末总人口
1 2020 A030101 年末总人口
2 2019 A030101 年末总人口
3 2018 A030101 年末总人口
4 2017 A030101 年末总人口
.. ... ... ...
215 1982 A030105 乡村人口
216 1981 A030105 乡村人口
217 1980 A030105 乡村人口
218 1979 A030105 乡村人口
219 1978 A030105 乡村人口
[220 rows x 3 columns]
>>>
>>> # 选择第0列和第2列
>>> df.iloc[:, [0,2]]
年份 指标中文
0 2021 年末总人口
1 2020 年末总人口
2 2019 年末总人口
3 2018 年末总人口
4 2017 年末总人口
.. ... ...
215 1982 乡村人口
216 1981 乡村人口
217 1980 乡村人口
218 1979 乡村人口
219 1978 乡村人口
[220 rows x 2 columns]
>>>
>>> #同时选择行和列
>>> df.iloc[1:5, [0,2]]
年份 指标中文
1 2020 年末总人口
2 2019 年末总人口
3 2018 年末总人口
4 2017 年末总人口
>>>
7.3 条件过滤
loc和iloc是通过索引或列名来过滤.
还可以根据列的值来过滤.
7.3.1 单条件
根据列的值来过滤, 列的值可以是数字或字符串.
>>> # 按数字大小过滤
>>> df[df['年份']>2020]
年份 指标编码 指标中文 value
0 2021 A030101 年末总人口 14
44 2021 A030102 男性人口 7
88 2021 A030103 女性人口 6
132 2021 A030104 城镇人口 9
176 2021 A030105 乡村人口 4
>>>
>>> # 按包含字符串过滤. .head()表示只取前面几个.
>>> df[df['指标中文'].str.contains('村人')].head()
年份 指标编码 指标中文 value
176 2021 A030105 乡村人口 4
177 2020 A030105 乡村人口 5
178 2019 A030105 乡村人口 5
179 2018 A030105 乡村人口 5
180 2017 A030105 乡村人口 5
7.3.2 多条件
可以通过逻辑符号&和|设置多个条件.
>>> # 两个条件相与, 注意两个条件要分别用小括号包围.
>>> df[(df['年份']>2020) & (df['指标中文'].str.contains('村人'))].head()
年份 指标编码 指标中文 value
176 2021 A030105 乡村人口 4
>>>
>>> # 两个条件相或.
>>> df[(df['年份']>2020) | (df['指标中文'].str.contains('村人'))].head()
年份 指标编码 指标中文 value
0 2021 A030101 年末总人口 14
44 2021 A030102 男性人口 7
88 2021 A030103 女性人口 6
132 2021 A030104 城镇人口 9
176 2021 A030105 乡村人口 4
7.4 函数过滤
有两个作用: 1) 过滤数据, 2) 转换数据.
7.4.1 apply
对某一列施加指定函数, 返回新列, 不修改原列数据
>>> #增加一列"value10倍", 值为value列的值乘以10.
>>> df['value10倍'] = df['value'].apply(lambda x:x*10)
>>> df
年份 指标编码 指标中文 value value10倍
0 2021 A030101 年末总人口 14 140
1 2020 A030101 年末总人口 14 140
2 2019 A030101 年末总人口 14 140
3 2018 A030101 年末总人口 14 140
4 2017 A030101 年末总人口 14 140
.. ... ... ... ... ...
215 1982 A030105 乡村人口 8 80
216 1981 A030105 乡村人口 7 70
217 1980 A030105 乡村人口 7 70
218 1979 A030105 乡村人口 7 70
219 1978 A030105 乡村人口 7 70
[220 rows x 5 columns]
7.4.2 map
对某一列施加指定map, 返回新列, 不修改原列数据
>>> #增加一列"指标缩写", 值为把'指标中文'列的值map为其它值.
>>> df['指标缩写'] = df['指标中文'].map({'年末总人口':'总人口', '乡村人口':'人口'})
>>> df
年份 指标编码 指标中文 value value10倍 指标缩写
0 2021 A030101 年末总人口 14 140 总人口
1 2020 A030101 年末总人口 14 140 总人口
2 2019 A030101 年末总人口 14 140 总人口
3 2018 A030101 年末总人口 14 140 总人口
4 2017 A030101 年末总人口 14 140 总人口
.. ... ... ... ... ... ...
215 1982 A030105 乡村人口 8 80 人口
216 1981 A030105 乡村人口 7 70 人口
217 1980 A030105 乡村人口 7 70 人口
218 1979 A030105 乡村人口 7 70 人口
219 1978 A030105 乡村人口 7 70 人口
[220 rows x 6 columns]