Pandas 的使用
典型的数据分析流程是采集、整理清洗、处理(分组、排序、计算),然后按照分析目的产出最终数据,最后进行可视化,得出结论。
一、Pandas 读取和导出
格式 | 文件格式 | 读取函数 | 写入(输出)函数 |
binary | Excel | read_excel | to_excel |
text | CSV | read_csv | read_table |
text | JSON | read_json | to_json |
text | 网页表格 | HTML | read_html |
text | 剪贴板 | read_clipboard | to_clipboard |
SQL | SQL | read_sql | to_sql |
text | Markdown | to_markdown |
1、CSV
pd.read_csv('data.csv') # 如果文件与代码文件在同目录下
pd.read_csv('https://www.gairuo.com/file/data/dataset/GDP-China.csv')
# 也可以从 StringIO 中读取
from io import StringIO
data = ('col1,col2,col3\n'
'a,b,1\n'
'a,b,2\n'
'c,d,3')
pd.read_csv(StringIO(data))
1)指定分隔符号
# 数据分隔转化是逗号, 如果是其他可以指定
pd.read_csv(data, sep='\t') # 制表符分隔 tab
pd.read_table(data) # read_table 默认是制表符分隔 tab
2)列、索引、名称
# 默认第一行是表头,可以指定,如果指定列名会被忽略
pd.read_csv(data, header=0)
pd.read_csv(data, header=None) # 没有表头
pd.read_csv(data, names=['列1', '列2']) # 指定列名列表
# 如没列名,自动指定一个: 前缀加序数
pd.read_csv(data, prefix='c_', header=None)
# 读取部分列
pd.read_csv(data, usecols=[0,4,3]) # 按索引只读取指定列,顺序无关
pd.read_csv(data, usecols=['列1', '列5']) # 按索引只读取指定列
# 指定列顺序,其实是 df 的筛选功能
pd.read_csv(data, usecols=['列1', '列5'])[['列5', '列1']]
pd.read_csv(data, index_col=0) # 第几列是索引
# 以下用 callable 方式可以巧妙指定顺序, in 后边的是我们要的顺序
pd.read_csv(data, usecols=lambda x: x.upper() in ['COL3', 'COL1'])
3)数据类型
data = 'https://www.gairuo.com/file/data/dataset/GDP-China.csv'
# 指定数据类型
pd.read_csv(data, dtype=np.float64) # 所有数据均为此数据类型
pd.read_csv(data, dtype={'c1':np.float64, 'c2': str}) # 指定字段的类型
# 解析日期时间
pd.read_csv(data, parse_dates=True) # 自动解析日期时间格式
pd.read_csv(data, parse_dates=['年份']) # 指定日期时间字段进行解析
# 将 1、4 列合并解析成名为 时间的 时间类型列
pd.read_csv(data, parse_dates={'时间':[1,4]})
# 指定时间解析库,默认是 dateutil.parser.parser
pd.read_csv(data, date_parser=pd.io.date_converters.parse_date_time)
date_parser=lambda x: pd.to_datetime(x, utc=True, format=...)
4)导出文件
df.to_csv('done.csv')
df.to_csv('done.csv', index=False) # 不要索引
# 导出二进制文件句柄(缓冲), 支持编码和压缩 pandas 1.2.0 增加
import io
buffer = io.BytesIO()
df.to_csv(buffer, encoding="utf-8", compression="gzip")
2、Excel 文件
read_excel() 方法可以使用 xlrd Python 模块读取 Excel 2003(.xls)文件。 可以使用 xlrd 或 openpyxl 读取Excel 2007+(.xlsx)文件。 可以使用 pyxlsb 读取二进制Excel(.xlsb)文件。 to_excel() 实例方法用于将DataFrame 保存到 Excel。
xlsx = pd.ExcelFile('data.xlsx')
df = pd.read_excel(xlsx, 'Sheet1') # 读取
xlsx.parse('sheet1') # 取指定标签为 DataFrame
# Excel 的所有标签
xlsx.sheet_names
# ['sheet1', 'sheet2', 'sheet3', 'sheet4']
1)文件读取
# Returns a DataFrame
pd.read_excel('team.xlsx') # 默认读取第一个标签页 Sheet
pd.read_excel('path_to_file.xls', sheet_name='Sheet1') # 指定 Sheet
# 从网址 url 读取
pd.read_excel('https://www.gairuo.com/file/data/dataset/team.xlsx')
# !!! 读取的功能基本与 read_csv 一样,可参考上文
# 不指定索引,不指定表头,使用自动行列索引
pd.read_excel('tmp.xlsx', index_col=None, header=None)
# 指定列的数据类型
pd.read_excel('tmp.xlsx', index_col=0,
dtype={'Name': str, 'Value': float})
2)多个 Sheet 的读取:
pd.read_excel('path_to_file.xls', sheet_name=['Sheet1', 'Sheet2'])
3)ExcelFile 对象:
# 使用 ExcelFile 保存文件对象
xlsx = pd.ExcelFile('path_to_file.xls')
df = pd.read_excel(xlsx, 'Sheet1')
# 可以把多个 Sheet 存入 ExcelFile
with pd.ExcelFile('path_to_file.xls') as xls:
df1 = pd.read_excel(xls, 'Sheet1')
df2 = pd.read_excel(xls, 'Sheet2')
df = pd.read_excel(xlsx)
常用的参数使用与 read_csv 相同。
4)导出 excel
df.to_excel('path_to_file.xlsx')
# 指定 sheet 名, 不要索引
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1', index=False)
# 指定索引名,不合并单元格
df.to_excel('path_to_file.xlsx', index_label='label', merge_cells=False)
# 将多个 df 分不同 sheet 导入到一个 excel
with pd.ExcelWriter('path_to_file.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sheet1')
df2.to_excel(writer, sheet_name='Sheet2')
# 指定操作引擎
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1', engine='xlsxwriter')
# By setting the 'engine' in the ExcelWriter constructor.
writer = pd.ExcelWriter('path_to_file.xlsx', engine='xlsxwriter')
df.to_excel(writer)
writer.save()
# 设置系统引擎
from pandas import options # noqa: E402
options.io.excel.xlsx.writer = 'xlsxwriter'
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1')
3、JSON 格式
Pandas 可以读取和生成 Json 字符串,Series 或 DataFrame 都可以被转换。JSON 格式在网络上非常通用,在写爬虫时可以使用极大提高效率,在做可视化时前端的 JS 库往往需要接受 Json 格式。
1)读取 JSON
pd.read_json('data.json')
json = '''{"columns":["col 1","col 2"],
"index":["row 1","row 2"],
"data":[["a","b"],["c","d"]]}
'''
pd.read_json(json)
pd.read_json(json, orient='split') # json 格式
'''
2)orient 支持:
- ‘split’ : dict like {index -> [index], columns -> [columns], data -> [values]}
- ‘records’ : list like [{column -> value}, … , {column -> value}]
- ‘index’ : dict like {index -> {column -> value}}
- ‘columns’ : dict like {column -> {index -> value}}
3)输出 JSON
Series 或 DataFrame 转换 JSON 的机制如下:
Series :
默认为 index
支持 {split, records, index}
DataFrame
默认为 columns
支持 {split, records, index, columns, values, table}
df = pd.DataFrame([['a', 'b'], ['c', 'd']],
index=['row 1', 'row 2'],
columns=['col 1', 'col 2'])
# 输出 json 字符串
df.to_json(orient='split')
3、HTML
read_html() 函数可以接受 HTML字符串 / html文件 / URL,并将HTML表解析为 DataFrame。返回的是一个 df 列表,可以通知索引取第几个。
仅解析网页内
标签里的数据。
dfs = pd.read_html('https://www.gairuo.com/p/pandas-io')
dfs[0] # 查看第一个 df
# 读取网页文件,第一行为表头
dfs = pd.read_html('data.html', header=0)
# 第一列为索引
dfs = pd.read_html(url, index_col=0)
# !!! 常用的功能与 read_csv 相同,可参考上文
如果一个网页表格很多,可以指定元素来取得:
# id='table' 的表格,注意这儿仍然可能返回多个
dfs1 = pd.read_html(url, attrs={'id': 'table'})
# dfs1[0]
# class='sortable'
dfs2 = pd.read_html(url, attrs={'class': 'sortable'})
常用的参数使用与 read_csv 相同。
输出 html
会输出 html 表格代码字符串。
print(df.to_html())
print(df.to_html(columns=[0])) # 输出指定列
print(df.to_html(bold_rows=False)) # 表头不加粗体
# 表格指定样式,支持多个
print(df.to_html(classes=['class1', 'class2']))
4、剪贴板 Clipboard
剪贴板(Clipboard)是操作系统级的一个暂存数据的地方,它存在内存中,可以在不同软件之间传递,非常方便。pandas 支持读取剪贴板中的结构化数据,这就意味着我们不用将数据保存成文件,直接从网页、文件中复制,然后中直接读取,非常方便。
读取剪贴板,它的参数使用与 read_csv 完全一样:
'''
A B C
x 1 4 p
y 2 5 q
z 3 6 r
'''
# 复制上边的数据,然后直接赋值
cdf = pd.read_clipboard()
保存到剪贴板:
# 执行完找个地方粘贴一下看看效果
df = pd.DataFrame({'A': [1, 2, 3],
'B': [4, 5, 6],
'C': ['p', 'q', 'r']},
index=['x', 'y', 'z'])
df.to_clipboard()
5、SQL
Pandas 支持连接数据库进行查询,有以下几个方法:
read_sql_table(table_name, con[, schema, …]), 把数据表里的数据转成 DataFrame
read_sql_query(sql, con[, index_col, …]), 用 sql 查询数据到 DataFrame
read_sql(sql, con[, index_col, …]), 同时支持上边两个功能
DataFrame.to_sql(self, name, con[, schema, …]),把记录数据写到数据库里
# 需要安装 sqlalchemy 库
from sqlalchemy import create_engine
# 创建数据库对象,sqlite 内存模式
engine = create_engine('sqlite:///:memory:')
# 把表名为 data 的表数据拿出来
with engine.connect() as conn, conn.begin():
data = pd.read_sql_table('data', conn)
# data
# 将数据写入
data.to_sql('data', engine)
# 大量写入
data.to_sql('data_chunked', engine, chunksize=1000)
# 使用 sql 查询
pd.read_sql_query('SELECT * FROM data', engine)
6、输出 Markdown
Markdown 是一种常用的技术文档编写语言,Pandas 支持输出 Markdown 格式字符串:
print(df.to_markdown())
'''
| | A | B | C |
|:---|----:|----:|:----|
| x | 1 | 4 | p |
| y | 2 | 5 | q |
| z | 3 | 6 | r |
'''
# 不需要索引
print(df.to_markdown(index=False))
# 填充空值
print(df.fillna('').to_markdown(index=False))
二、Pandas 索引 Indexing
Pandas 创建合理的具有业务意义的索引
1、建立索引
加载数据生成 DataFrame 时可以指定索引
data = 'https://www.gairuo.com/file/data/dataset/team.xlsx'
df = pd.read_excel(data, index_col='name') # 设置索引为 name
如果加载时没有指定索引,我们可以使用 df.set_index() 指定:
df.set_index('name') # 设置索引
df.set_index(['team', 'name']) # 设置多层索引
s = pd.Series(range(100))
# df.set_index(s) # 指定一个索引
# df.set_index([s, 'name']) # 指定的索引和现有字段同时指定
df.set_index([s, s**2]) # 计算索引
# 其他的参数
df.set_index('name', drop=False) # 保留原列
df.set_index('name', append=True) # 保留原来的索引
df.set_index('name', inplace=True) # 建立索引并重写覆盖 df
2、索引类型
数字索引 Numeric Index
RangeIndex: 单调整数范围的不可变索引。
Int64Index: int64类型,有序可切片集合的不可变ndarray。
UInt64Index: 无符号整数标签的
Float64Index: Float64 类型
pd.RangeIndex(1,100,2)
# RangeIndex(start=1, stop=100, step=2)
pd.Int64Index([1,2,3,-4], name='num')
# Int64Index([1, 2, 3, -4], dtype='int64', name='num')
pd.UInt64Index([1,2,3,4])
# UInt64Index([1, 2, 3, 4], dtype='uint64')
pd.Float64Index([1.2,2.3,3,4])
# Float64Index([1.2, 2.3, 3.0, 4.0], dtype='float64')
类别索引 CategoricalIndex
类别只能包含有限数量的(通常是固定的)可能值(类别)。 可以理解成枚举,比如性别只有男女,但在数据中每行都有,如果按文本处理会效率不高。类别的底层是 pandas.Categorical。
pd.CategoricalIndex(['a', 'b', 'a', 'b'])
# CategoricalIndex(['a', 'b', 'a', 'b'], categories=['a', 'b'], ordered=False, dtype='category')
只有在体量非常大的数据面前才能显示其优势。
间隔索引 IntervalIndex
pd.interval_range(start=0, end=5)
'''
IntervalIndex([(0, 1], (1, 2], (2, 3], (3, 4], (4, 5]],
closed='right',
dtype='interval[int64]')
'''
多层索引 MultiIndex
arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
'''
MultiIndex([(1, 'red'),
(1, 'blue'),
(2, 'red'),
(2, 'blue')],
names=['number', 'color'])
'''
时间索引 DatetimeIndex
# 从一个日期连续到另一个日期
pd.date_range(start='1/1/2021', end='1/08/2021')
# 指定开始时间和周期
pd.date_range(start='1/1/2021', periods=8)
# 以月为周期
pd.period_range(start='2021-01-01', end='2021-01-01', freq='M')
# 周期嵌套
pd.period_range(start=pd.Period('2021Q1', freq='Q'),
end=pd.Period('2021Q2', freq='Q'), freq='M')
时间差 TimedeltaIndex
pd.TimedeltaIndex(data =['06:05:01.000030', '+23:59:59.999999',
'22 day 2 min 3us 10ns', '+23:29:59.999999',
'+12:19:59.999999'])
# 使用 datetime
pd.TimedeltaIndex(['1 days', '1 days, 00:00:05',
np.timedelta64(2, 'D'),
datetime.timedelta(days=2, seconds=2)])
周期索引 PeriodIndex
t = pd.period_range('2020-5-1 10:00:05', periods=8, freq='S')
pd.PeriodIndex(t,freq='S')
3、索引对象
行和列的索引在 Pandas 里其实是一个 Index 对象,以下是创建一个 index 对象的方法:
创建对象
pd.Index([1, 2, 3])
# Int64Index([1, 2, 3], dtype='int64')
pd.Index(list('abc'))
# Index(['a', 'b', 'c'], dtype='object')
# 可以定义一相 name
pd.Index(['e', 'd', 'a', 'b'], name='something')
查看
df.index
# RangeIndex(start=0, stop=4, step=1)
df.columns
# Index(['month', 'year', 'sale'], dtype='object')
属性
以下方法也适用于 df.columns, 因为都是 index 对象:
# 属性
df.index.name # 名称
df.index.array # array 数组
df.index.dtype # 数据类型
df.index.shape # 形状
df.index.size # 元素数量
df.index.values # array 数组
# 其他,不常用
df.index.empty # 是否为空
df.index.is_unique # 是否不重复
df.index.names # 名称列表
df.index.is_all_dates # 是否全是日期时间
df.index.has_duplicates # 是否有重复值
df.index.values # 索引的值 array
操作
以下方法也适用于 df.columns, 因为都是 index 对象,有些也支持 Series:
# 方法
df.index.astype('int64') # 转换类型
df.index.isin() # 是否存在,见下方示例
df.index.rename('number') # 修改索引名称
df.index.nunique() # 不重复值的数量
df.index.sort_values(ascending=False,) # 排序,倒序
df.index.map(lambda x:x+'_') # map 函数处理
df.index.str.replace('_', '') # str 替换
df.index.str.split('_') # 分隔
df.index.to_list() # 转为列表
df.index.to_frame(index=False, name='a') # 转成 DataFrame
df.index.to_series() # 转 series
df.index.to_numpy() # 转为 numpy
df.index.unique() # 去重
df.index.value_counts() # 去重及数量
df.index.where(df.index=='a') # 筛选
df.index.rename('grade', inplace=False) # 重命名索引名称
df.index.rename(['species', 'year']) # 多层,重命名索引名称
df.index.max() # 最大值
df.index.argmax() # 最大索引值
df.index.any()
df.index.all()
df.index.T # 转置,多层索引里很有用
# 其他,不常用
df.index.append(pd.Index([4,5])) # 追加
df.index.repeat(2) # 重复几次
df.index.inferred_type # 推测数据类型
df.index.hasnans # 有没有空值
df.index.is_monotonic_decreasing # 是否单调递减
df.index.is_monotonic # 是否单调递增
df.index.is_monotonic_increasing # 是否单调递增
df.index.nbytes # 基础数据中的字节数
df.index.ndim # 维度数,维数
df.index.nlevels # 索引层级数,通常为 1
df.index.min() # 最小值
df.index.argmin() # 最小索引值
df.index.argsort() # 顺序值组成的数组
df.index.asof(2) # 返回最近的索引
# numpy dtype or pandas type
df.index.astype('int64', copy=True) # 深拷贝
# 拷贝
df.index.copy(name='new', deep=True, dtype='int64')
df.index.delete(1) # 删除指定位置
# 对比不同
df.index.difference(pd.Index([1,2,4]), sort=False)
df.index.drop('a', errors='ignore') # 删除
df.index.drop_duplicates(keep='first') # 去重值
df.index.droplevel(0) # 删除层级
df.index.dropna(how='all') # 删除空值
df.index.duplicated(keep='first') # 重复值在结果数组中为True
df.index.equals(df.index) # 与另外一个索引对象是否相同
df.index.factorize() # 分解成(array:0-n, Index)
df.index.fillna(0, {0:'nan'}) # 填充空值
# 字符列表, 把 name 值加在第一位, 每个值加10
df.index.format(name=True, formatter=lambda x:x+10)
# 返回一个 array, 指定值的索引位数组,不在的为 -1
df.index.get_indexer([2,9])
# 获取 指定层级 Index 对象
df.index.get_level_values(0)
# 指定索引的位置,见示例
df.index.get_loc('b')
df.index.insert(2, 'f') # 在索引位 2 插入 f
df.index.intersection(df.index) # 交集
df.index.is_(df.index) # 类似 is 检查
df.index.is_categorical() # 是否分类数据
df.index.is_type_compatible(df.index) # 类型是否兼容
df.index.is_type_compatible(1) # 类型是否兼容
df.index.isna() # array 是否为空
df.index.isnull() # array 是否缺失值
df.index.join(df.index, how='left') # 连接
df.index.notna() # 是否不存在的值
df.index.notnull() # 是否不存在的值
df.index.ravel() # 展平值的ndarray
df.index.reindex(['a','b']) # 新索引 (Index,array:0-n)
df.index.searchsorted('f') # 如果插入这个值排序后在哪个索引位
df.index.searchsorted([0, 4]) # array([0, 3]) 多个
df.index.set_names('quarter') # 设置索引名称
df.index.set_names('species', level=0)
df.index.set_names(['kind', 'year'], inplace=True)
df.index.shift(10, freq='D') # 日期索引向前移动 10 天
idx1.symmetric_difference(idx2) # 两个索引不同的内容
idx1.union(idx2) # 拼接
df.add_prefix('t_') # 表头加前缀
df.add_suffix('_d') # 表头加后缀
df.first_valid_index() # 第一个有值的索引
df.last_valid_index() # 最后一个有值的索引
4、重置索引
有时我们想取消已有的索引,以重新来过,可以使用 df.reset_index():
df.reset_index() # 清除索引
df.set_index('month').reset_index() # 相当于啥也没干
# 删除原索引,month 列没了
df.set_index('month').reset_index(drop=True)
df2.reset_index(inplace=True) # 覆盖使生效
# year 一级索引取消
df.set_index(['month', 'year']).reset_index(level=1)
df2.reset_index(level='class') # 同上使用层级索引名
df.reset_index(level='class', col_level=1) # 列索引
# 不存在层级名称的填入指定名称
df.reset_index(level='class', col_level=1, col_fill='species')
如果想修改索引内容可以用df.reindex([‘a’,‘b’]),还能用它做指定排序。
4、索引重命名
对行和列的索引名进行修改。
# 一一对应修改列索引
df.rename(columns={"A": "a", "B": "c"})
df.rename(str.lower, axis='columns')
# 修改行索引
df.rename(index={0: "x", 1: "y", 2: "z"})
df.rename({1: 2, 2: 4}, axis='index')
# 修改数据类型
df.rename(index=str)
# 重新修改索引
replacements = {l1:l2 for l1, l2 in zip(list1, list2)}
df.rename(replacements)
# 列名加前缀
df.rename(lambda x:'t_' + x, axis=1)
# 利用 iter() 函数的 next 特性修改
df.rename(lambda x, y=iter('abcdef'): next(y), axis=1)
# 修改列名,用解包形式生成新旧字段字典
df.rename(columns=dict(zip(df, list('abcd'))))
df.set_axis 可以将所需的索引分配给给定的轴。可以通过分配类似列表或索引的方式来更改列标签或行标签的索引。
# 修改索引
df.set_axis(['a', 'b', 'c'], axis='index')
# 修改列名
df.set_axis(list('abcd'), axis=1)
# 使修改生效
df.set_axis(['a', 'b'], axis='columns', inplace=True)
# 传入索引内容
df.set_axis(pd.Index(list('abcde')), axis=0)
5、索引名重命名
注意,这是修改索引的名称,不是索引或者列名本身:
s.rename_axis("animal") # 索引重命名
df.rename_axis(["dow", "hr"]) # 多层索引索引名修改
df.rename_axis('info', axis="columns") # 修改行索引名
# 修改多层列索引名
df.rename_axis(index={'a': 'A', 'b': 'B'})
# 修改多层列行索引名
df.rename_axis(columns={'name': 's_name', 'b': 'B'})
df.rename_axis(columns=str.upper) # 行索引名变大写
6、部分示例
# idx.isin() 是否存在
idx = pd.Index([1,2,3])
df.index.isin(idx)
# array([False, False, False, False])
df.index.isin(['a','b'])
# array([ True, True, False, False])
midx = pd.MultiIndex.from_arrays([[1,2,3],
['red', 'blue', 'green']],
names=('number', 'color'))
midx.isin([(1, 'red'), (3, 'red')])
# array([ True, False, False])
dates = ['2000-03-11', '2000-03-12', '2000-03-13']
dti = pd.to_datetime(dates)
dti.isin(['2000-03-11'])
# array([ True, False, False])
# i.argsort() 排序
# 将对索引进行排序的整数索引,见下文示例
idx = pd.Index(['b', 'a', 'd', 'c'])
order = idx.argsort() # array([1, 0, 3, 2])
idx[order] # Index(['a', 'b', 'c', 'd'], dtype='object')
# i.asof(2) 返回最近的索引, 支持日期,可实现找最近日期
# 从索引中返回标签;如果不存在,则返回前一个标签
idx2 = pd.Index([1,3,6])
idx2.asof(5) # 3
idx2.asof(6) # 5
idx2.asof(-1) # nan
# index.get_loc 指定索引的位置,见示例
unique_index = pd.Index(list('abc'))
unique_index.get_loc('b') # 1
monotonic_index = pd.Index(list('abbc'))
monotonic_index.get_loc('b') # slice(1, 3, None)
non_monotonic_index = pd.Index(list('abcb'))
non_monotonic_index.get_loc('b')
# array([False, True, False, True], dtype=bool)
更多的操作可以看官方文档。
7、重复索引
注:Pandas 版本要求 1.2.0+,这是一项实验功能
Pandas 默认地行列索引对象不需要唯一,可以有重复的行或列标签。但有时候比如通过 SQL 将数据存入数据库,就不能有重复的索引和列名,我们可以通过设置来限制重复索引:
df = pd.DataFrame({"A": [1, 2]}, index=['a', 'a'])
# 默认是允许重复的
df.flags["allows_duplicate_labels"] # True
df.flags.allows_duplicate_labels # True
df.flags
# <Flags(allows_duplicate_labels=True)>
# 已重复的就不能再设置为不重复的了
df.flags.allows_duplicate_labels = False
# DuplicateLabelError: Index has duplicates. positions....
# 生成时设置为标签为不可重复,后继操作就不能有重复的索引了
s = (pd.Series([1, 2], index=['a', 'b'])
.set_flags(allows_duplicate_labels=False)
)
s.reindex(['a', 'a'])
# DuplicateLabelError: Index has duplicates...
三、Pandas 数据的信息
加载完数据后,我们需要需要对数据的全貌有所了解,比如有多少行,多少列,有哪些字段,索引是什么等等。
查看样本
df = pd.read_excel(‘https://www.gairuo.com/file/data/dataset/team.xlsx’)
s = df.Q1 # 取其中一列,形成 Series
df.head() # 查看前五条数据
‘’’
name team Q1 Q2 Q3 Q4
0 Liver E 89 21 24 64
1 Arry C 36 37 37 57
2 Ack A 57 60 18 84
3 Eorge C 93 96 71 78
4 Oah D 65 49 61 86
‘’’
其他:
df.head(10) # 查看前10条数据
df.tail() # 查看后五条数据
df.tail(10) # 查看后10条数据
df.sample() # 随机查看一条数据
df.sample(3) # 随机查看3条数据
形状 df.shape
df.shape() 会返回一个数组,第一个代表行数,第二个代表列数,这就是这个数据的基本形状,也是数据的大小。
df.shape
(100, 6)
共 100 行,6列 (索引不算)
Series 只有一个值
s.shape
(100,)
基本信息 df.info()
df.info() 显示有数据类型、索引情况、行列数、各字段数据类型、内存占用等。Series 不支持。
df.info()
‘’’
<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 100 entries, 0 to 99
Data columns (total 6 columns):
Column Non-Null Count Dtype
0 name 100 non-null object
1 team 100 non-null object
2 Q1 100 non-null int64
3 Q2 100 non-null int64
4 Q3 100 non-null int64
5 Q4 100 non-null int64
dtypes: int64(4), object(2)
memory usage: 4.8+ KB
‘’’
数据类型 df.dtypes
会返回每个字段的数据类型。
df.dtypes
‘’’
name object
team object
Q1 int64
Q2 int64
Q3 int64
Q4 int64
dtype: object
‘’’
如果是 Series 需要用 s.dtype
s.dtype
dtype(‘int64’)
行列索引内容 df.axes
会返回一个列内容和行内容组成的列表 [列索引, 行索引]。
df.axes
‘’’
[RangeIndex(start=0, stop=100, step=1),
Index([‘name’, ‘team’, ‘Q1’, ‘Q2’, ‘Q3’, ‘Q4’], dtype=‘object’)]
‘’’
Series 只显示列索引,就是它的索引:
s.axes
[RangeIndex(start=0, stop=100, step=1)]
其他信息
注:以下信息操作,DataFrame 和 Series 一般都支持。
索引对象
df.index
RangeIndex(start=0, stop=100, step=1)
列索引,Series 不支持
df.columns
Index([‘name’, ‘team’, ‘Q1’, ‘Q2’, ‘Q3’, ‘Q4’], dtype=‘object’)
df.values # 建议使用 to_numpy()
df.to_numpy() # numpy array(<所有值的列表矩阵>)
df.ndim # 2 维度数
df.size # 600 行x列的总数,就是总共有多少数据
是否为空,注意有空值不认为是空
df.empty # False
Series 的索引, DataFrame 的列名
dfs.keys()
返回第一个非NA/空值的索引
df.first_valid_index() # 0
返回最后一个非NA/空值的索引
df.last_valid_index() # 99
数据的标记信息(目前只支持是否重复标签)pd 1.2.0+
df.flags
设置元信息,可用于数据基础信息描述
df.attrs={‘info’: ‘学生成绩表’}
查看元信息
df.attrs # {‘info’: ‘学生成绩表’}
标签是否允许重复
df.flags[“allows_duplicate_labels”]
df.flags.allows_duplicate_labels # True
df.set_flags(allows_duplicate_labels=False) # 设置
此外 Series 独有的如下:
s.name # ‘Q1’
s.array # 值组成的数组
s.dtype # 类型,dtype(‘int64’)
s.hasnans # False 是否有空
.name 可获取索引的名称,需要区分的是上例数据中 df.name 也能正常执行,它其实是 df 调用数据字段的方法,因为正好有名为 name 的列,如果没有就会报错,DataFrame 是没有此属性的。
四、Pandas 数学统计
Pandas 可以对 Series 与 DataFrame 进行快速的描述性统计,如求和、平均数、最大值、方差等,是最基础也是最实用的统计方法。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
数据总结 df.describe()
会返回一个有多个行的所有数字列的统计表,每个行是一个统计指标,有总数、平均数、标准差、最大最小值、四分位数等,对我们初步了解数据还是很有作用。
df.describe()
‘’’
Q1 Q2 Q3 Q4
count 100.000000 100.000000 100.000000 100.000000
mean 49.200000 52.550000 52.670000 52.780000
std 29.962603 29.845181 26.543677 27.818524
min 1.000000 1.000000 1.000000 2.000000
25% 19.500000 26.750000 29.500000 29.500000
50% 51.500000 49.500000 55.000000 53.000000
75% 74.250000 77.750000 76.250000 75.250000
max 98.000000 99.000000 99.000000 99.000000
‘’’
如果无数字:
pd.Series([‘a’, ‘b’, ‘c’, ‘c’]).describe()
‘’’
count 4
unique 3
top c
freq 2
dtype: object
‘’’
如果是一个时间类型则会按时间相关的如开始结束时间、周期等信息。
s2 = pd.Series([
np.datetime64(“2000-01-01”),
np.datetime64(“2010-01-01”),
np.datetime64(“2010-02-01”)
])
s2.describe()
‘’’
count 3
unique 3
top 2000-01-01 00:00:00
freq 1
first 2000-01-01 00:00:00
last 2010-02-01 00:00:00
dtype: object
‘’’
1.1 的用法
(pd.Series(pd.date_range(‘2000-01-01’, ‘2000-05-01’))
.describe(datetime_is_numeric=True)
)
还可以自己指定分位数(一般情况下,默认值包含中位数)等:
df.describe(percentiles=[.05, .25, .75, .95])
df.describe(include=[np.object, np.number]) # 指定类型
df.describe(exclude =[np.object]) # 排除类型
数学统计
数学计算是最常见的统计方法,比如我们要知道列的平均数据:
df.mean()
‘’’
Q1 49.20
Q2 52.55
Q3 52.67
Q4 52.78
dtype: float64
‘’’
看每行
df.mean(1).head()
‘’’
0 49.50
1 41.75
2 54.75
3 84.50
4 65.25
dtype: float64
‘’’
Q1 列的平均值
df.Q1.mean()
49.2
一般 DataFrame 计算后为一个 Series,Series 计算后为一个定值。
统计函数
Pandas 内置很多数学计算方法:
df.mean() # 返回所有列的均值
df.mean(1) # 返回所有行的均值,下同
df.corr() # 返回列与列之间的相关系数
df.count() # 返回每一列中的非空值的个数
df.max() # 返回每一列的最大值
df.min() # 返回每一列的最小值
df.abs() # 绝对值
df.median() # 返回每一列的中位数
df.std() # 返回每一列的标准差, 贝塞尔校正的样本标准偏差
df.var() # 无偏方差
df.sem() # 平均值的标准误差
df.mode() # 众数
df.prod() # 连乘
df.mad() # 平均绝对偏差
df.cumprod() # 累积连乘,累乘
df.cumsum(axis=0) # 累积连加,累加
df.nunique() # 去重数量,不同值的量
df.idxmax() # 每列最大的值的索引名
df.idxmin() # 最小
df.cummax() # 累积最大值
df.cummin() # 累积最小值
df.skew() # 样本偏度 (第三阶)
df.kurt() # 样本峰度 (第四阶)
df.quantile() # 样本分位数 (不同 % 的值)
一些特殊的说明:
很多支持指定行列(默认是 axis=0 列)等参数
df.mean(1) # 按行计算
很多支持
df.sum(0, skipna=False) # 否要排除缺失数据
很多支持
df.sum(level=‘blooded’) # 索引级别
df.sum(level=0)
如果有空值总共算几
df.sum(min_count=1)
可自定义相关性函数
def histogram_intersection(a, b):
v = np.minimum(a, b).sum().round(decimals=1)
return v
df = pd.DataFrame([(.2, .3), (.0, .6), (.6, .0), (.2, .1)],
columns=[‘dogs’, ‘cats’])
df.corr(method=histogram_intersection)
这些函数都是我们今后用于统计计算的基础。
五、Pandas 加工计算
除了简单的数学统计外,我们往往对数据还需要做非统计性计算,如去重、格式化等等,接下来我们将介绍一些数据的加工处理方法。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
位置差值 df.diff()
df.diff() 可以做位移差操作,经常用在一个序列性数据中上一个数据和下一个数据之前的差值,如增量研究。
本行与前一行的差值(即当前值比上一行增加了多少)
无前一行的本行值为 NaN
df.diff()
df.diff(axis=1) # 向右一列
df.diff(2)
df.diff(-1) # 新的本行为本行减去后一行
df.shift() 可以对数据进行移位,不做任何计算,移动后目标位置的类型无法接收收的为 NaN。
整体下移一行,最顶的一行为 NaN
df.shift()
df.shift(3) # 移三行
整体上移一行,最底的一行为 NaN
df.Q1.head().shift(-1)
向右移动一位
df.shift(axis=1)
df.shift(3, axis=1) # 移三位
向左移动一位
df.shift(-1, axis=1)
实现了 df.Q1.diff()
df.Q1 - df.Q1.shift()
生成序号 df.rank()
df.rank() 可以生成数据的排序值,典例的例子如学生的成绩表,给出排名。
排名, 将值变了序号数
df.rank()
df.rank(axis=1) # 横向排名
相同值的排名处理:
method=‘average’ 并列第1 计算(1+2)/2=都是1.5,下个是3
method=‘max’:并列第1,显示2,下个 3
method=‘min’:并列第1,显示1,下个3
method=‘dense’:并列第1,显示1,下个 2
method=‘first’:按索引顺序看谁在索引前
df.Q1.rank(method=‘max’)
df.rank(na_option=‘bottom’) # 把空值放在最后
df.rank(pct=True) # 以百分比形式返回
常用函数
df.all() # 返回所有列all()值的Series
df.any()
用表达式计算生成列。仅支持列,不是太安全
df.eval(‘Q2Q3 = Q2 + Q3’)
df.eval(‘Q2Q3 = Q2 + Q3’, inplace=True) # 替换生效
四舍五入
df.round(2) # 指定字段指定保留小数位,如有
df.round({‘Q1’: 2, ‘Q2’: 0})
df.round(-1) # 保留10位
每个列的去重值的数量
df.nunique()
s.nunique() # 本列的去重值
真假检测
df.isna() # 值的真假值替换
df.notna() # 与上相反
对 df 整体所有元素做加减乘除等计算:
df + 1 # 等运算
df.add() # 加
df.sub() # 减
df.mul() # 乘
df.div() # 除
df.divmod() # 返回 (a // b, a % b)
df.truediv() # Divide DataFrames (float division).
df.floordiv() # Divide DataFrames (integer division).
df.mod() # 模,除后的余数
df.pow() # 指数幂
df.dot(df2) # 矩阵运算
Series 专门函数
不重复的值及数量
s.value_counts()
s.value_counts(normalize=True) # 重复值的频率
s.value_counts(normalize=True)*100 # 当前值在序列中的百分比
s.value_counts(sort=False) # 不按频率排序
s.unique() # 去重的值 array
s.is_unique # 是否有重复
最大最小值
s.nlargest() # 最大的前5个
s.nlargest(15) # 最大的前15个
s.nsmallest() # 最小的前5个
s.nsmallest(15) # 最小的前15个
s.pct_change() # 计算与前一行的变化百分比
s.pct_change(periods=2) # 前两行
s1.cov(s2) # 两个序列的协方差
六、Pandas 查询筛选数据
数据有选择是 Pandas 最基础的使用,我们通过各种条件的组合可以模拟 Excel 的筛选操作。Pandas 也能实现类似列表的切片的操作。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
数据检查
我们一拿到数据需要对数据有一个抽查,一方面是了解数据结构,另一方面随机检查一下数据的质量问题。常用的:
语法 操作 返回结果
df.head(n) 查看 DataFrame 对象的前n行 DataFrame
df.tail(n) 查看 DataFrame 对象的最后n行 DataFrame
df.sample(n) 查看 n 个样本,随机 DataFrame
以上都是选择整行。
查看头部 df.head()
每次加载数据后一般需要看一下头部数据
df.head()
‘’’
name team Q1 Q2 Q3 Q4
0 Liver E 89 21 24 64
1 Arry C 36 37 37 57
2 Ack A 57 60 18 84
3 Eorge C 93 96 71 78
4 Oah D 65 49 61 86
‘’’
可指定数量
df.head(15)
查看尾部 df.tail()
查看最后的尾部数据。
df.head()
‘’’
name team Q1 Q2 Q3 Q4
95 Gabriel C 48 59 87 74
96 Austin7 C 21 31 30 43
97 Lincoln4 C 98 93 1 20
98 Eli E 11 74 58 91
99 Ben E 21 43 41 74
‘’’
可指定数量
df.tail(15)
查看样本 df.sample()
df.sample() 会随机返回一条样本数据。
df.sample()
‘’’
name team Q1 Q2 Q3 Q4
79 Tyler A 75 16 44 63
‘’’
可指定数量
df.sample(15)
数据截取:
去掉索引之前和之后的数据
df.truncate(before=2, after=4) # 只要索引 2-4
s.truncate(before=“60”, after=“66”)
df.truncate(before=“A”, after=“B”, axis=“columns”) # 选取列
操作列
以下两种方法都可以代表一列:
df[‘name’] # 会返回本列的 Series
df.name
df.Q1
df.1Q 即使列名叫 1Q 也无法使用
df.my name 有空格也无法调用,可以处理加上下划线
注意,当列名为一个合法的 python 变量时可以直接作为属性去使用。
选择部分行列
有时我们需要按条件选择部分列、部分行,一般常用的有:
操作 语法 返回结果
选择列 df[col] Series
按索引选择行 df.loc[label] Series
按数字索引选择行 df.iloc[loc] Series
使用切片选择行 df[5:10] DataFrame
用表达式筛选行 df[bool_vec] DataFrame
以上操作称为 Fancy Indexing(花式索引),它来自 Numpy,是指传递一个索引序列,然后一次性得到多个索引元素。Fancy Indexing 和 slicing 不同,它通常将元素拷贝到新的数据对象中。索引中可以有切片 slice,或者省略 ellipsis、新轴 newaxis、布尔数组或者整数数组索引等,可以看做是一个多维切片。
接下来我们将重点介绍一下这些查询的方法。
切片 []
我们可以像列表那样利用切片功能选择部分行的数据,但是不支持索引一条:
df[:2] # 前两行数据
df[4:10]
df[:] # 所有数据,一般没这么用的
df[:10:2] # 按步长取
s[::-1] # 反转顺序
也可以选择列:
df[‘name’] # 只要一列,Series
df[[‘Q1’, ‘Q2’]] # 选择两列
df[[‘name’]] # 选择一列,返回 DataFrame,注意和上例区别
按标签 .loc
df.loc() 的格式为 df.loc[<索引表达式>, <列表达式>],表达式支持以下形式:
单个标签:
代表索引,如果是字符需要加引号
df.loc[0] # 选择索引为 0 的行
df.loc[8]
单个列表标签:
df.loc[[0,5,10]] # 指定索引 0,5,10 的行
df.loc[[‘Eli’, ‘Ben’]] # 如果索引是 name
真假选择,长度要和索引一样
df.loc[[False, True]*50] # 为真的列显示,隔一个显示一个
带标签的切片,包括起始和停止start:stop, 可以其中只有一个,返回包括它们的数据:
df.loc[0:5] # 索引切片, 代表0-5行,包括5
df.loc[‘2010’:‘2014’] # 如果索引是时间可以用字符查询
df.loc[:] # 所有
本方法支持 Series
进行切片操作,索引必须经过排序,意味着索引单调递增或者单调递减,以下代码中其中一个为 True,否则会引发 KeyError 错误。
索引单调性
(
df.index.is_monotonic_increasing,
df.index.is_monotonic_decreasing
)
(True, False)
通过上边的规则可以先对索引排序再执行词义上的查询,如:
姓名开头从 Ad 到 Bo 的
df.set_index(‘name’).sort_index().loc[‘Ad’:‘Bo’]
姓名开头从开始到 Bo 的
df.set_index(‘name’).sort_index().loc[:‘Bo’]
团队名称从 C 到 D 的
df.set_index(‘team’).sort_index().loc[‘C’: ‘D’]
姓名开头从 Te 到 X 的
df.sort_values(‘name’).set_index(‘name’).loc[‘Te’: ‘X’]
列筛选,必须有行元素:
dft.loc[:, [‘Q1’, ‘Q2’]] # 所有行,Q1 和 Q2两列
dft.loc[:, [‘Q1’, ‘Q2’]] # 所有行,Q1 和 Q2两列
dft.loc[:10, ‘Q1’:] # 0-10 行,Q1后边的所有列
按位置 .iloc
df.iloc 与 df.loc 相似,但只能用自然索引(行和列的 0 - n 索引),不能用标签。
df.iloc[:3]
df.iloc[:]
df.iloc[:, [1, 2]]
df.iloc[2:20:3]
s.iloc[:3]
如果想筛选多个不连续的行列数据(使用 np.r_),可以使用以下方法:
筛选索引0-4&10&5-29每两行取一个&70-74
df.iloc[np.r_[:5, 10, 15:30:2, 70:75]] # 行
df.iloc[:, np.r_[0, 2:6]] # 列,0列和第2-5列
也可以使用追加的方式拼接
df.loc[:5].append(df.loc[10]).append(df.loc[15:30:2])
取具体值 .at
类似于 loc, 但仅取一个具体的值,结构为 at[<索引>,<列名>]:
注:索引是字符需要加引号
df.at[4, ‘Q1’] # 65
df.at[‘lily’, ‘Q1’] # 65 假定索引是 name
df.at[0, ‘name’] # ‘Liver’
df.loc[0].at[‘name’] # ‘Liver’
指定列的值对应其他列的值
df.set_index(‘name’).at[‘Eorge’, ‘team’] # ‘C’
df.set_index(‘name’).team.at[‘Eorge’] # ‘C’
指定列的对应索引的值
df.team.at[3] # ‘C’
同样 iat 和 iloc 一样,仅支持数字索引:
df.iat[4, 2] # 65
df.loc[0].iat[1] # ‘E’
.get 可以做类似字典的操作,如果无值给返回默认值(例中是0):
df.get(‘name’, 0) # 是 name 列
df.get(‘nameXXX’, 0) # 0, 返回默认值
s.get(3, 0) # 93, Series 传索引返回具体值
df.name.get(99, 0) # ‘Ben’
表达式筛选
[] 切片里可以使用表达式进行筛选:
df[df[‘Q1’] == 8] # Q1 等于8
df[~(df[‘Q1’] == 8)] # 不等于8
df[df.name == ‘Ben’] # 姓名为Ben
df.loc[df[‘Q1’] > 90, ‘Q1’:] # Q1 大于90,显示Q1后边的所有列
df.loc[(df.Q1 > 80) & (df.Q2 < 15)] # and 关系
df.loc[(df.Q1 > 90) | (df.Q2 < 90)] # or 关系
df[df.Q1 > df.Q2]
df.loc 里的索引部分可以使用表达式进行数据筛选。
df.loc[df[‘Q1’] == 8] # 等于8
df.loc[df.Q1 == 8] # 等于8
df.loc[df[‘Q1’] > 90, ‘Q1’:] # Q1 大于90,只显示 Q1
其他表达式与切片一致
通过列位置筛选列
df.loc[:, lambda df: df.columns.str.len()==4] # 真假组成的序列
df.loc[:, lambda df: [i for i in df.columns if ‘Q’ in i]] # 列名列表
df.iloc[:3, lambda df: df.columns.str.len()==2] # 真假组成的序列
逻辑判断和函数:
df.eq() # 等于相等 ==
df.ne() # 不等于 !=
df.le() # 小于等于 >=
df.lt() # 小于 <
df.ge() # 大于等于 >=
df.gt() # 大于 >
都支持 axis{0 or ‘index’, 1 or ‘columns’}, default ‘columns’
df[df.Q1.ne(89)] # Q1 不等于8
df.loc[df.Q1.gt(90) & df.Q2.lt(90)] # and 关系 Q1>90 Q2<90
其他函数:
isin
df[df.team.isin([‘A’,‘B’])] # 包含 AB 两组的
df[df.isin({‘team’: [‘C’, ‘D’], ‘Q1’:[36,93]})] # 复杂查询,其他值为 NaN
函数筛选
函数生成具体的标签值或者同长度对应布尔索引,作用于筛选:
df[lambda df: df[‘Q1’] == 8] # Q1为8的
df.loc[lambda df: df.Q1 == 8, ‘Q1’:‘Q2’] # Q1为8的, 显示 Q1 Q2
选择字段时尽量使用字典法,属性法在条件表达式时一些情况可能有 bug
函数不仅能应用在行位上,也能应用在列位上。
where 和 mask
s.where(s > 90) # 不符合条件的为 NaN
s.where(s > 90, 0) # 不符合条件的为 0
np.where, 大于80是真否则是假
np.where(s>80, True, False)
np.where(df.num>=60, ‘合格’, ‘不合格’)
s.mask(s > 90) # 符合条件的为 NaN
s.mask(s > 90, 0) # 符合条件的为 0
例:能被整除的显示,不能的显示相反数
m = df.loc[:,‘Q1’:‘Q4’] % 3 == 0
df.loc[:,‘Q1’:‘Q4’].where(m, -df.loc[:,‘Q1’:‘Q4’])
行列相同数量,返回一个 array
df.lookup([1,3,4], [‘Q1’,‘Q2’,‘Q3’]) # array([36, 96, 61])
df.lookup([1], [‘Q1’]) # array([36])
mask 和 where 还可以通过数据筛选返回布尔序列:
返回布尔序列,符合条件的行为 True
(df.where((df.team==‘A’) & (df.Q1>60)) == df).Q1
返回布尔序列,符合条件的行为 False
(df.mask((df.team==‘A’) & (df.Q1>60)) == df).Q1
query
df.query(‘Q1 > Q2 > 90’) # 直接写类型 sql where 语句
df.query(‘Q1 + Q2 > 180’)
df.query(‘Q1 == Q2’)
df.query(’(Q1<50) & (Q2>40) and (Q3>90)’)
df.query(‘Q1 > Q2 > Q3 > Q4’)
df.query(‘team != “C”’)
df.query(‘team not in (“E”,“A”,“B”)’)
对于名称中带有空格的列,可以使用反引号引起来
df.query('B == team name
')
支持传入变量,如:大于平均分40分的
a = df.Q1.mean()
df.query(‘Q1 > @a+40’)
df.query(‘Q1 > Q2
+@a’)
df.eval() 用法与 df.query 类似
df[df.eval(“Q1 > 90 > Q3 > 10”)]
df[df.eval(“Q1 > Q2
+@a”)]
filter
使用 filter 可以对行名和列名进行筛选。
df.filter(items=[‘Q1’, ‘Q2’]) # 选择两列
df.filter(regex=‘Q’, axis=1) # 列名包含Q的
df.filter(regex=‘eKaTeX parse error: Expected 'EOF', got '#' at position 12: ', axis=1) #̲ 以 e 结尾的 df.fil…’, axis=0) # 正则, 索引名包含1的
df.filter(like=‘2’, axis=0) # 索引中有2的
索引中2开头列名有Q的
df.filter(regex=’^2’, axis=0).filter(like=‘Q’, axis=1)
索引选择器 pd.IndexSlice
pd.IndexSlice 的使用方法类似于df.loc[] 切片中的方法,常用在多层索引中,以及需要指定应用范围(subset 参数)的函数中,特别是在链式方法中。
df.loc[pd.IndexSlice[:, [‘Q1’, ‘Q2’]]]
变量化使用
idx = pd.IndexSlice
df.loc[idx[:, [‘Q1’, ‘Q2’]]]
df.loc[idx[:, ‘Q1’:‘Q4’], :] # 多索引
复杂的选择:
创建复杂条件选择器
selected = df.loc[(df.team==‘A’) & (df.Q1>90)]
idxs = pd.IndexSlice[selected.index, ‘name’]
应用选择器
df.loc[idxs]
选择这部分区域加样式(样式功能见教程后文介绍)
df.style.applymap(style_fun, subset=idxs)
按数据类型
可以只选择或者排除指定类型数据:
df.select_dtypes(include=[‘float64’]) # 选择 float64 型数据
df.select_dtypes(include=‘bool’)
df.select_dtypes(include=[‘number’]) # 只取数字型
df.select_dtypes(exclude=[‘int’]) # 排除 int 类型
df.select_dtypes(exclude=[‘datetime64’])
any 和 all
any 方法如果至少有一个值为 True 是便为 True,all 需要所有值为 True 才为 True。它们可以传入 axis 为 1,会按行检测。
Q1 Q2 成绩全为 80 分的
df[(df.loc[:,[‘Q1’,‘Q2’]] > 80).all(1)]
Q1 Q2 成绩至少有一个 80 分的
df[(df.loc[:,[‘Q1’,‘Q2’]] > 80).any(1)]
理解筛选原理
df[<表达式>] 里边的表达式如果单独拿出来,可以看到:
df.Q1.gt(90)
‘’’
0 False
1 False
2 False
3 True
4 False
…
Name: Q1, Length: 100, dtype: bool
‘’’
会有一个由真假值组成的数据,筛选后的结果就是为 True 的内容。
七、Pandas 数据类型转换
数据分析前我们就需要对数据分配好适合的类型,这才能理工高效地处理数据,不用的数据类型可以用不同的处理方法。注意,一个列只能有一个总数据类型,但具体值可以是不同的数据类型。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
数据初始化时指定
df = pd.DataFrame(data, dtype=‘float32’) # 对所的字段指定类型
每个字段分别指定
df = pd.read_excel(data, dtype={‘team’: ‘string’, ‘Q1’: ‘int32’})
自动推定类型
Pandas 可以用以下方法智能地推定各列的数据类型,以下方法不妨一试:
自动转换合适的数据类型
df.convert_dtypes() # 推荐!新的方法,支持 string 类型
df.infer_objects()
按大体类型推定
m = [‘1’, 2, 3]
s = pd.to_numeric(s) # 转成数字
pd.to_datetime(m) # 转成时间
pd.to_timedelta(m) # 转成时差
pd.to_datetime(m, errors=‘coerce’) # 错误处理
pd.to_numeric(m, errors=‘ignore’)
pd.to_numeric(m errors=‘coerce’).fillna(0) # 兜底填充
pd.to_datetime(df[[‘year’, ‘month’, ‘day’]]) # 组合成日期
最低期望
pd.to_numeric(m, downcast=‘integer’) # smallest signed int dtype
array([1, 2, 3], dtype=int8)
pd.to_numeric(m, downcast=‘signed’) # same as ‘integer’
array([1, 2, 3], dtype=int8)
pd.to_numeric(m, downcast=‘unsigned’) # smallest unsigned int dtype
array([1, 2, 3], dtype=uint8)
pd.to_numeric(m, downcast=‘float’) # smallest float dtype
array([1., 2., 3.], dtype=float32)
应用函数
df.apply(pd.to_timedelta)
类型转换 astype()
这也是最常见的数据类型转换方式,各数据类型的介绍可参阅:
df.dtypes # 查看数据类型
df.index.astype(‘int64’) # 索引类型转换
df.astype(‘int32’) # 所有数据转换为 int32
df.astype({‘col1’: ‘int32’}) # 指定字段转指定类型
s.astype(‘int64’)
s.astype(‘int64’, copy=False) # 不与原数据关联
s.astype(np.uint8)
df[‘name’].astype(‘object’)
data[‘Q4’].astype(‘float’)
s.astype(‘datetime64[ns]’)
data[‘状态’].astype(‘bool’)
索引类型修改
df.rename() 可以用在链式方法中修改索引的数据类型
df.rename(int)
df.rename(str)
df.rename(str, axis=1) # 修改行
s.rename(int)
其他方法
df.index.astype(str)
df.columns.astype(str)
转换为时间
pd.to_datetime() 和 s.astype(‘datetime64[ns]’) 是最简单的时间转换方法。
可参考教程关于时间的专门介绍。
常用案例
将 89.3% 这样的文本转为浮点数字
data.rate.apply(lambda x: x.replace(’%’, ‘’)).astype(‘float’) / 100
八、Pandas 数据排序
排序是数据分析的一种手段,Pandas 支持三种排序方式:按索引标签排序,按列值排序以及两者结合进行排序。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
索引排序
sort_index() 可将索引重新排序,意味着每行数据的位置跟着索引而变化。
s.sort_index() # 升序排列
df.sort_index() # df 也是按索引进行排序
df.team.sort_index()
s.sort_index(ascending=False) # 降序排列
s.sort_index(inplace=True) # 排序后生效,改变原数据
索引重新0-(n-1) 排, 很有用,可以得到它的排序号
s.sort_index(ignore_index=True)
s.sort_index(na_position=‘first’) # 空值在前,另 ‘last’
s.sort_index(level=1) # 如果多层,排一级
s.sort_index(level=1, sort_remaining=False) # 这层不排
行索引排序,表头排序
df.sort_index(axis=1) # 会把列按列名顺序排列
df.reindex()指定自己定义顺序的索引,实现行和列的顺序重新定义:
df = pd.DataFrame({
‘A’: [1,2,4],
‘B’: [3,5,6]
}, index=[‘a’, ‘b’, ‘c’]
)
df
‘’’
A B
a 1 3
b 2 5
c 4 6
‘’’
按要求重新指定索引顺序
df.reindex([‘c’, ‘b’, ‘a’])
‘’’
A B
c 4 6
b 2 5
a 1 3
‘’’
指定列顺序
df.reindex([‘B’, ‘A’], axis=1)
‘’’
B A
a 3 1
b 5 2
c 6 4
‘’’
数据值排序
数据值的排序主要使用 sort_values(),数值按大小顺序,字符按字母顺序。
s.sort_values() # 升序
s.sort_values(ascending=False) # 降序
s.sort_values(inplace=True) # 修改生效
s.sort_values(na_position=‘first’) # 空值在前
df 按指定字段顺序
df.sort_values(by=[‘team’])
df.sort_values(‘Q1’)
按多个字段,先排 team, 在同 team 内再看 Q1
df.sort_values(by=[‘team’, ‘Q1’])
全降序
df.sort_values(by=[‘team’, ‘Q1’], ascending=False)
对应指定team升Q1降
df.sort_values(by=[‘team’, ‘Q1’], ascending=[True, False])
索引重新0-(n-1) 排
df.sort_values(‘team’, ignore_index=True)
索引和值同时排序
有些时间就需要索引和值混合排序,比如先按名字排序同序的再按团队排:
df.set_index(‘name’, inplace=True)
df.index.names = [‘s_name’]
df.sort_values(by=[‘s_name’, ‘team’])
以下方法也可以实现上述需求,不过要注意顺序
df.set_index(‘name’).sort_values(‘team’).sort_index()
以上方法也适用于多层索引。
以下多层索引示例,a 为一级 a1 为 a 下边的二级索引
df1.sort_values(by=(‘a’, ‘a1’))
其他
也可以用 nsmallest() 和 nlargest() 来实现排序(只支持数字):
s.nsmallest(3) # 最小的三个
s.nlargest(3) # 最大的三个
指定列
df.nlargest(3, ‘Q1’)
df.nlargest(5, [‘Q1’, ‘Q2’])
df.nsmallest(5, [‘Q1’, ‘Q2’])
九、Pandas 添加修改数据
数据分析过程中,对数据的修改调整也是比较多的,最简单的如学生成绩表加一列把总分算出来。根据某一列的数据解析出指定内容,如学生成绩单有个学生家庭地址,然后把所在小区解析出来形成新的一列。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
修改原理
Pandas 的数据修改是进行赋值,先把要修改的数据筛选出来,然后将同结构或者可解包的数据赋值给它:
df.Q1 = [1, 3, 5, 7, 9] * 20 # 就会把值进行修改
df.loc[1:3, ‘Q1’:‘Q2’] = 99 # 这个范围的数据会全变成 99
修改索引名称
对索引的修改包含行索引和列索引:
对索引值进行修改
df.rename(columns={“Q1”: “a”, “Q2”: “b”}) # 对表头进行修改
df.rename(index={0: “x”, 1: “y”, 2: “z”}) # 对索引进行修改
df.rename(index=str) # 对类型进行修改
df.rename(str.lower, axis=‘columns’) # 传索引类型
df.rename({1: 2, 2: 4}, axis=‘index’)
对索引名进行修改
s.rename_axis(“animal”)
df.rename_axis(“animal”) # 默认是列索引
df.rename_axis(“limbs”, axis=“columns”) # 指定行索引
多层索引时可以将type修改为class
df.rename_axis(index={‘type’: ‘class’})
可以用 set_axis 进行设置修改
s.set_axis([‘a’, ‘b’, ‘c’], axis=0)
df.set_axis([‘I’, ‘II’], axis=‘columns’)
df.set_axis([‘i’, ‘ii’], axis=‘columns’, inplace=True)
修改指定数据
替换数据:
s.replace(0, 5) # 将列数据中 0 换为 5
df.replace(0, 5) # 将数据中所有 0 换为 5
df.replace([0, 1, 2, 3], 4) # 将 0-3 全换成 4
df.replace([0, 1, 2, 3], [4, 3, 2, 1]) # 对应修改
{‘pad’, ‘ffill’, ‘bfill’, None} 试试
s.replace([1, 2], method=‘bfill’) # 向下填充
df.replace({0: 10, 1: 100}) # 字典对应修改
df.replace({‘Q1’: 0, ‘Q2’: 5}, 100) # 指定字段的指定值修改为 100
df.replace({‘Q1’: {0: 100, 4: 400}}) # 指定列里指定值按指定的值替换
使用正则
df.replace(to_replace=r’^ba.KaTeX parse error: Expected '}', got 'EOF' at end of input: …ce({'A': r'^ba.’}, {‘A’: ‘new’}, regex=True)
df.replace(regex={r’^ba.KaTeX parse error: Expected 'EOF', got '}' at position 23: …', 'foo': 'xyz'}̲) df.replace(re…’, ‘foo’], value=‘new’)
空值删除填充
删除空值:
df.dropna() # 一行中有一个空NaT就删除
df.dropna(axis=‘columns’) # 只保留全有值的列
df.dropna(how=‘all’) # 行或列全没值才删除
df.dropna(thresh=2) # 至少有两个空值时才删除
df.dropna(inplace=True) # 删除并生效替换
填充空值:
df.fillna(0) # 空全修改为 0
{‘backfill’, ‘bfill’, ‘pad’, ‘ffill’, None}, default None
df.fillna(method=‘ffill’) # 都修改为它前一个值
values = {‘A’: 0, ‘B’: 1, ‘C’: 2, ‘D’: 3}
df.fillna(value=values) # 各列替换空值不同
df.fillna(value=values, limit=1) # 只替换第一个
更多内容可参考数据清洗章节。
添加行列
添加列
Pandas 的数据添加修改非常简单,新赋值一个原 DF 中没有列名就会产生一个新列:
df[‘foo’] = 100 # 增加一列 foo, 所有值都是 100
df[‘foo’] = df.Q1 + df.Q2 # 新列为两列相加
df[‘foo’] = df[‘Q1’] + df[‘Q2’] # 同上
把所有为数字的加起来
df[‘total’] = df.select_dtypes(include=[‘int’]).sum(1)
df[‘total’] = df.loc[:,‘Q1’:‘Q4’].apply(lambda x: sum(x), axis=‘columns’)
df.loc[:, ‘Q10’] = ‘我是新来的’ # 也可以
增加一列并赋值,不满足条件的为 NaN
df.loc[df.num >= 60, ‘成绩’] = ‘合格’
df.loc[df.num < 60, ‘成绩’] = ‘不合格’
使用df.assign()指定新列:
df.assign(Q5=[100]*100) # 新增加一列 Q5
df = df.assign(Q5=[100]*100) # 赋值生效
df.assign(Q6=df.Q2/df.Q1) # 计算并增加 Q6
df.assign(Q7=lambda x: x.Q1 * 9 / 5 + 32) # 使用 lambda
添加一列,值为表达式结果 True or False
df.assign(tag=df.Q1>df.Q2)
True 为1 False 为 0
df.assign(tag=(df.Q1>df.Q2).astype(int))
映射文案
df.assign(tag=(df.Q1>60).map({True:‘及格’,False:‘不及格’}))
增加多个
df.assign(Q8=lambda x: x.Q1*5,
Q9=lambda x: x.Q8+1) # 注 Q8没生效不能直接 df.Q8
使用 df.insert() 插入新的行,会立即生效:
一般格式 df.insert(新列索引位, 名字, 数据)
df.insert(len(df.columns), ‘Qx’,
pd.Series(np.random.randn(100), index=df.index))
df.eval() 可以进行赋值定义一个新列:
df[‘C1’] = df.eval(‘Q2 + Q3’)
df.eval(‘C2 = Q2 + Q3’) # 计算
a = df.Q1.mean()
df.eval(“C3 = Q3
+@a”) # 使用变量
df.eval(“C3 = Q2 > (Q3
+@a)”) # 加一个布尔值
df.eval(‘C4 = name + team’, inplace=True) # 立即生效
添加行
最简单的办法利用新索引,按位置给出新数据的列表:
df.loc[101] = [‘tom’, ‘A’, 88, 88, 88, 88]
df.loc[101]={‘Q1’:88,‘Q2’:99} # 指定列,无数据列值为NaN
df.loc[df.shape[0]+1] = {‘Q1’:88,‘Q2’:99} # 自动增加索引
df.loc[len(df)+1] = {‘Q1’:88,‘Q2’:99}
如果需要批量操作,可以使用迭代的办法。
rows = [[1,2],[3,4],[5,6]]
for row in rows:
df.loc[len(df)] = row
df.append() 可以追加一个新行。
df = pd.DataFrame([[1, 2], [3, 4]], columns=list(‘AB’))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list(‘AB’))
df.append(df2)
pd.concat([s1, s2]) 可以将两个 df/s 连接起来:
s1 = pd.Series([‘a’, ‘b’])
s2 = pd.Series([‘c’, ‘d’])
pd.concat([s1, s2])
pd.concat([s1, s2], ignore_index=True) # 索引重新编
原数索引不就,增加一个一层索引(keys 里的内容)变成多层索引
pd.concat([s1, s2], keys=[‘s1’, ‘s2’])
pd.concat([s1, s2], keys=[‘s1’, ‘s2’],
names=[‘Series name’, ‘Row ID’])
df 同样道理
pd.concat([df1, df2])
pd.concat([df1, df3], sort=False)
pd.concat([df1, df3], join=“inner”) # 只连相同列
pd.concat([df1, df4], axis=1) # 连接列
关于将多个数据合并连接的操作可以查看教程数据合并。
删除行列
df.pop(‘Q1’) # 删除一列
s.pop(3) # 删除一个索引位
也可以把想要的列筛选出来赋值给 df 达到删除的目的
十、Pandas 删除数据
通过指定标签名称和相应的轴,或直接指定索引或列名称,删除行或列。 使用多索引时,可以通过指定级别来删除不同级别上的标签。
删除语法
基本语法为:
语法
df.drop(labels=None, axis=0,
index=None, columns=None,
level=None, inplace=False,
errors=‘raise’)
参数为:
labels:要删除的列或者行,多个传入列表
axis:轴的方向,0为行,1为列,默认为0
index:指定的一个行或者多个行,
column:指定的一个列或者多个列
level:索引层级,将删除此层级
inplace:布尔值,是否生效
errors:ignore或者raise,默认raise,如果为ignore,则抑制错误并仅删除现有标签
示例
原始数据:
df = pd.DataFrame(np.arange(12).reshape(3, 4),
columns=[‘A’, ‘B’, ‘C’, ‘D’])
df
‘’’
A B C D
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
‘’’
删除列:
df.drop([‘B’, ‘C’], axis=1)
df.drop(columns=[‘B’, ‘C’]) # 同上
‘’’
A D
0 0 3
1 4 7
2 8 11
‘’’
按索引删除行:
df.drop([0, 1])
‘’’
A B C D
2 8 9 10 11
‘’’
多层索引删除
多层索引数据删除行和列:
midx = pd.MultiIndex(levels=[[‘lama’, ‘cow’, ‘falcon’],
[‘speed’, ‘weight’, ‘length’]],
codes=[[0, 0, 0, 1, 1, 1, 2, 2, 2],
[0, 1, 2, 0, 1, 2, 0, 1, 2]])
df = pd.DataFrame(index=midx, columns=[‘big’, ‘small’],
data=[[45, 30], [200, 100], [1.5, 1], [30, 20],
[250, 150], [1.5, 0.8], [320, 250],
[1, 0.8], [0.3, 0.2]])
df
‘’’
big small
lama speed 45.0 30.0
weight 200.0 100.0
length 1.5 1.0
cow speed 30.0 20.0
weight 250.0 150.0
length 1.5 0.8
falcon speed 320.0 250.0
weight 1.0 0.8
length 0.3 0.2
‘’’
删除行和列:
df.drop(index=‘cow’, columns=‘small’)
‘’’
big
lama speed 45.0
weight 200.0
length 1.5
falcon speed 320.0
weight 1.0
length 0.3
‘’’
指定层级:
df.drop(index=‘length’, level=1)
‘’’
big small
lama speed 45.0 30.0
weight 200.0 100.0
cow speed 30.0 20.0
weight 250.0 150.0
falcon speed 320.0 250.0
weight 1.0 0.8
‘’’
十一、Pandas 数据迭代遍历
迭代工作可以将数据按行或者按列遍历,我们可以做更加细化、个性化的数据处理,不过大多数情况下,我们只要写好处理方法,用相应的函数帮我们去迭代。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
按行迭代
df.iterrows()
可以按行取出数据,每条数据是一个元组:
(<索引>, ), 其中 Series 的索引是 表头,可以用 s[‘team’]、 s.team 形式取出
for index, row in df.iterrows():
print(index, row[‘name’], row.team, row.Q1)
注: s[‘name’] 和 s.name 输出的结果不一样,s.name 输出的是 Series 的 name 属性
df.itertuples()
可以生成一个 namedtuples 类型数据,非常方便使用:
for row in df.itertuples():
print(row)
Pandas(Index=0, name=‘Liver’, team=‘E’, Q1=89, Q2=21, Q3=24, Q4=64)
for row in df.itertuples(index=False):
print(row)
Pandas(name=‘Liver’, team=‘E’, Q1=89, Q2=21, Q3=24, Q4=64)
for row in df.itertuples(index=False, name=‘Gairuo’): # namedtuples
print(row)
Gairuo(name=‘Liver’, team=‘E’, Q1=89, Q2=21, Q3=24, Q4=64)
使用
for row in df.itertuples():
print(row.Index, row.Q1)
注:
itertuples() 应该比 iterrows() 快
迭代时不会保留行的 dtypes
不要修改行,迭代器返副本,写入不起作用 可以 copy() 处理
按列迭代
df.items()Iterate over (column name, Series) pairs,和df.iteritems()有相同的功能。
for label, ser in df.loc[1].items():
print(label, ser)
‘’’
name Arry
team C
Q1 36
Q2 37
Q3 37
Q4 57
‘’’
其他:
依次取出每个列
for column in df:
print(df[column])
可对每个列的内容进行迭代
for column in df:
for i in df[column]:
print(i)
当然,可以迭代指定列
for i in df.name:
print(i)
一个方法,只迭代想要的列
l = [‘name’, ‘Q1’]
cols = df.columns.intersection(l)
for col in cols:
print (col)
此外,df.Q1.values 和 df.values 可以返回 array 类型的数据,可用于迭代。
apply 和 applymap 可以对方法进行迭代,可以查询教程函数应用章节查看更多函数应用。
十二、Pandas 函数应用
函数是一个大杀器,如果 Pandas 提供的内置方法不够用,我们可以定义函数来做特别的处理。函数也可以让我们对数据重复的工作自动化。
注:本文所使用的 df 和 s 是数据信息一文中的数据。
管道方法 pipe()
Pandas 提供的 pipe() 可以让我们写的分析过程标准化、流水线化,达到复用,同时也是最近非常流行的链式方法的重要担当,可在Pandas链式方法中查看它的思想和应用。
语法结构:df.pipe(<函数名>, <传给函数的参数列表>)
对 df 多重应用多个函数
f(g(h(df), arg1=a), arg2=b, arg3=c)
用 pipe 可以把它们连接起来
(df.pipe(h)
.pipe(g, arg1=a)
.pipe(f, arg2=b, arg3=c)
)
以下是将 ‘arg2’ 参数给函数 f 然后作为函数整体授受后边的参数
(df.pipe(h)
.pipe(g, arg1=a)
.pipe((f, ‘arg2’), arg1=a, arg3=c)
)
以下是个实例:
定义一个函数,给所有Q的成绩加 n,然后增加平均数
其中 n 中要加的值,为必传参数
def add_mean(rdf, n):
df = rdf.copy()
df = df.loc[:,‘Q1’:‘Q4’].applymap(lambda x: x+n)
df[‘avg’] = df.loc[:,‘Q1’:‘Q4’].mean(1)
return df
调用
df.pipe(add_mean, 100)
也可以直接使用匿名函数:
其中 xy 是变量,df_ 是前边的数据内容
df.pipe(lambda df_, x, y: df_[(df_.a >= x) & (df_.b <= y)], 2, 8)
apply()
对 DataFrame 中的按行和列(默认)进行函数处理。
df.apply(max) # 所有列的最大值
df.apply(lambda x: x*2) # 所有列的值乘于2 = df * 2
df.Q1.apply(lambda x: x+10 if type(x) is int else x) # 所有数字加10
df.loc[:,‘Q1’:‘Q4’].apply(sum, axis=1) # 指定列横向相加
def mymax(x):
return x.max()
df.apply(lambda x:mymax(x)) # 应用函数
判断一个值是否在另外一个类似列表的列中
df.apply(lambda x: x.s in x.s_list, axis=1) # 布尔序列
df.apply(lambda x: x.s in x.s_list, axis=1).astype(int) # 0 和 1 序列
一个常用的根据条件输出结果的案例(使用 numpy 库 np.where):
fun = lambda x: np.where(x.team==‘A’ and x.Q1>90, ‘good’ ,‘other’)
df.apply(fun, axis=1)
同上效果
(df.apply(lambda x:x.team==‘A’ and x.Q1>90, axis=1)
.map({True:‘good’, False:‘other’})
)
df.apply(lambda x: ‘good’ if x.team==‘A’ and x.Q1>90 else ‘’, axis=1)
总结,apply 可以应用的函数类型包括:
df.apply(fun) # 自定义
df.apply(max) # python 内置函数
df.apply(lambda x: x*2) # lambda
df.apply(np.mean) # numpy 等其他库的函数
df.apply(pd.Series.first_valid_index) # Pandas 自己的函数
df.apply(‘count’) # Pandas 自己的函数
多个函数
df.apply([sum, ‘count’]) # 相当于 .aggregate, 即.agg
df.apply({‘Q1’:sum, ‘Q2’:‘count’}) # 同上
其他函数调用方法基本都支持上述几类函数。
applymap()
df.applymap() 可做到元素级函数应用,就是对 DataFrame 中所有的元素(不包含索引)应用函数处理。使用 lambda 时,变量是指每一个具体的值。
df.applymap(lambda x: x*2) # 所有元素的最大值
df.applymap(lambda x: len(str(x))) # 所有的值长度
df.applymap(lambda x: x+10 if type(x) is int else x) # 所有数字加10
def mylen(x):
return len(str(x))
df.applymap(mylen) # 应用函数
对空值不使用函数 pandas 1.2.0+
df.applymap(mylen, na_action=‘ignore’)
map()
根据输入对应关系映射值修改内容,用于 Series 对象或 DataFrame 对象的一列。
df.team.map({‘A’:‘一班’, ‘B’:‘二班’,‘C’:‘三班’, ‘D’:‘四班’,}) # 枚举替换
df.team.map(‘I am a {}’.format)
df.team.map(‘I am a {}’.format, na_action=‘ignore’)
t = pd.Series({‘six’: 6., ‘seven’: 7.})
s.map(t)
应用函数
def f(x):
return len(str(x))
df[‘name’].map(f)
agg()
使用指定轴上的一项或多项操作进行汇总。
每列的最大值
df.agg(‘max’)
将所有列聚合产生 sum 和 min 两行
df.agg([‘sum’, ‘min’])
系列多个聚合
df.agg({‘Q1’ : [‘sum’, ‘min’], ‘Q2’ : [‘min’, ‘max’]})
分组后聚合
df.groupby(‘team’).agg(‘max’)
df.Q1.agg([‘sum’, ‘mean’])
def mymean(x):
return x.mean()
df.Q2.agg([‘sum’, mymean])
每列使用不同的方法进行聚合
df.agg(a=(‘Q1’, max),
b=(‘Q2’, ‘min’),
c=(‘Q3’, np.mean),
d=(‘Q4’, lambda s:s.sum()+1)
)
按行聚合
df.loc[:,‘Q1’:].agg(“mean”, axis=“columns”)
利用 pd.Series.add 方法对所有数据加分
other 是 add 方法的参数
df.loc[:,‘Q1’:].agg(pd.Series.add, other=10)
更加详细的介绍可查看教程Pandas 聚合分组部分。
transform()
自身调用函数并返回一个 DataFrame。
df.transform(lambda x: x*2) # 应用匿名函数
df.transform([np.sqrt, np.exp]) # 调用多个函数
df.transform([np.abs, lambda x: x + 1])
df.transform({‘A’: np.abs, ‘B’: lambda x: x + 1})
df.transform(‘abs’)
df.transform(lambda x: x.abs())
可以对比下下两个操作:
聚合后按组显示合计
df.groupby(‘team’).sum()
聚合后按原数据结构显示数据,但在指定位置上显示聚合计算后的结果
df.groupby(‘team’).transform(sum)
copy()
类似于 Python 中的 copy() 函数,df.copy() 方法可以返回一个新的对象,这个新的对象就与原对象断绝关系了。
s = pd.Series([1, 2], index=[“a”, “b”])
s_1 = s
s_copy = s.copy()
s_1 is s # True
s_copy is s # False