一:简介
Pandas 是一个开源的第三方 Python 库,从 Numpy 和 Matplotlib 的基础上构建而来,享有数据分析
“三剑客之一”的盛名(NumPy
、Matplotlib
、Pandas
)。提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。B站视频。
pip install openpyxl
pip install pandas
# 使用阿里云镜像安装
pip install pandas -i https://mirrors.aliyun.com/pypi/simple/
# 引入模块,简写成pd(这是大家都采取不成文的习惯)
import pandas as pd
二:数据结构
要学Pandas就必须要先了解Pandas的两大数据结构:Series 和 DataFrame。
2.1 Series 一维数据结构
- Series类似于一维数组结构,用于表示一行数据或者一列数据。由
索引index
➕值values
组成。 - 可以通过list或者dict来构造Series。
- 访问数据采用字典方式,通过
[索引]
来获取对应的数据。 - Series 重写了算术运算符,如果数据是数字可以两个对象直接相加series1 + series2,对于索引相同的值可以做如加法运算,索引不相同的返回
NaN
(Not a Number)。 - Series也提供了add()、sub()、mul()、div()等方法,提供了一些参数来设置,如fill_value表示默认填充值。
列表list构建
- series.index:获取索引列对象
- series.values:获取值列表
# 表示一列数据(第一列表示默认自带的索引从0开始),也可以通过参数index=[]自己设置索引
series1 = pd.Series(['张无忌', '孙悟空', '武大郎'])
print(series1)
0 张无忌
1 孙悟空
2 武大郎
dtype: object
# 武大郎
print(series1[2])
# index=keys(),RangeIndex(start=0, stop=3, step=1)
print(series1.index, series1.keys())
# ['张无忌' '孙悟空' '武大郎']
print(series1.values)
# 显式设置索引列
series1 = pd.Series(['张无忌', '孙悟空', '武大郎'], index=['a', 'b', 'c'])
print(series1)
字典构建
series2 = pd.Series({'a': '张无忌', 'b': '孙悟空', 'c': '武大郎'})
print(series2)
a 张无忌
b 孙悟空
c 武大郎
dtype: object
# 武大郎
print(series2['c'])
series1 = pd.Series({'a': 1, 'b': 2, 'c': 3})
series2 = pd.Series({'a': 10, 'b': 20, 'c': 30, 'd': 40})
print(series1 + series2)
a 11.0
b 22.0
c 33.0
d NaN
dtype: float64
# fill_value: 表示索引不存在按照默认值0算
add = series1.add(series2, fill_value=0)
print(add)
a 11.0
b 22.0
c 33.0
d 40.0
dtype: float64
pd.Series(data, index, name)
2.2 DataFrame 二维数据结构
DataFrame类似于一个二维数组,可以看做成表格,由行和列组成。表格中的每一行每一列都是Series数据结构。
Series是由index索引➕values值组成。对于列index是指的列索引,对于行index是指的行索引(列名)。
# data: 每一行数据
# columns:列名
# index:自定义索引列,默认是数字从0开始,也可以显式指定
data = [('猛男', 30, '男'), ('舔狗', 50, '男'), ('细狗', 18, '男')]
df = pd.DataFrame(data, columns=('姓名', '年龄', '性别'))
print(df)
姓名 年龄 性别
0 猛男 30 男
1 舔狗 50 男
2 细狗 18 男
print(df['姓名'])
# 每一列也是
print(type(df['姓名']))
# 获取指定的行,没行也是一个Series ['猛男' 30 '男']
print(df.loc[0].values, type(df.loc[0]))
# 行的index是列名
# Index(['姓名', '年龄', '性别'], dtype='object')
print(df.loc[0].index)
Series作为行还是作为列主要取决于在构建DataFrame时是使用字典dict(列)还是列表list(行)。
作为列
# 方式一:value是list类型
# dtype指定列的数据类型,注意:只能统一指定,不能按照列来指定
df = pd.DataFrame({'姓名': ['猛男', '舔狗', '细狗'],
'年龄': [10, 20, 30],
'性别': ['男', '男', '男']},
index=[1, 2, 3],
dtype=str)
# 单独指定列的数据类型
df['姓名'] = df['姓名'].astype(str)
df['年龄'] = df['年龄'].astype(float)
df['性别'] = df['性别'].astype(str)
print(df)
姓名 年龄 性别
1 猛男 10.0 男
2 舔狗 20.0 男
3 细狗 30.0 男
# 方式二:value是Series对象
# 作为列,index表示列索引,name就表示列名
c1 = pd.Series(['猛男', '舔狗', '细狗'], index=[1, 2, 3], name='姓名')
c2 = pd.Series([10, 20, 30], index=[1, 2, 3], name='年龄')
c3 = pd.Series(['男', '男', '男'], index=[1, 2, 3], name='性别')
df = pd.DataFrame({c1.name: c1, c2.name: c2, c3.name: c3})
print(df)
姓名 年龄 性别
1 猛男 10 男
2 舔狗 20 男
3 细狗 30 男
作为行
# 作为行,index表示列名,name就表示列索引
header = ['姓名', '年龄', '性别']
r1 = pd.Series(['猛男', 10, '男'], index=header, name='a')
r2 = pd.Series(['舔狗', 20, '男'], index=header, name='b')
r3 = pd.Series(['细狗', 30, '男'], index=header, name='c')
df = pd.DataFrame([r1, r2, r3])
df.to_excel('temp.xlsx', index=False, header=False)
print(df)
姓名 年龄 性别
a 猛男 30 男
b 舔狗 50 男
c 细狗 18 男
三:DataFrame API
属性或方法 |
描述 |
列索引操作 |
|
|
获取表头列索引对象 |
|
获取表头列索引对象的values列表 |
|
重新设置表头 |
|
获取所有列索引 |
获取部分行 |
|
|
获取所有列索引列表 |
|
获取所有行数据,返回值类型ndarray’> [[‘张三’, 20],[‘李四’, 25],[‘王五’, 30]] |
|
获取数据行数(不算表头) |
|
获取数据行数和列数tuple |
|
获取前n行数据,返回值类型 |
|
获取最后n行数据,返回值类型 |
|
随机获取n行数据,返回值类型 |
获取指定行 |
|
|
df.loc[1]:获取指定行的 |
|
df.loc[[1, 2]]:获取指定的多个行索引数据,返回值类型为 |
|
df.iloc[1]: 获取指定行的 |
|
df.loc[df[‘姓名’] == ‘李四’] : 返回满足条件的行,返回值类型 |
|
多个loc表示and关系 |
获取指定列 |
|
|
df[‘姓名’] :获取指定列的数据,返回值类型 |
|
df[[‘姓名’, ‘年龄’]] : 获取多列数据,返回值类型 |
获取指定行指定列 |
|
|
df.loc[1, ‘姓名’] :获取指定行指定列的单元格值,返回值 |
|
df.loc[1, [‘姓名’, ‘性别’]] : 获取某行的多列值,返回值类型 |
|
df.at[1, ‘姓名’] = df.loc[1, ‘姓名’] 获取指定指定列的值,返回值 |
|
df[‘姓名’].at[1] : 获取指定列的指定行的值,返回值 |
columns:表头操作
import pandas as pd
df = pd.DataFrame([('张三', 20), ('李四', 25), ('王五', 30)], columns=('姓名', '年龄'))
# Index(['姓名', '年龄'], dtype='object')
print(df.columns, df.keys())
# ['姓名' '年龄']
print(df.columns.values)
# 重新设置表头
df.columns = ['Name', 'Age']
print(df)
Name Age
0 张三 20
1 李四 25
2 王五 30
df.loc[df[‘列名’] == ‘列值’]:获取满足条件的行
df = pd.DataFrame([('张三', 20, '男'), ('李四', 25, '男'), ('王五', 30, '男')],
columns=('姓名', '年龄', '性别'))
print(df['姓名'] == '李四')
0 False
1 True
2 False
Name: 姓名, dtype: bool
# 返回值类型为
print(type(df['姓名'] == '李四'))
df = pd.DataFrame([('张三', 20, '男'), ('李四', 25, '男'), ('王五', 30, '男')],
columns=('姓名', '年龄', '性别'))
print(df.loc[df['姓名'] == '李四'])
姓名 年龄 性别
1 李四 25 男
#
print(type(df.loc[df['姓名'] == '李四']))
print(df.loc[df['姓名'] == '李四'].loc[df['性别'] == '男'])
df.set_index(‘索引列名’, inplace=True) 指定索引列
pandas将索引列index
和数据列columns
作为两个不同的概念来对待的。
df.set_index(“索引列名”, inplace=True):用于将某列作为索引列,inplace=True表示替换默认的索引列。
import pandas as pd
df = pd.DataFrame([(1, '张三', 20, '男'), (2, '李四', 25, '男'), (3, '王五', 30, '男')],
columns=('id', '姓名', '年龄', '性别'))
print(df)
id 姓名 年龄 性别
0 1 张三 20 男
1 2 李四 25 男
2 3 王五 30 男
# 设置id为索引列,inplace=True表示替换默认的索引列
df.set_index('id', inplace=True)
print(df)
姓名 年龄 性别
id
1 张三 20 男
2 李四 25 男
3 王五 30 男
# Int64Index([1, 2, 3], dtype='int64', name='id')
print(df.index)
四:Excel读写
4.1 pd.ExcelFile(‘excel路径’):构建ExcelFile对象
file = pd.ExcelFile('订单.xlsx')
names = file.sheet_names
4.2 pd.ExcelWriter(‘文件路径’):构建ExcelWriter对象
4.3 pd.read_excel() -> dict[IntStrT, DataFrame]
- io:excel文件路径。
-
sheet_name:list[IntStrT]
指定读取的sheet,默认为第一个,可以通过指定sheet的名字或者索引(从0开始),多个使用列表。 - skiprows:跳过的行,从0开始。
- header:指定表头实际的行索引。
- index_col=‘ID’:设置索引列,设置后如果再写入pandas就不会再生成默认的索引列了。
- dtype={‘ID’: str}:指定某些列的数据类型。注意:NaN的类型默认为float,NaN不能转换为int,可以变相的设置为str
- 返回值类型:
dict[IntStrT, DataFrame]
:key表示sheet的索引,DataFrame表示每个Sheet对应的数据。
读取所有sheet的每行数据。
import pandas as pd
excel = pd.read_excel('订单.xlsx', sheet_name=[0, 1], skiprows=0)
for sheet, df in excel.items():
for row in df.values:
print(row)
4.4 pd.read_csv():读取csv、tsv、txt文件
import pandas as pd
csv = pd.read_csv('test.csv', index_col='id')
tsv = pd.read_csv('test.tsv', sep='t', index_col='id')
txt = pd.read_csv('test.txt', sep='|', index_col='id')
4.5 pd.read_sql() : 从数据库中读取数据
import pandas as pd
import pymysql
import sqlalchemy
pymysql.install_as_MySQLdb()
sql = 'select id, username, gender from user'
conn = sqlalchemy.create_engine('mysql://root:root123@127.0.0.1:3306/test?charset=utf8')
user = pd.read_sql(sql, conn)
print(user)
4.5 df.to_excel()
- excel_writer:文件路径或者ExcelWriter
- sheet_name:Sheet名称
- index:第一列是否需要索引
- header:是否指定表头bool,默认为True,当没有显式指定表头时使用列索引作为表头。
写入单个Sheet
import pandas as pd
header = ('姓名', '年龄')
rows = [('张三', 20), ('李四', 25)]
df = pd.DataFrame(rows, columns=header)
df.to_excel('test.xlsx', sheet_name='Sheet1', index=False)
写入多个Sheet
import pandas as pd
header1 = ('姓名', '年龄')
rows1 = [('张三', 20), ('李四', 25)]
df = pd.DataFrame(rows1, columns=header1)
header2 = ('姓名', '年龄')
rows2 = [('虚竹', 20), ('梦姑', 25)]
df2 = pd.DataFrame(rows2, columns=header2)
writer = pd.ExcelWriter('test1.xlsx')
df.to_excel(writer, sheet_name='Sheet1', index=False)
df2.to_excel(writer, sheet_name='Sheet2', index=False)
writer.close()
五:基本案例
行操作
import pandas as pd
sheet1 = pd.DataFrame([(1, '张三'), (2, '李四'), (3, '王五')], columns=('id', 'name'))
sheet2 = pd.DataFrame([(4, '赵六'), (5, '冯七')], columns=('id', 'name'))
# 追加Sheet drop=True 放弃旧的index
# users = sheet1.append(sheet2).reset_index(drop=True)
users = pd.concat([sheet1, sheet2]).reset_index(drop=True)
# 追加一行
user = pd.Series({'id': 6, 'name': '六六'})
users = users.append(user, ignore_index=True)
# 修改单元格数据
users.at[2, 'name'] = '隔壁老王'
# 整行替换
user = pd.Series({'id': 66, 'name': '六六'})
users.iloc[5] = user
# 插入一行
part1 = users[:3]
insert = pd.Series({'id': 99, 'name': '插队狗'})
part2 = users[3:]
users = part1.append(insert, ignore_index=True).append(part2).reset_index(drop=True)
# 删除多行 index也可以是range
users.drop(index=[0, 1], inplace=True)
# 通过切片删除
users.drop(index=users[3:5].index, inplace=True)
# 根据条件移除
where = users.loc[users['id'] == 3]
users.drop(index=where.index, inplace=True)
print(users)
列操作
import pandas as pd
import numpy as np
sheet1 = pd.DataFrame([(1, '张三'), (2, '李四'), (3, '王五')], columns=('id', 'name'))
sheet2 = pd.DataFrame([(1, 10), (2, 20), (3, 30)], columns=('id', 'age'))
# 拼接列
all = pd.concat([sheet1, sheet2], axis=1)
print(all)
# 追加一列
sheet1['no'] = np.arange(1000, len(sheet1) + 1000)
# 删除列
sheet1.drop(columns=['name'], inplace=True)
# 插入一列
sheet1.insert(1, column='age', value=np.repeat(18, len(sheet1)))
# 重命名列名
sheet1.rename(columns={'id': 'ID', 'no': 'NO'}, inplace=True)
# 删除任意列种有NaN的行
sheet1.dropna(inplace=True)
print(sheet1)
过滤
import pandas as pd
df = pd.DataFrame([(1, 10, 0.1), (2, 20, 0.2), (3, 15, 0.15)], columns=('id', 'price', 'discount'))
df.set_index('id', inplace=True)
df = df.loc[df['price'].apply(lambda x: 15 0.15)]
# 简写形式:可以直接通过 df.price = df['price']
df = df.loc[df.price.apply(lambda x: 15 0.15)]
print(df)
计算某列的值
计算某列的值:Series整列直接相乘。
import pandas as pd
df = pd.DataFrame([(1, 10, 0.1), (2, 20, 0.2)], columns=('id', 'price', 'discount'))
df.set_index('id', inplace=True)
#
# Python是可以对类进行计算符重写的,所以这里可以加减相乘等计算
print(type(df['price']))
df['amount'] = df['price'] * df['discount']
print(df)
计算某列的值:单元格值 * 单元格值。这种方式可以对每一行做特殊处理。
import pandas as pd
df = pd.DataFrame([(1, 10, 0.1), (2, 20, 0.2)], columns=('id', 'price', 'discount'))
df.set_index('id', inplace=True)
for i in df.index:
df.at[i, 'amount'] = df.at[i, 'price'] * df.at[i, 'discount']
通过函数计算某列的值。
import pandas as pd
df = pd.DataFrame([(1, 10, 0.1), (2, 20, 0.2)], columns=('id', 'price', 'discount'))
df.set_index('id', inplace=True)
for i in df.index:
# apply(函数名|匿名函数)
df['amount'] = df['price'].apply(lambda x: x + 2)
print(df)
复杂计算列
import pandas as pd
def calc(row):
return (row['p1'] * 2 + row['p2'] * 3)/2 + row['id']
sheet1 = pd.DataFrame([(1, 20, 30), (2, 30, 40)], columns=('id', 'p1', 'p2'))
sheet1['p3'] = sheet1.apply(calc, axis=1)
print(sheet1)
排序
import pandas as pd
df = pd.DataFrame([(1, 10, 0.1), (2, 20, 0.2), (3, 15, 0.15)], columns=('id', 'price', 'discount'))
df.set_index('id', inplace=True)
# inplace=True表示影响原来的df的值, ascending=True表示升续
# df.sort_values(by='price', inplace=True, ascending=True)
# 多个值排序:price asc, discount desc
df.sort_values(by=['price', 'discount'], inplace=True, ascending=[True, False])
print(df)
统计每行的值和统计每列的值
import pandas as pd
# 每行求和、求平均值
df = pd.DataFrame([(1, '张三', 80, 90), (2, '李四', 70, 88), (3, '王五', 90, 98)], columns=('id', 'name', 'chinese', 'english'))
row = df[['chinese', 'english']]
df['sum'] = row.sum(axis=1)
df['avg'] = row.mean(axis=1)
print(df)
# 每列就平均值
col_avg = df[['chinese', 'english', 'sum', 'avg']].mean()
col_avg['id'] = ''
col_avg['name'] = 'summary'
new_df = df.append(col_avg, ignore_index=True)
print(new_df)
合并和连接join
import pandas as pd
sheet1 = pd.DataFrame([(1, '张三'), (2, '李四'), (3, '王五')], columns=('id', 'name'))
sheet1.set_index('id', inplace=True)
sheet2 = pd.DataFrame([(1, 88), (2, 99)], columns=('id', 'score'))
sheet2.set_index('id', inplace=True)
# how: 表示连接方式, left/right/inner
# left_on:表示左表关联的字段,right_on表示右表关联的字段,on:表示左右两个表的关联字段相同
# 表示如果值为NaN就设置指定的值
# student_score = sheet1.merge(sheet2, how='left', on='id').fillna(0)
# student_score = sheet1.merge(sheet2, how='left', left_on='id', right_on='id').fillna(0)
# merge如果不设置on、left_on、right_on 会报错而join函数会自动识别每个sheet的index只作为关联字段
student_score = sheet1.merge(sheet2, how='left', left_on=sheet1.index, right_on=sheet2.index).fillna(0)
# 设置列的类型,数字默认是float
student_score.score = student_score.score.astype(int)
# print(student_score)
student_score2 = sheet1.join(sheet2, how='left').fillna(0)
student_score2.score = student_score2.score.astype(int)
print(student_score2)
去除重复的行
import pandas as pd
# 去除重复行
df = pd.DataFrame([(1, '张三', 80, 90), (2, '李四', 70, 88), (3, '张三', 90, 98), (4, '张三', 90, 98)],
columns=('id', 'name', 'chinese', 'english'))
# 指定重复数据依据的字段, 如果重复可以选择留下first或者last
df.drop_duplicates(subset=['name'], inplace=True, keep='first')
print(df)
获取重复的行
import pandas as pd
df = pd.DataFrame([(1, '张三', 80, 90), (2, '李四', 70, 88), (3, '张三', 90, 98), (4, '张三', 90, 98)],
columns=('id', 'name', 'chinese', 'english'))
# True表示重复
duplicated = df.duplicated(subset=['name'])
# 表示是否有True值
print(duplicated.any())
# 找出重复的行
duplicated = duplicated[duplicated==True]
print(df.iloc[duplicated.index])
分组求和
import pandas as pd
df = pd.DataFrame([
(1, '上海', '2021-03-01', 80), (2, '上海', '2022-05-01', 59),
(3, '上海', '2022-07-01', 80), (4, '上海', '2022-08-01', 59),
(5, '郑州', '2021-10-01', 50), (6, '郑州', '2021-10-01', 80),
(7, '郑州', '2022-10-01', 30), (8, '郑州', '2022-10-01', 20)
], columns=('id', 'city', 'date', 'score'))
# 添加一列
df['year'] = pd.DatetimeIndex(df['date']).year
groups = df.groupby(['city', 'year'])
sum = groups['score'].sum()
count = groups['id'].count()
pd2 = pd.DataFrame({'sum': sum, 'count': count})
print(pd2)
填充列的值
import pandas as pd
from datetime import date, timedelta
def add_month(start_date, month):
yd = month // 12
m = start_date.month + month % 12
if m != 12:
yd += m // 12
m = m % 12
return date(start_date.year + yd, m, start_date.day)
books = pd.read_excel('book.xlsx', skiprows=3, usecols='C:F', dtype={'ID': str, 'InStore': str, 'Date': str})
start = date(2022, 10, 30)
for i in books.index:
books['ID'].at[i] = i + 1
books['InStore'].at[i] = 'Yes' if i % 2 == 0 else 'No'
# 加天
books.at[i, 'Date'] = start + timedelta(days=i)
# 加年
#books.at[i, 'Date'] = date(start.year + 1, start.month, start.day)
# 加月
#books.at[i, 'Date'] = add_month(start, i)
print(books)
books.set_index('ID', inplace=True)
books.to_excel('book2.xlsx')
数据拆分
import pandas as pd
# 数据分列
df = pd.DataFrame([(1, '张 三'), (2, '李 四'), (3, '王 五')], columns=('id', 'name'))
tmp = df['name'].str.split(" ",expand=True)
# 列不存在则添加
df['first'] = tmp[0]
df['last'] = tmp[1]
print(df)
校验数据的合法性
import pandas as pd
def check_age(row):
if row.age 150:
print(f'{row.id} : {row.age} 数据非法')
pd = pd.DataFrame([(1, '张三', 30), (2, '李四', -1), (3, '王五', 1000)], columns=('id', 'name', 'age'))
# axis = 1: 表示从左到右(逐行校验)
# axis = 0: 表示从上到下(逐列校验)
pd.apply(check_age, axis=1)
旋转
import pandas as pd
pd.options.display.max_columns = 999
df = pd.DataFrame([(1, '张三', 90), (2, '李四', 70), (3, '张三', 90)],
columns=('id', 'name', 'chinese'))
df.set_index('id', inplace=True)
transpose = df.transpose()
print(transpose)
透视表分组求和
import pandas as pd
import numpy as np
df = pd.DataFrame([
(1, '上海', '2021-03-01', 80), (2, '上海', '2022-05-01', 59),
(3, '上海', '2022-07-01', 80), (4, '上海', '2022-08-01', 59),
(5, '郑州', '2021-10-01', 50), (6, '郑州', '2021-10-01', 80),
(7, '郑州', '2022-10-01', 30), (8, '郑州', '2022-10-01', 20)
], columns=('id', 'city', 'date', 'score'))
# 添加一列
df['year'] = pd.DatetimeIndex(df['date']).year
table = df.pivot_table(columns='year', values='score', aggfunc=np.sum, index='city')
print(table)
修改Sheet名称
from openpyxl import load_workbook
wb = load_workbook(file_path)
ws = wb['工作表1']
ws.title = '表1'
wb.save(file_path)
wb.close()
// 修改所有sheet名称, 重新读取再保存
file_path = 'test.xlsx'
file = pd.ExcelFile(file_path)
writer = pd.ExcelWriter(file_path)
for name in file.sheet_names:
df = pd.read_excel(file_path, sheet_name=name)
df.to_excel(excel_writer=writer, sheet_name=name + '2', header=False, index=False)
writer.save()
writer.close()
from openpyxl import load_workbook
wb = load_workbook(file_path)
sheetnames = wb.sheetnames
for sheetname in sheetnames:
ws = wb[sheetname]
ws.title = sheetname + '1'
wb.save(file_path)
wb.close()
线性回归,数据预测
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import linregress
# pip install matplotlib
# pip install scipy
df = pd.DataFrame([
('2022-01-01', 20), ('2022-02-01', 30), ('2022-03-01', 50),
('2022-04-01', 40), ('2022-05-01', 60), ('2022-06-01', 80),
('2022-07-01', 90), ('2022-08-01', 80), ('2022-09-01', 130),
('2022-10-01', 120), ('2022-11-01', 150), ('2022-12-01', 110)],
columns=('month', 'amount'))
slope, intercept, r, p, std_err = linregress(df.index, df.amount)
exp = df.index * slope + intercept
# 预测值
print(slope * 35 + intercept)
plt.scatter(df.index, df.amount)
plt.plot(df.index, exp, color='orange')
plt.title(f'y={slope} * x + {intercept} ')
plt.xticks(df.index, df.month, rotation=90)
plt.tight_layout()
plt.show()
条件格式
import pandas as pd
# 需要在jupyer环境下运行 jupyter notebook
def lowcolor(x):
color = 'red' if x
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
SQLite Database SQLite is an embedded relational database engine. Its developers call it a self-contained, serverless, zero-config…