Pandas
Pandas提供了高级数据结构和函数,这些数据结构和函数的设计使得利用结构化、表格化数据的工作快速、简单、有表现力
一些独特的需求,促使作者开发Pandas
- 带有标签轴,支持自动化或显式数据对齐功能的数据结构(这可以防止未对齐数据和不同数据源的不同索引数据所引起的常见错误,数据对齐可以简单理解为数据库的连表操作)
- 集成时间序列函数功能
- 能够同时处理时间序列数据和非时间序列数据的统一数据结构
- 可以保存元数据的算术操作和简化
- 灵活处理缺失数据
- 流行数据库(例如基于SQL的数据库)中的合并等关系型操作
Pandas的两个核心数据结构Series、DataFrame分别代表着一维的序列和二维的表结构
- Series - 一维,带标签数组
- 本质上由2个数组构成,一个数组构成键(index、行索引),一个数组构成值(values),键=>值
- 很多方法跟ndarray类似,Series有where方法(ndarry没有,可用使用np.where())
- DataFrame - 二维,Series容器
- 既有行索引(index),横向索引,axis=0
- 又有列索引(columns),纵向索引,axis=1
基于这两种数据结构,Pandas可以对数据进行导入、清洗、处理、统计和输出等操作
优化打印预览样式
import pandas as pd
pd.set_option('expand_frame_repr', False)
pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)
创建Series
s = pd.Series([1, 2, 3])
s = pd.Series(np.arange(3), index=list('ABC'))
# X=>NaN,dtype会变成float64
s1 = pd.Series({"A": 0, "B": 1, "C": 2}, index=list('ABCX'))
print(s)
print(type(s))
print(s.dtype)
Series的索引切片
Series的索引可以直接传入序号或index
import pandas as pd
import numpy as np
import string
# Series的切片可参照numpy
s = pd.Series(np.arange(10), index=list(string.ascii_uppercase[:10]))
# Index(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], dtype='object')
print(s.index)
# 改变索引顺序,值不变
s.index = ['B', 'C', 'A', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
# [0 1 2 3 4 5 6 7 8 9]
print(s.values)
# <class 'pandas.core.indexes.base.Index'>
print(type(s.index))
# <class 'numpy.ndarray'>
print(type(s.values))
print(s[0:10:2])
print(s[[1, 3, 5]])
print(s[["B", "D", "F"]])
print(s[s > 5])
print(s * 2)
a = [1, 2, 3, 4, 5]
s = pd.Series(a, index=list('abcde'))
# [1 2 3] 用数字切片和普通的Python或numpy一样,是不含尾部的
print(s[0:3].values)
# [1 2 3 4] 用索引切片是含尾部的
print(s['a':'d'].values)
s2 = pd.Series(np.arange(3), index=list('DEF'))
'''
s+s2会根据索引对齐,其他填None
A NaN
B NaN
C NaN
D 3.0
E 5.0
F 7.0
G NaN
H NaN
I NaN
J NaN
'''
print(s + s2)
# asof示例,在数字索引上也是等效的
s = pd.Series([11, 22, 33, 44], index=pd.date_range('20230101', periods=4))
'''
正常打印Series
2023-01-01 11
2023-01-02 22
2023-01-03 33
2023-01-04 44
'''
print(s)
'''
匹配时间索引后打印Series
2023-01-01 11
2023-01-03 33
'''
print(s.asof(pd.date_range('20230101', periods=2, freq='2D')))
'''
匹配时间索引后打印Series,超过最大索引的用最大索引的值填充
2023-01-01 11
2023-01-03 33
2023-01-05 44
2023-01-07 44
2023-01-09 44
'''
print(s.asof(pd.date_range('20230101', periods=5, freq='2D')))
创建DataFrame
- 2D ndarray:数据的矩阵,行和列的标签是可选参数
- 数组、列表和元祖构成的字典:每个序列成为DataFrame的一列,所有的序列必须长度相等
- NumPy结构化/记录化数组:与数组构成的字典一致
- Series构成的字典:每个值成为一列,每个Series的索引联合起来形成结果的行索引,也可以显示地传递索引
- 字典构成的字典:每一个内部字典成为一列,键联合起来形成结果的行索引
- 字典或Series构成的列表:列表中的一个元素形成DataFrame的一行,字典键或Series索引联合起来形成DataFrame的列标签
- 列表或元祖构成的列表:与2D ndarray的情况一致
- 其他DataFrame:如果不显示传递索引,则会使用原DataFrame的索引
- NumPy MaskedArray:与2D ndarray的情况类似,但隐蔽值会在结果DataFrame中成为NA/缺失值
import pandas as pd
import numpy as np
# 字典+列表,显示指定行索引
df = pd.DataFrame({"w": [1, 2, 3], "x": [4, 5, 6], "y": [7, 8, 9], "z": [10, 11, 12]}, index=list('abc'))
# 字典+字典,也可以是Series
df = pd.DataFrame({"w": {"a": 1, "b": 2, "c": 3}, "x": {"a": 11, "b": 22, "c": 33}, "y": {"a": 111, "b": 222, "c": 333},
"z": {"a": 1111, "b": 2222, "c": 3333}})
# 使用ndarray(或二维数组)创建DataFrame,指定行、列索引
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list('abc'), columns=list('wxyz'))
# 通过columns调整列顺序,b、a、c(c列全为NaN)
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}, columns=['b', 'a','c'])
print(df)
DataFrame的常用方法和属性
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list('abc'), columns=list('wxyz'))
# 整体情况查询
# 显示头几行,默认5行
print(df.head(10))
# 显示最后几行,默认5行
print(df.tail(10))
# 相关信息概览:行数、列数、列索引、列非空值个数、行类型、列类型、内存占用情况等
print(df.info())
# 快速统计信息:计数、均值、标准差、最大值、四分位数、最小值等
print(df.describe())
# 基础属性
print(df.shape) # 行数、列数
print(df.size) # 行列数
print(df.index) # 行索引
print(df.values) # 对象值,二维ndarray数组
print(df.columns) # 列索引
print(df.dtypes) # 数据类型
print(df.ndim) # 数据维度
# NumPy的函数也能在pandas对象上使用
df = pd.DataFrame([1,-1,2,-2],columns=['A'])
print(np.abs(df))
DataFrame的索引
一些索引对象的方法和属性
- append:将额外的索引对象粘贴到原索引后,产生一个新的索引
- difference:计算两个索引的差集
- intersection:计算两个索引的交集
- union:计算两个索引的并集
- isin:计算表示每一个值是否在传值容器中的布尔数组
- delete:将位置i的元素删除,并产生新的索引
- drop:根据传参删除指定索引值,并产生新的索引
- insert:在位置i插入元素,并产生新的索引
- is_monotonic:如果索引序列递增则返回True
- is_unique:如果索引序列唯一则返回True
- unique:计算索引的唯一值序列
reindex常用方法
- index:新建作为索引的序列,可以是索引实例或任意其他序列型Python数据结构,索引使用时无需复制
- method:插值方式,'ffill'是前向填充、'bfill'是后向填充(通常用在顺序索引或时间序列索引上)
- fill_value:通过重新索引引入缺失数据时使用的替代值
- limit:当前向或后向填充时,所需填充的最大尺寸间隙(以元素数量)
- tolerance:当前向或后向填充时,所需填充的不精确匹配下的最大尺寸间隙(以绝对数字距离)
- level:匹配MultiIndex级别的简单索引;否则选择子集
- copy:如果为True,即使新索引等于旧索引,也总是复制底层数据;如果是False,则在索引相同时不要复制数据
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list('XYZ'), columns=list('wxyz'))
# 设置索引
df.index = ['AA', 'BB', 'CC']
# 设置列
df.columns = ['w', 'x', 'y', 'z']
# 重排索引,如果索引不存在会填充NaN
df1 = df.reindex(['AA', 'BB', 'CCC'])
# reindex默认行索引,也可以重排列(或行、列一起改)
df2 = df1.reindex(['AA', 'BB', 'CCC'], columns=["w", "x", "y", "zz"])
# 将某一列作为索引,drop=False保留原值(x作为索引后,依然保留x列)。有点像array_reset_key
df2 = df.set_index('x', drop=False)
# 还原set_index,还原的时候如果之前的x列没有被drop,这里要加上drop=True,否则会报错(有2个x列了)
df3 = df2.reset_index(drop=True)
# DataFrame的索引是可以重复的,可以通过unique()去重
print(df2.index.unique(), df)
# 分层索引、复合索引
arr = np.arange(12).reshape((3, 4))
df = pd.DataFrame(arr, columns=[['A', 'B', 'C', 'D'], ['AA', 'AA', 'DD', 'DD']],
index=[['X', 'Y', 'Z'], ['XX', 'ZZ', 'ZZ']])
'''
A B C D
AA AA DD DD
X XX 0 1 2 3
Y ZZ 4 5 6 7
Z ZZ 8 9 10 11
'''
print(df)
df = pd.DataFrame(
{"a": [0, 1, 2, 3, 4, 5, 6], "b": [7, 6, 5, 4, 3, 2, 1], "c": ["one", "one", "one", "one", "two", "two", "two"],
"d": ["i", "j", "k", "l", "m", "n", "o"]})
# Series的复合索引
df1 = df.set_index(['b', 'c'])['a']
print(df1)
print(df1[7, 'one'])
print(df1[7]['one'])
# 交换索引等级,从内层索引开始取数据
print(df1.swaplevel()['one'])
# DataFrame的复合索引和Series类似,用loc或iloc取就行了
df2 = df.set_index(['b', 'c'])
print(df2.swaplevel().loc['one'])
# 如果多层索引有多个可以指定level(从0开始)或指定名称(需要取名)进行交换
df2.index.names = ['key1', 'key2']
print(df2.swaplevel('key1', 'key2'))
print(df2.swaplevel(0, 1))
遍历DataFrame
import pandas as pd
df = pd.DataFrame({"name": ["张三", "李四", "王五"], "age": [18, 19, 20]})
# 将DataFrame迭代成元组,按行遍历
for i in df.itertuples():
print(getattr(i, 'name'))
# 将DataFrame迭代成(index ,series),按行遍历
for i, v in df.iterrows():
print(v['name'])
# 将DataFrame迭代成(列名,series),按列遍历
for i, v in df.iteritems():
print(v.values)
break
DataFrame的索引切片
df的切片与取值
- df[val]:从DataFrame中选择单列或列序列;特殊情况的便利:布尔数组(过滤行),切片(切片行)或布尔值DataFrame(根据某些标准设置的值)
- df.loc[val]:根据标签选择DataFrame的单行或多行
- df.loc[:, val]:根据标签选择单列或多列
- df.loc[val1, val2]:同时选择行和列中的一部分
- df.iloc[where]:根据整数位置选择单行或多行
- df.iloc[:, where]:根据整数位置选择单列或多列
- df.iloc[where_i:, where_j]:根据整数位置选择行和列
- df.at[label_i:, label_j]:根据行、列标签选择单个标量值
- df.iat[i:, j]:根据行、列整数位置选择单个标量值
- reindex方法:通过标签选择行或列
- get_value,set_value:根据行和列的标签设置单个值
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list('abc'), columns=list('wxyz'))
# 不管取行或取列都会变成Series
# 取行用loc或iloc,取行后列变成Series的索引
print(df.loc['a'])
print(df.iloc[0])
# 取列用df['column'](任意列名都有效,可以创建新列)或df.column(只在列名是有效的Python变量名时有效,不能创建新列),取列后行变成Series的索引
print(df['x'])
df = pd.DataFrame(np.arange(24).reshape(6, 4), index=list('abcefg'), columns=list('wxyz'))
# 取第0行和第1行
print(df[0:2])
# 取第0行
print(df.iloc[0])
# 取第0行和第1行
print(df.iloc[0:2])
# 交叉取
print(df.iloc[[0, 2], [1, 2]])
# 取第0行和第2行(标签是闭合尾巴)
print(df.loc["a":"c"])
# 交叉取,a-c行的x列和y列
print(df.loc["a":"c", ["x", "y"]])
# 交叉取,a-c行的x列和y列
print(df.loc[["a", "c"], ["x", "y"]])
# 取w列的前2行
print(df.loc[:'b', 'w'])
算术相关方法
- add、radd:加法(+)
- sub、rsub:减法(-)
- div、rdiv:除法(/)(方法前面加"r"会翻转参数,比如:1 / df 和 df.rdiv(1)等效)
- floordiv、rfloordiv:整除(//)
- mul、rmul:乘法(*)
- pow、rpow:幂次方(**)
import pandas as pd
import numpy as np
# 和Series相加一样,df的相加也会自动对齐
df1 = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
df2 = pd.DataFrame({"b": [1, 2, 3], "c": [4, 5, 6]})
'''
a b c
0 NaN 5 NaN
1 NaN 7 NaN
2 NaN 9 NaN
'''
print(df1 + df2)
'''
如果需要填充NaN,可以使用函数,通过fill_value来设置
注意:这里的效果不是上面结果的NaN全变成0,而是df1、df2先各自填0
a b c
0 1.0 5 4.0
1 2.0 7 5.0
2 3.0 9 6.0
'''
print(df1.add(df2, fill_value=0))
# DataFrame和Series间的算术操作和NumPy中不同维度的数组间操作类似
# 默认情况下使用df的列和Series的索引进行匹配并广播到各行
# 如果一个索引不再df的列中也不在Series的索引中,则对象会重建索引并形成联合
# 如果想在行上匹配并在列上广播,必须使用函数并传入axis
s = pd.Series({"a": 1, "b": 2})
print(df1 - s)
s1 = pd.Series([1, 2, 3])
print(df1.sub(s1, axis=0))
删除行列
import numpy as np
import pandas as pd
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=['a', 'b', 'c'], columns=['A', 'B', 'C', 'D'])
# 删除D列
del df['D']
# 删除C列
df.drop(columns='C', inplace=True)
# 删除D列
df.drop('D', axis=1, inplace=True)
# 删除行
df.drop(index="a", inplace=True)
# 删除多行
df.drop(['a', 'b'], axis=0, inplace=True)
# 删除行、列(不是交叉,是一起删掉)
df.drop(index="b", columns='B', inplace=True)
# 去除重复行
df.drop_duplicates(inplace=True)
print(df)
map、apply、applymap
- map:Series逐元素
- apply:用在行或列上,也可以用在Series逐元素(如果函数需要额外参数的话),也可以用在groupby上对每组数据进行处理
- applymap:DataFrame逐元素
map
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list("xyz"), columns=list("abcd"))
print(df['a'].map(lambda x: x + 100))
apply
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list("xyz"), columns=list("abcd"))
# 下面2个效果相同
print(df.apply(np.sum, axis=1))
print(df.sum(axis=1))
def mysum(x, args1, args2, args3):
return x + args1 + args2 + args3
# 自定义函数(多参数)
print(df.apply(mysum, args=(1, 2, 3)))
applymap
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list("xyz"), columns=list("abcd"))
def size(i):
if i == 0:
return None
elif i < 3:
return 'small'
elif i < 8:
return 'middle'
else:
return 'large'
print(df.applymap(size))
排序、排名
# 以DataFrame为例,Series中也是一样的(只是不需要指定列)
df = pd.DataFrame(np.arange(8).reshape(2, 4), index=['z', 'y'], columns=['d', 'a', 'b', 'c'])
# 根据index排序
df.sort_index(inplace=True)
# 根据column降序排序
df.sort_index(inplace=True, axis=1, ascending=False)
# 根据指定一列或多列的值排序
df.sort_values(inplace=True, by='a')
df.sort_values(inplace=True, by=['d', 'c'])
排名的method参数
整个组举例:[7, -5, 7, 4, 2, 0, 4],2个7一组、2个4一组、其他分别一组
- average:在每个组中分配平均排名(默认)
- min:对整个组使用最小排名
- max:对整个组使用最大排名
- first:按照值在数据中出现的次序分配排名
- dense:类似于method='min',但在组间排名总是增加1,而不是一个组中的相等元素的个数
视图与复制
从DataFrame中选取的列是数据的视图,而不是拷贝。所以,对Series的修改会映射到DataFrame中
如果需要复制,显示地使用Series的copy方法
布尔索引
import pandas as pd
df = pd.DataFrame({"语文": [88, 89, 90], "数学": [58, 100, 90], "英语": [38, 99, 70]}, index=["张三", "李四", "王五"])
# 布尔索引
df1 = df[df['语文'] >= 90]
# 或、且操作,需要用括号括起来
df2 = df[(df['语文'] >= 90) | (df['数学'] == 100)]
df3 = df[(df['语文'] >= 60) & (df['英语'] >= 60)]
字符串相关方法
import pandas as pd
df = pd.DataFrame({"姓名": ["张三张s", "张四", "王五"], "职业": ["Python工程师", "财经分析师", "PHP工程师"]}, dtype=str) # type:pd
# 逗号分隔拼接
df['cat'] = df['姓名'].str.cat(df['职业'], sep=',')
# 按逗号拆分
df['cat_list'] = df['cat'].str.split(",")
# 字符串是否包含(模糊匹配)
print(df['职业'].str.contains('工程'))
# 字符串出现的次数(模糊匹配)
print(df['职业'].str.count('财经'))
# 头部或末尾是否包含
df['金融相关'] = df['职业'].str.startswith('财经')
df['技术相关'] = df['职业'].str.endswith('工程师')
# 带张的找出来 [张,张] [张] []
print(df['姓名'].str.findall('张'))
# 找到第0个字符
print(df['姓名'].str.get(0))
# 用-把每个字符连接
df['join'] = df['姓名'].str.join('-')
# 字符数
print(df['姓名'].str.len())
# 大小写转换
print(df['姓名'].str.upper())
print(df['姓名'].str.lower())
# 正则匹配张开头的
print(df['姓名'].str.match(r'^张.*?'))
# 宽度20,两边添加x
df['职业'] = df['职业'].str.pad(20, side='left', fillchar='x')
# 相当于str.pad设置side='both'
df['职业'] = df['职业'].str.center(30, fillchar='y')
# 姓名重复3次,相当于姓名*3
print(df['姓名'].str.repeat(3))
# 替换,把s替换成空
print(df['姓名'].str.replace('s', ''))
# 截取字符串[start,end)
print(df['姓名'].str.slice(1, 2))
# 去掉左边、右边、两边的空白符(包括换行符),可指定自定义字符
print(df['职业'].str.lstrip(to_strip='y'))
print(df['职业'].str.rstrip(to_strip='y'))
print(df['职业'].str.strip(to_strip='y'))
统计相关函数
描述性统计和汇总统计相关方法
- count:非NA的个数
- describe:计算Series或DataFrame各列的汇总统计集合
- min,max:计算最小值、最大值
- argmin,argmax:分别计算最小值、最大值所在索引位置(整数)
- idxmin,idxmax:分别计算最小值、最大值所在索引标签
- quantile:计算样本从0到1间的分位数
- sum:加和
- mean:均值
- median:中位数(50%分位数)
- mad:平均值的平均绝对离差
- prod:所有值的积
- var:值的样本方差
- std:值的样本标准差
- skew:样本偏度(第三时刻)值
- kurt:样本峰度(第四时刻)值
- cumsum:累计值
- cummin,cummax:累计值的最小值或最大值
- cumprod:值的累计积
- diff:计算第一个算术差值(对时间序列有用)
- pct_change:计算百分比
归约方法可选参数
- axis:归约轴,0为行向,1位列向
- skipna:排除缺失值,默认为:True
- level:如果轴是多层索引(MultiIndex),该参数可以缩减分组层级
import pandas as pd
# 如果不忽略None值,那么那一列的均值为None
df = pd.DataFrame({"a": [1, 6, 9], "b": [2, 3, None]})
print(df.mean(skipna=False))
相关性与协方差
import pandas as pd
df = pd.DataFrame(
{"age": [3, 6, 9, 20, 30, 40, 50], "height": [20, 40, 60, 170, 190, 170, 160], "sex": [1, 1, 1, 1, 1, 2, 2]})
# Series的corr方法计算的是两个Series中重叠的、非NA的、按索引对齐的值的相关性。相应的,cov计算的是协方差
# 相关性,0.823525151594576
print(df['height'].corr(df['age']))
# 协方差,1076.1904761904761
print(df['height'].cov(df['age']))
# DataFrame的corr和cov方法会分别以DataFrame的形式返回相关性和协方差矩阵
'''
age height sex
age 1.000000 0.823525 0.847782
height 0.823525 1.000000 0.465621
sex 0.847782 0.465621 1.000000
'''
print(df.corr())
'''
age height sex
age 326.619048 1076.190476 7.476190
height 1076.190476 5228.571429 16.428571
sex 7.476190 16.428571 0.238095
'''
print(df.cov())
# 使用DataFrame的corrwith方法,可以计算DataFrame中的行或列与另外一个序列或DataFrame的相关性
'''
age 0.823525
height 1.000000
sex 0.465621
'''
print(df.corrwith(df['height']))
'''
age 1.0
height 1.0
sex 1.0
'''
print(df.corrwith(df))
'''
0 1.0
1 1.0
2 1.0
3 1.0
4 1.0
5 1.0
6 1.0
'''
print(df.corrwith(df,axis=1))
NaN相关处理
计算平均值等情况,nan是不参与计算的,但是0会
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), columns=list('abcd'))
df.loc[[1, 2], ['b', 'c']] = np.nan
# isna、notna分别是isnull、notnull的别名
print(df.isna())
print(df.isnull())
print(df.notna())
print(df.notnull())
# 查看哪列存在空值NaN
print(df.isnull().any())
# 填充NaN
print(df.fillna(df.mean()))
# 使用高频值填充
print(df['a'].fillna(df['a'].value_counts.index[0],inplace=True))
# 删除NaN
df.dropna(axis=0, inplace=True, how='any')
# 0变成NaN
df[df == 0] = np.nan
数据合并
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.arange(12).reshape(3, 4), columns=list('abcd'))
df2 = pd.DataFrame(np.arange(10, 22).reshape(3, 4), columns=list('efgh'))
# join 横向合并,根据索引连表,是merge指定索引连表的简写形式
print(df1.join(df2))
print(df1.merge(df2, left_index=True, right_index=True))
# concat 纵向合并,根据column
df3 = pd.DataFrame(np.arange(10, 22).reshape(3, 4), columns=list('abcd'))
print(pd.concat([df1, df3]))
'''
axis=1,concat可指定轴变成横向合并
join='inner',假设df1有3行,df2有2行,那么concat后也只会有2行,如下:
df2.loc[2] = None
df2.dropna(inplace=True)
keys=['one','two'],column增加一个外层索引(变成多层索引)
names=['upper','lower'],index增加一个外层索引(变成多层索引)
ignore_index=True,忽略索引(行(index)和列(column)都变成自增的数字),取第一列df[0]、取第一行df.loc[0]
df = pd.concat([s1,s2], axis=1, join='inner', join_axes[['a','b','c']], keys=['one','two'], names=['upper','lower'], ignore_index=True)
'''
# merge 类似于MySQL的连表操作
df4 = pd.DataFrame(np.array([
[0, 11, 22, 33],
[0, 22, 33, 44],
[0, 33, 44, 55],
]), columns=list('ijkl'))
print(df1.merge(df4, how='left', left_on='a', right_on='i'))
'''
常用参数示例,left_on也可以多个['left_key1', 'left_key2'],right_on也可以多个['right_key1', 'right_key2']
pd.merge(df1, df2, left_on='left_key', right_on='right_key', how='outer')
其他参数示例,suffixes('_left', '_right')列名重复的场景可以用后缀,left_index=True、right_index=True使用索引作为连表的主键
跟数据库连表类似,如果数据存在多对多的话会笛卡尔积
'''
# combine_first 互相修补None
df1 = pd.DataFrame({'A': ['A1', None, 'A3', 'A4'], 'B': ['B1', None, None, 'B4']})
df2 = pd.DataFrame({'A': [None, 'A2', 'A3', 'AA4'], 'B': [None, None, 'B3', 'BB4']})
'''
如果都非None,不进行修补,即:以左边的对象为主
A B
0 A1 B1
1 A2 None
2 A3 B3
3 A4 B4
A B
0 A1 B1
1 A2 None
2 A3 B3
3 AA4 BB4
'''
print(df1.combine_first(df2))
print(df2.combine_first(df1))
堆叠
stack():从列到行堆叠
unstack():从行到列取消堆叠
import pandas as pd
import numpy as np
arr = np.arange(12).reshape((3, 4))
df = pd.DataFrame(arr, columns=['A', 'B', 'C', 'D'],index=['X','Y','Z'])
'''
A B C D
X 0 1 2 3
Y 4 5 6 7
Z 8 9 10 11
'''
print(df)
df1 = df.stack()
'''
堆叠后DataFrame降维成分层索引的Series
X A 0
B 1
C 2
D 3
Y A 4
B 5
C 6
D 7
Z A 8
B 9
C 10
D 11
'''
print(df1)
'''
取消堆叠后分层索引的Series变成DataFrame
A B C D
X 0 1 2 3
Y 4 5 6 7
Z 8 9 10 11
'''
print(df1.unstack())
分组和聚合
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.arange(12).reshape((3, 4)), columns=list('ABCD'), index=list('XYZ'))
df2 = pd.DataFrame(np.arange(12).reshape((3, 4)), columns=list('ABCD'))
df2.loc[[0, 1], ['B', 'C']] = None
df2['C'] = None
df = pd.concat([df1, df2])
# Series 根据另一个 Series 分组 SeriesGroupBy 以下等效
print(df['A'].groupby(df['B']))
# DataFrame 根据列名分组后取某列的值 SeriesGroupBy
print(df.groupby('B')['A'])
print(df.groupby(['B', 'C'])['A'])
# 如果希望分组后得到的是DataFrameGroupBy
print(df.groupby(['B'])[['A']])
print(df[['A']].groupby(df['B']))
# Series 根据一个同样长度的列表分组 SeriesGroupBy
print(df['A'].groupby([1, 1, 2, 2, 3, 3]))
# DataFrame 根据列名分组 DataFrameGroupBy
print(df.groupby('B'))
print(df.groupby(['B']))
# DataFrame 根据列名联合分组后统计数量,None不计数、以非None最多的计数(合并成1列)
print(df.groupby(['A', 'B']).size())
# DataFrame 根据列名联合分组后统计数量,None不计数、对每列进行计数
print(df.groupby(['A', 'B']).count())
# 遍历grouped
grouped = df.groupby(['A', 'B'])
# tup是一个元祖,元祖的第0项是key,第1项是值
for tup in grouped:
# (tuple_key, DataFrame)
print(tup)
# 拆包遍历
for (k1, k2), g in grouped:
print(k1, k2, g)
# 直接将grouped转成字典{"group_key": DataFrame}
d = dict(list(grouped))
# 在纵轴(二维df的1轴)上分组,根据列的dtype分组
grouped = df.groupby(df.dtypes, axis=1)
for i in grouped.groups.keys():
if i == int or i == float:
print(grouped.get_group(i).columns)
# 使用字典分组
df = pd.DataFrame({"橘子": [1, 2], "菠萝": [1, 1], "橙子": [3, 4], "香蕉": [2, 4]})
d = {"橘子": "橙色", "菠萝": "黄色", "橙子": "橙色", "香蕉": "黄色"}
print(df.groupby(d, axis=1).sum())
s = pd.Series(d)
print(df.groupby(s, axis=1).sum())
df1 = pd.DataFrame(np.arange(12).reshape((3, 4)), columns=list('ABCD'), index=list('XYZ'))
df2 = pd.DataFrame(np.arange(12).reshape((3, 4)), columns=list('ABCD'), index=['XX', 'YYY', 'ZZZ'])
df = pd.concat([df1, df2])
# 使用函数分组
# 根据行索引的长度分组,行索引不能是数字(如果要根据列索引分组,axis=1)
grouped_by_index_len = df.groupby(len)
for i in grouped_by_index_len:
print(i)
# 根据行索引最后一位分组
grouped = df.groupby(lambda x: x[-1])
for i in grouped:
print(i)
# 根据函数和列表联合分组
print(df.groupby([len, ['ab', 'ab', 'cd', 'cd', 'ab', 'ab']]).min())
# 根据索引等级分组,如果索引有name,也可以level='index_name'
df1 = pd.DataFrame(np.arange(12).reshape((3, 4)), columns=list('ABCD'), index=[['X', 'Y', 'Z'], ['X', 'Y', 'Z']])
df2 = pd.DataFrame(np.arange(12).reshape((3, 4)), columns=list('ABCD'), index=[['X', 'Y', 'Z'], ['XX', 'YY', 'ZZ']])
df = pd.concat([df1, df2])
# 如果groupby后不需要行索引,可以使用as_index=False
# # 如果groupby后不需要分组索引,可以使用group_keys=False
grouped = df.groupby(level=0)
for i in grouped:
print(i)
# 分组后的"聚合函数":count、sum、mean、median、std、var、min、max、prod、first、last、quantile、describe
# 分组后的能聚合(数值列)的列全部聚合,DataFrame
print(grouped.sum())
# 分组后的指定列聚合,Series,quantile(0.9)是9分位数的意思(不传默认为:median中位数)
print(grouped['A'].quantile(0.9))
# 使用自定义函数(aggregate或agg),参数是需要集合的列,最大值-最小值,DataFrame
print(grouped.agg(lambda col: col.max() - col.min()))
# agg可以用多套规则进行集合,假设有2套,那么聚合后的列数会成2
# agg中可以传系统自带函数(需要用引号),也可以用自定义函数(不需要用引号)
def my_func(col):
return col.max() - col.min()
print(grouped.agg(['mean', my_func]))
# 使用list后,函数名会默认为列索引名,可以使用元祖的第一个元素对其重命名
print(grouped.agg([('system_mean', 'mean'), ('customer_my_func', my_func)]))
# 针对不同列,使用不同的聚合函数,A列求和、B列取第一个
# 某些场景,假设B列是字符串,但我们也想保留(取第一个作为代表),可以这么使用
print(grouped.agg({"A": "sum", "B": "first"}))
# 分组后只保留updated_flag最大的一行
df = pd.DataFrame(
{"money": [11, 22, 33, 44], "updated_flag": [1, 1, 1, 2], "date": ["20230331", "20230630", "20230930", "20230930"]})
grouped = df.groupby("date").apply(lambda g: g.sort_values(by='updated_flag')[-1:])
print(grouped)
# 更通用的写法,自定义字段和行数
def my_func(g, col, n):
return g.sort_values(by=col)[-n:]
grouped = df.groupby("date", as_index=True).apply(my_func, 'updated_flag', 1)
print(grouped)
# g是分组后的DataFrame,和agg不同的是agg是分组后循环将每列(Series)传入
df.groupby("date").apply(lambda g: print(type(g)))
df.groupby("date").agg(lambda col: print(type(col)))
# 前面的"聚合函数"的describe,其实是以下写法的简写
print(df.groupby("date").apply(lambda g: g.describe()))
# g.name输出分组的key值,本例为:20230331 20230630 20230930
grouped.apply(lambda g: print(g.name))
# 根据cut或qcut分桶后,返回的是一个category对象,可以直接扔给groupby,示例:df_origin.groupby(pd.cut(df['money'], 2))
df = pd.DataFrame({"money": [0, 100, 66, 55, 54, 44, 33, 22, 44, 88]})
# 等长桶,根据指定的区间将数据分为n个等间距的箱子。每个箱子的边界由数据的最大值和最小值决定
# (100 + 0) / 4
print(pd.cut(df['money'], 4))
# 等大小桶,基于样本分位数进行分箱。首先会对数据进行排序,然后根据分位数将数据划分为q个等长的箱子
print(pd.qcut(df['money'], 4))
# 分位数计算公式,示例如下:
# 升序排序后变为[0, 22, 33, 44, 44, 54, 55, 66, 88, 100]
# 25百分位数对应的位置是:0.25 * (n - 1) = 0.25 * 9 = 2.25(n是数据点的数量)
# 使用线性插值法,计算位置2和位置3中间的数: 33 + (0.25 * (44 - 33)) = 35.75(0.25是2.25的小数部分)
# 30百分位数对应的位置是:0.3 * (n - 1) = 0.3 * 9 = 2.7(n是数据点的数量)
# 使用线性插值法,计算位置2和位置3中间的数: 33 + (0.7 * (44 - 33)) = 40.7(0.7是2.7的小数部分)
print(df['money'].quantile(0.25))
print(df['money'].quantile(0.3))
透视表、交叉表
pivot_table:透视表,df.pivot_table(),也有顶层的pd.pivot_table()为groupby提供一个方便的接口
crosstab:交叉表是透视表的一种特殊形式,计算的是分组中的频率,df.crosstab(),也有顶层的pd.crosstab()为groupby提供一个方便的接口
交叉表和透视表是基于groupby实现的,如果使用起来不习惯的话,可以直接使用groupby
参数示例:
- values: 需要聚合的列名,默认情况下聚合所有数值型的列
- index: 在结果透视表的行上进行分组的列名或其他分组键
- columns: 在结果透视表的列上进行分组的列名或其他分组键
- aggfunc: 聚合函数或函数列表(默认:'mean'),可是groupby上下文的任意有效函数
- fill_value: 在结果表中替换缺失值的值
- dropna: 如果为True,将不含所有条件均为NA的列
- margins: 添加行/列小计和总计(默认:False)
时间序列
pd.date_range()
import pandas as pd
import numpy as np
from pandas.tseries.offsets import Hour, Minute, MonthEnd
from datetime import datetime
# <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
# 2001-1-1到2001-2-1每天的时间索引
dt = pd.date_range('2001-1-1', '2001-2-1')
# 开始时间往后推5天,含开始时间
dt = pd.date_range(start='2001-1-1', periods=5)
# 结束时间往前推5天,含结束时间
dt = pd.date_range(end='2001-1-1', periods=5)
# 时间序列索引作为df的索引
df = pd.DataFrame(np.arange(5), columns=['num'], index=dt)
# Q-JAN:1月作为季度结束(非自然年季度)
# [2000-01-31 00:00:00, 2000-04-30 00:00:00, 2000-07-31 00:00:00, 2000-10-31 00:00:00]
dt = pd.date_range('2000-1-1', '2000-12-31', freq='Q-JAN')
# 生成标准化为0的时间戳
dt = pd.date_range('2010-01-01 11:11:11', periods=5, normalize=True)
# 对于基础频率,都有一个对象可以被用于定义日期偏置
print(pd.date_range("2001-1-1", '2001-1-1 23:59', freq=Hour(1) + Minute(30)))
print(pd.date_range("2001-1-1", '2001-1-1 23:59', freq=Minute(90)))
# 大多数情况下我们不需要显示调用,直接使用字符串别名就可以了
print(pd.date_range("2001-1-1", '2001-1-1 23:59', freq='1h30min'))
print(pd.date_range("2001-1-1", '2001-1-1 23:59', freq='90min'))
# 像MonthEnd这种叫锚定偏置量
now = datetime(2023, 11, 23)
# 当月月底,2023-11-30 00:00:00
print(now + MonthEnd())
# 下月底,2023-12-31 00:00:00
print(now + MonthEnd(2))
# 锚定偏置量有向前滚动(rollforward)和向后滚动(rollback)的移位方法
offset = MonthEnd()
# 2023-11-30 00:00:00
print(offset.rollforward(now))
# 2023-10-31 00:00:00
print(offset.rollback(now))
# 用移位方法和groupby结合使用,是日期偏置的一种创造性用法
ts = pd.Series(np.arange(20), pd.date_range('2023-1-1', periods=20, freq='10D'))
offset = MonthEnd()
print(ts.groupby(offset.rollforward).sum())
# 当然该示例使用重采样会更简单
print(ts.resample("M").sum())
别名 | 偏置类型 | 描述 |
---|---|---|
D | Day | 日历日的每天 |
B | BusinessDay | 工作日的每天 |
H | Hour | 每小时 |
T或min | Minute | 每分 |
S | Second | 每秒 |
L或ms | Milli | 每毫秒(千分之一秒) |
U | Micro | 每微秒(百万分之一秒) |
M | MonthEnd | 日历日的月底日期 |
BM | BusinessMonthEnd | 工作日的月底日期 |
MS | MonthBegin | 日历日的月初日期 |
BMS | BusinessMonthBegin | 工作日的月初日期 |
W-MON,W-TUE,... | Week | 按照给定的星期日期按每周取日期(SUN,MON,TUE,WED,THU,FRI,SAT) |
WOM-1MON,WOM-2MON,... | WeekOfMonth | 在本月的第一、二、三或四周创建按周分隔的日期(例如:WOM-3FRI代表每月的第三个星期五) |
Q-JAN,Q-FEB,... | QuarterEnd | 每个月最后一个日历日的季度日期,以表示月份结束的年份(JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC) |
BQ-JAN,BQ-FEB,... | BusinessQuarterEnd | 每个月最后一个工作日的季度日期,以表示月份结束的年份 |
QS-JAN,QS-FEB,... | QuarterBegin | 每个月第一个日历日的季度日期,以表示月份开始的年份 |
BQS-JAN,BQS-FEB,... | BusinessQuarterBegin | 每个月第一个工作日的季度日期,以表示月份开始的年份 |
A-JAN,A-FEB,... | YearEnd | 给定月份所在的月的最后一个日历日所对应的年度日期 |
BA-JAN,BA-FEB,... | BusinessYearEnd | 给定月份所在的月的最后一个工作日所对应的年度日期 |
AS-JAN,AS-FEB,... | YearBegin | 给定月份所在的月的第一个日历日所对应的年度日期 |
BAS-JAN,BAS-FEB,... | BusinessYearBegin | 给定月份所在的月的第一个工作日所对应的年度日期 |
import pandas as pd
import numpy as np
from datetime import datetime
# DatetimeIndex(['2023-01-01', '2023-12-11', '2023-01-01', 'NaT'], dtype='datetime64[ns]', freq=None)
# None -> Nat(not a time)
dt = pd.to_datetime(['2023-01-01', '20231211', '2023-11-1', None])
print(dt.year)
# 如果传入的是Series,返回的也是Series,需要.dt后再获取相关的信息
s = pd.to_datetime(pd.Series(['2023-01-01', '20231211', '2023-11-1', None]))
print(s.dt.year)
# 跟其他索引的Series一样,时间序列相加会根据时间对齐(前提:时间序列索引不重复)
ts = pd.Series(np.arange(4), index=dt)
ts + ts[::2]
# 时间索引可能存在重复的情况,和其他重复索引一样,可以通过is_unique来判断是否重复
print(dt.is_unique)
# 返回的是标量还是Series取决于索引是否重复
print(ts['20231211'])
# 重复索引的聚合
ts.groupby(level=0)
# 传入datetime类型,会自动变成时间索引:DatetimeIndex
s = pd.Series([1], index=[datetime(2022, 12, 1)])
s.index
# 如果是DatetimeIndex类型的索引,下面取法都可以
s['20221201']
s['2022-12-01']
s['2022/12/1']
s = pd.Series(np.arange(1000), pd.date_range('20000101', periods=1000))
# 取2001年每天的数据
s['2001']
# 取2001年5月每天的数据
s['2001-5']
# 取2001年5月1日到5月27日每天的数据
s['2001-5-1':'20010527']
# 取2002年1月1日之后的数据,以下等效
s[datetime(2002, 1, 1):]
s.truncate(before='2002-01-01')
# 以上操作在df上也是可以的
df = pd.DataFrame({"number": np.arange(1000)}, index=pd.date_range('2000-01-01', periods=1000))
df.loc['2002-01-01':]
重采样指的是将时间序列从一个频率转化为另一个频率进行处理的过程
将高频率数据转化为低频率数据为降采样,低频率转化为高频率为升采样
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.uniform(0, 99, (100, 1)), pd.date_range('2021-1-1', periods=100, freq='D'))
# 降采样,按月抽样后,取抽样的平均值
print(df.resample("M").mean())
# 降采样,按10天抽样后,取抽样的求和
print(df.resample("10D").sum())
# 扩展,抽样2行
print(df.sample(2))
时间期间(时间段)
import pandas as pd
df = pd.DataFrame(
{"year": [2021] * 48, "month": [1] * 48, "day": [1] * 24 + [2] * 24, "hour": list(range(0, 24)) * 2})
periods = pd.PeriodIndex(year=df["year"], month=df["month"], day=df["day"], hour=df["hour"], freq="H")
同比、环比、本期、上期、滚动、时间序列滚动
import pandas as pd
df = pd.DataFrame([1, 1.3, 1.8, 2.2, 5], columns=['num'])
'''
num
0 1.0
1 1.3
2 1.8
3 2.2
4 5.0
'''
print(df)
'''
向下滚动,滚动后本期变成了上期
num
0 0.0(fill_value)
1 1.0
2 1.3
3 1.8
4 2.2
'''
print(df.shift(1, fill_value=0))
'''
向上滚动,滚动后本期变成了下期
num
0 1.3
1 1.8
2 2.2
3 5.0
4 NaN
'''
print(df.shift(-1))
# 计算同比,(本期 - 上期) / 上期
df['pct'] = df.pct_change()
df['percent'] = (df['num'] - df.shift(1)['num']) / df.shift(1)['num']
print(df)
时间序列滚动
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(6), index=pd.date_range("2001-1-1", '2001-1-1 23', freq='4h'),
columns=['number'])
'''
number
2001-01-01 00:00:00 0
2001-01-01 04:00:00 1
2001-01-01 08:00:00 2
2001-01-01 12:00:00 3
2001-01-01 16:00:00 4
2001-01-01 20:00:00 5
'''
print(df)
'''
普通滚动(滚动值,不滚动索引),非时间序列索引也可以
number
2001-01-01 00:00:00 NaN
2001-01-01 04:00:00 0.0
2001-01-01 08:00:00 1.0
2001-01-01 12:00:00 2.0
2001-01-01 16:00:00 3.0
2001-01-01 20:00:00 4.0
'''
print(df.shift(1))
'''
增加频率(freq)对时间序列进行滚动,值不变,索引滚动
number
2001-01-01 08:00:00 0
2001-01-01 12:00:00 1
2001-01-01 16:00:00 2
2001-01-01 20:00:00 3
2001-01-02 00:00:00 4
2001-01-02 04:00:00 5
'''
print(df.shift(1, freq='8h'))
数据载入
常用读取文件的方法
- read_csv:从文件、URL或文件型对象读取分隔好的数据,逗号是默认分隔符
- read_table:从文件、URL或文件型对象读取分隔好的数据,制表符('\t)是默认分隔符
- read_fwf:从特定宽度格式的文件中读取数据(无分隔符)
- read_clipboard:read_table的剪贴板版本,在将表格从Web页面上转换成数据时有用
- read_excel:从Excel的XLS或XLSX文件中读取表格数据
- read_hdf:读取用pandas存储的HDF5文件
- read_html:从HTML文件中读取所有表格数据
- read_json:从JSON(JavaScript Objec tNotation)字符串中读取数据
- read_msgpack:读取MessagePack二进制格式的pandas数据
- read_pickle:读取以Python pickle格式存储的任意对象
- read_sas:读取存储在SAS系统中定制存储格式的SAS数据集
- read_sql:将SOL查询的结果(使用sqlalchemy)读取为pandas的DataFrame
- read_stata:读取Stata格式的数据集
- read_feather:读取Feather二进制格式
一些read_csv和read_table的常用参数(其他方法也可以参考)
- path:表明文件系统位置的字符串、URL或文件型对象
- sep或delimiter:用于分隔每行字段的字符序列或正则表达式
- header:用作列名的行号,默认是0(第一行),如果没有列名的话,应该为None
- index_col:用作结果中行索引的列号或列名,可以是一个单一的名称/数字,也可以是一个分层索引
- names:结果的列名列表,和header=None一起用
- skiprows:从文件开头处起,需要跳过的行数或行号列表
- na_values:需要用NA替换的值序列
- comment:在行结尾处分隔注释的字符
- parse_dates:尝试将数据解析为datetime,默认是False。如果为True,将尝试解析所有的列。也可以指定列号或列名列表来进行解析。如果列表的元素是元组或列表,将会把多个列组合在一起进行解析(例如日期/时间将拆分为两列)
- keep_date_col:如果连接列到解析日期上,保留被连接的列,默认是False
- converters:包含列名称映射到函数的字典(例如{'foo':f}会把函数f应用到'foo'列)
- dayfirst:解析非明确日期时,按照国际格式处理(例如:7/6/2012->June7,2012),默认为False
- date_parser:用于解析日期的函数
- nrows:从文件开头处读入的行数
- iterator:返回一个TextParse对象,用于零散地读入文件
- chunksize:用于迭代的块大小
- skip_footer:忽略文件尾部的行数
- verbose:打印各种解析器输出的信息,比如位于非数值列中的缺失值数量
- encoding:Unicode文本编码(例如:utf-8用于表示UTF-8编码的文本)
- squeeze:如果解析数据只包含一列,返回一个Series
- thousands:千位分隔符(例如','或'.')
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.arange(12).reshape(3, 4), index=["a", "b", "c"], columns=["w", "x", "y", "z"])
df1.to_excel("./excel_demo.xlsx", index=False)
df2 = pd.read_excel('./excel_demo.xlsx')
# 如果需要读取多个sheet,可以生成ExcelFile,这样读取更快
# xlsx = pd.ExcelFile("1.xlsx")
# pd.read_excel("xlsx", 'sheet1')
# pd.read_excel("xlsx", 'sheet2')
df1.to_csv("./csv_demo.csv", index=False)
df3 = pd.read_csv("./csv_demo.csv")
'''
从数据库读取的Json一般是这种格式的
[
{"id":1, "name":"张三"},
{"id":2, "name":"李四"},
]
'''
print(data.to_json(orient='records'))
读取二进制(简单整理下),一般用不到
- pickle:仅被推荐为短期的存储格式
- HDF5:可以长期存储,但是同时写入等操作可能导致文件损坏
- HDFS:分布式存储的二进制格式之一,有专门的Python接口
import pandas as pd
import numpy as np
# pickle
df = pd.DataFrame({"name": ['张三', '李四'], "age": [13, 14]})
df.to_pickle('1.pickle')
df2 = pd.read_pickle('1.pickle')
print(df2)
# hdf5
df = pd.DataFrame({'a': np.random.randn(100)})
store = pd.HDFStore("mydata.h5")
store['df1'] = df
store['col1'] = df['a']
print(store)
print(store['df1'])
# HDFStore支持两种存储模式,'fixed'和'table',后者速度慢,但支持类sql语法
store.put('df2', df, format='table')
df2 = store.select("df2", where=['index >= 10 and index <= 15'])
print(df2)
# 关闭连接
store.close()
# 直接写到文件
df.to_hdf('mydata.h5', 'df3', format='table')
# 读取文件
df3 = pd.read_hdf('mydata.h5', 'df3', where=['index < 5'])
print(df3)
数据库,需要安装 pymysql
和 sqlalchemy
import pandas as pd
from sqlalchemy import create_engine
import urllib.parse
df = pd.DataFrame({"test": ['a', 'b', 'c']})
# 如果存在特殊符号,需要使用urllib.parse处理下
password = urllib.parse.quote_plus('123456@qq.com')
DB_CONFIG = f'mysql+pymysql://root:{password}@127.0.0.1:3306/txf_test_db?charset=utf8mb4'
conn = create_engine(DB_CONFIG)
# 写数据库
df.to_sql('txf_test_tb', conn, index=False, if_exists='append', chunksize=3000)
# 读数据库
pd.read_sql("select * from txf_test_tb", conn)
其他常用函数
- isin:计算表征Series中的每个值是否包含于传入序列的布尔值数组
- match:计算数组中每个值的整数索引,形成一个唯一值数组。有助于数据对齐和join类型的操作
- unique:计算Series值中的唯一索引值,按照观察顺序返回
- value_counts:返回一个Series,索引是唯一值序列,值是计数个数,按照个数降序排序
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(3, 4), index=list("xyz"), columns=list("abcd"))
# 重命名
df.rename(columns={"test": "测试"}, inplace=True)
# 转换类型
df['bb'] = df['bb'].astype("float")
one-hot编码
import pandas as pd
data = {'A': ['a', 'b', 'a'], 'B': ['b', 'a', 'c']}
df = pd.DataFrame(data)
'''
A B
0 a b
1 b a
2 a c
A_a A_b B_a B_b B_c
0 1 0 0 1 0
1 0 1 1 0 0
2 1 0 0 0 1
'''
one_hot_df = pd.get_dummies(df, columns=['A', 'B'])