pd.read_csv()
读取csvpd.read_excel()
读取excelpd.read_txt()
读取文本文档公共参数:
header=None 从第几行开始读取
index_col 指定行索引
usecols 读取那几列
parse_dates 把给出的列转化为时间序列
nrows 读取的行数
在读取txt文件时经常遇到分隔符不是空格,read_table()有一个分隔参数叫sep自定义分隔符(可以写正则表达式)
一般在写入时把 index
设置为 False
,当索引没有使用意义时就要去掉
普通写入
to_csv
to_excel
以下需要安装tabulate包
to_markdown
to_latex
是 一维 的数据结构
pd.Series(data,index,dtype,name)
参数:
data = 值
index = 索引
dtype = 存储类型
name = 序列名字
#示例
pd.Series(data = [100,'a',{'dict':5}],
index = pd.Index(
['id1',20,'thrid'],
name='my_index'),
dtype='object',
name = 'my_name')
my_index
id1 100
20 a
thrid {'dict': 5}
Name: my_name, dtype: object
object类型
代表一种混合类型,目前pandas把 字符串数组 认为是object类型
相当于 二维 数组,由Series组成
data = [[1,'a',1.2],[2,'b',2.2],[3,'c',3.2]]
df = pd.DataFrame(data=data,
index = ['row_%d'%i for i in range(3)],
columns=['col_0','col_1','col_2'])
print(df)
col_0 col_1 col_2
row_0 1 a 1.2
row_1 2 b 2.2
row_2 3 c 3.2
df.values
查看值df.index
查看行索引df.dtypes
查看每列的类型df.shape
查看形状维度df.T
转置df.head(n)
查看数据的前n行df.tail(n)
查看数据的后n行df.info()
返回表的信息概况(如果有中文会报错)df.describe(n)
汇总统计函数df.std()
标准差df.var()
方差df.corr()
于原始DataFrame列与列之间相关性的DataFrame对象。df.quantile()
分位数
df.count()
非缺失值个数df.idxmax()
最大值对应的索引df.unique()
把去掉重复值的数据输出
df.nunique()
数据中唯一数据的个数
df.value_counts()
得到重复值的数据和他出现的频数
df.drop_duplicates()
多列去重
'''
df.drop_duplicates参数
subset: 列名,可选,默认为None
keep: {‘first’, ‘last’, False}, 默认值 ‘first’
first: 保留第一次出现的重复行,删除后面的重复行。
last: 删除重复项,除了最后一次出现。
False: 删除所有重复项。
inplace:布尔值,默认为False,是否直接在原数据上删除重复项或删除重复项后返回副本。(inplace=True表示直接在原来的DataFrame上删除重复项,而默认值False表示生成一个副本。)
'''
df.duplicated()返回是否为唯一值的布尔列表,参数与drop_duplicates一致,如果元素是重复的都会标上True,否则False,drop_duplicates等价于把duplicated为True的对应行删除
pandas中可以分为三类:
映射替换,逻辑替换,数值替换
df.replace(old, new[, max])
- old -- 将被替换的子字符串。
- new -- 新字符串,用于替换old子字符串。
- max -- 可选字符串, 替换不超过 max 次
可以直接给予 字典 来替换数据
特殊方向替换
指定method = ffill/bfill
用 前面最近的未被替换掉 的值进行替换
用 后面最近的未被替换掉 的值进行替换
s = pd.Series(['a',1,'b',2,1,1,'a'])
print('ffill:\n',s.replace([1,2],method='ffill'))
print('\nbfill:\n',s.replace([1,2],method='bfill'))
ffill:
0 a
1 a
2 b
3 b
4 b
5 b
6 a
dtype: object
bfill:
0 a
1 b
2 b
3 a
4 a
5 a
6 a
dtype: object
df.where(condition)
传入条件为 False
的对应行进行替换df.mask(condition)
传入条件为 True
的对应行进行替换传入的条件也可以是Serise对象,只要是序列一致的布尔序列即可
s_condition = pd.Series([True,False,False,True],index=s.index)
s.mask(s_condition,0)
0 0.00000
1 1.23456
2 100.00000
3 0.00000
dtype: float64
df.round(n)
返回小数位为n位的四舍五入的float值
df.abc()
取绝对值
df.clip(lower, upper, axis, inplace)
lower : float或array_like,默认为None
最小阈值。低于此阈值的所有值都将设置为它
upper : float或array_like,默认为None
最大阈值。高于此阈值的所有值都将设置为它
axis : int或string轴名称,可选
沿给定轴将对象与下部和上部对齐
inplace : 布尔值,默认为False
是否对数据执行操作
sort_values()
值排序被排序的列可以是列表来进行多列排序
print('年龄用降序排序,工资用升序排序')
print(s.head().sort_values(['年龄','工资(元)'],ascending=[False,True]))
#因为在实操种可能有一些数据相同,索引就需要多列排序的操作,排在前面的先拍
年龄用降序排序,工资用升序排序
序号 姓名 年龄 工资(元)
1 2 黄丽 32 3600
0 1 张茜 28 2900
4 5 曾丽萍 27 2500
3 4 邓大海 26 2200
2 3 李海涛 24 2800
sort_index()
索引排序可以先指定索引列(level),字符串排序由字母顺序决定
print('以名字进行索引升序排序\n')
s.head().sort_index(level='姓名',ascending=True)
#看得出来是A-Z是升序,Z-A是降序
以名字进行索引升序排序
序号 姓名 年龄 工资(元)
0 1 张茜 28 2900
1 2 黄丽 32 3600
2 3 李海涛 24 2800
3 4 邓大海 26 2200
4 5 曾丽萍 27 2500
apply用与DataFrame的 行迭代 和 列迭代
DataFrame.apply(func,axis,raw,result_type)
func:
应用于每一列或每一行的函数。
axis:
{0 或 'index',1 或 'columns'},默认 0
沿其应用函数的轴:
0 或“索引”:将函数应用于每一列。
1 或“列”:将函数应用于每一行。
raw:
布尔值,默认为 False
确定行或列是否作为 Series 或 ndarray 对象传递:
False: 将每一行或每一列作为一个系列传递给函数。
True:传递的函数将接收 ndarray 对象。如果您只是应用NumPy 缩减功能,这将获得更好的性能。
result_type
{'expand', 'reduce', 'broadcast','None'},默认无
axis=1这些仅在(列)时起作用:
'expand' : 类似列表的结果将变成列。
'reduce' :如果可能,返回一个系列,而不是扩展类似列表的结果。这与“扩展”相反。
'broadcast' : 结果将被广播到DataFrame的原始形状,原始索引和列将被保留。
默认行为(None)取决于应用函数的返回值:类似列表的结果将作为这些结果的系列返回。但是,如果应用函数返回一个系列,这些将扩展为列。
df_demo = s[['年龄','工资(元)']]
#先把需要遍历的列或行提取出来
print('不用apply函数的平均值:\n',df_demo.mean())
def func(x):
res = x.mean()
return res
print('\n使用了apply函数的平均值\n',df_demo.apply(func,axis=1))
不用apply函数的平均值:
年龄 30.763889
工资(元) 3059.722222
dtype: float64
使用了apply函数的平均值
0 1464.0
1 1816.0
2 1412.0
3 1113.0
4 1263.5
...
67 1919.0
68 1617.0
69 1263.0
70 1917.5
71 2273.0
Length: 72, dtype: float64
apply的自由度很高但是代价是性能,所以一般少用apply
mad
函数返回的是一个序列中偏离该序列均值的绝对值大小的均值
例如序列1,3,7,10中,均值为5.25,每一个元素偏离的绝对值为4.25,2.25,1.75,4.75,这个偏离序列的均值为3.25。
print('mad函数输出\n',df_demo.mad())
print('\n使用apply输出\n',df_demo.apply(lambda x:(x-x.mean()).abs().mean()))
mad函数输出
年龄 5.515432
工资(元) 600.231481
dtype: float64
使用apply输出
年龄 5.515432
工资(元) 600.231481
dtype: float64
滑动窗口rolling 扩张窗口expanding 指数加权窗口ewm
rolling
滑动窗口将window参数设置为多少,就从源数据第一个元素向左边数 window参数-1(因为包括它本身) 然后进行运算,以此向后推
num5 = pd.Series([1,2,3,4,5,6])
roller = num5.rolling(window=2)
print(roller.sum())
'''
当窗口为2时,从第一个源数据元素向左数 window-1 个位 就是1个位
因为0索引左边没有任何数[本位数据为1],所以为缺失值(任何数与缺失值作运算都是缺失值)
因为1索引向左边数是1(源数据)[本位数据为2],所以求和为3
因为2索引向左边数是2(源数据)[本位数据为3],所以为5
'''
0 NaN
1 3.0
2 5.0
3 7.0
4 9.0
5 11.0
dtype: float64
他们的公共参数:periods=n
shift
向左取第n个元素的值#shift:取向左第n个元素的值
num5 = pd.Series([1,3,6,10,15])
print('shift:\n',num5.shift(periods=2))
print('\n特殊用法(取负数)\n',num5.shift(-1))
shift:
0 NaN
1 NaN
2 1.0
3 3.0
4 6.0
dtype: float64
特殊用法(取负数)
0 3.0
1 6.0
2 10.0
3 15.0
4 NaN
dtype: float64
diff
与向左第n个元素做差(与numpy不同,后者表示n阶差分)#diff:向左取n个元素做差
num5 = pd.Series([1,3,6,10,15])
print('diff:\n',num5.diff(2))
print('\n特殊用法(取负数):\n',num5.diff(-2))
diff:
0 NaN
1 NaN
2 5.0
3 7.0
4 9.0
dtype: float64
特殊用法(取负数):
0 -5.0
1 -7.0
2 -9.0
3 NaN
4 NaN
dtype: float64
pct_change
与向左第n个元素相比计算增长量(n可以为负,表示反方向的类似操作)#pct_change:与向左第n个元素相比计算增长量
num5 = pd.Series([1,3,6,10,15])
print('pct_change:\n',num5.pct_change(2))
print('\n特殊用法(取负数):\n',num5.pct_change(-2))
pct_change:
0 NaN
1 NaN
2 5.000000
3 2.333333
4 1.500000
dtype: float64
特殊用法(取负数):
0 -0.833333
1 -0.700000
2 -0.600000
3 NaN
4 NaN
dtype: float64
另类滑窗函数也可以用rolling函数来实现
expanding
累计窗口函数,与滑动窗口不同的是他的窗口会动态增大,从第一个开始向右边平移n个元素进行计算
num5 = pd.Series([1,3,6,10,15])
num5.expanding().mean()
0 1.000000
1 2.000000
2 3.333333
3 5.000000
4 7.000000
dtype: float64
####行索引
一般的索引都是中括号['列名']
来索引内容,结果返回Serise(参数<=1时),如果参数>1就返回DataFrame
#读取文件
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',usecols =
['School', 'Grade', 'Name', 'Gender','Weight', 'Transfer'])
df['Name'].head()
0 Gaopeng Yang
1 Changqiang You
2 Mei Sun
3 Xiaojuan Sun
4 Gaojuan You
Name: Name, dtype: object
此外,若要取出单列,且列名中不包含空格,则可以用 .列名
取出,这和 [列名] 是等价的:
如果取出单个索引对应的元素,可以使用[index]
,若 Series
只有单个值对应,则返回这个标量值,如果有多个值对应,则返回一个 Series
s = pd.Series([1, 2, 3, 4, 5, 6],
index=['a', 'b', 'a', 'a', 'a', 'c'])
s
a 1
b 2
a 3
a 4
a 5
c 6
dtype: int64
如果想要取出某两个索引之间的元素,并且这两个索引是在整个索引中 唯一出现 ,就可以使用 切片 (注意:索引切片会包含两个端点 )
s['c': 'b': -2]
c 6
a 4
b 2
dtype: int64
如果前后端点的值存在 重复 ,即 非唯一值 ,那么需要经过 排序 才能使用切片
#错误案例
try:
s['a','b']
except Exception as e:
Err_Msg = e
Err_Msg
KeyError('key of type tuple not found and not a MultiIndex')
如果使用整数切片,则会取出对应索引 位置
的值,注意这里的整数切片同 Python 中的切片一样 不包含右端点
s[1:-1:2]
b 2
a 4
dtype: int64
提示:
如果不想陷入麻烦,那么请不要把纯浮点以及任何混合类型(字符串、整数、浮点类型等的混合作为索引,否则可能会在具体的操作时报错或者返回非预期的结果,并且在实际的数据分析中也不存在这样做的动机。
是一种基于 元素 的索引器
语法:df.loc[*,*]
第一个 *
代表行的选择,第二个 *
代表列的选择,如果省略第二个位置写作 loc[ * ] ,这个 *
是指行的筛选
其中, *
的位置一共有五类合法对象
分别是:单个元素、元素列表、元素切片、布尔列表以及函数
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',usecols =
['School', 'Grade', 'Name', 'Gender','Weight', 'Transfer'])
df.head()
School | Grade | Name | Gender | Weight | Transfer | |
---|---|---|---|---|---|---|
0 | Shanghai Jiao Tong University | Freshman | Gaopeng Yang | Female | 46.0 | N |
1 | Peking University | Freshman | Changqiang You | Male | 70.0 | N |
2 | Shanghai Jiao Tong University | Senior | Mei Sun | Male | 89.0 | N |
3 | Fudan University | Sophomore | Xiaojuan Sun | Female | 41.0 | N |
4 | Fudan University | Sophomore | Gaojuan You | Male | 74.0 | N |
####行和列
df_demo.loc['Qiang Sun', 'School'] # 返回Series,因为第一个是索引列
Name
Qiang Sun Tsinghua University
Qiang Sun Tsinghua University
Qiang Sun Shanghai Jiao Tong University
Name: School, dtype: object
df_demo.loc['Quan Zhao', 'School'] # 返回单个元素
'Shanghai Jiao Tong University'
####元素列表
df_demo.loc[['Qiang Sun','Quan Zhao'], ['School','Gender']]#dataframe
School | Gender | |
---|---|---|
Name | ||
Qiang Sun | Tsinghua University | Female |
Qiang Sun | Tsinghua University | Female |
Qiang Sun | Shanghai Jiao Tong University | Female |
Quan Zhao | Shanghai Jiao Tong University | Female |
####切片
Series 使用字符串索引时提到,如果是唯一值的起点和终点字符,那么就可以使用切片,并且包含两个端点,如果不唯一则报错
#两个端点都包含
df_demo.loc['Gaojuan You':'Gaoqiang Qian', 'School':'Gender']
School | Grade | Gender | |
---|---|---|---|
Name | |||
Gaojuan You | Fudan University | Sophomore | Male |
Xiaoli Qian | Tsinghua University | Freshman | Female |
Qiang Chu | Shanghai Jiao Tong University | Freshman | Female |
Gaoqiang Qian | Tsinghua University | Junior | Female |
需要注意的是,如果 DataFrame
使用整数索引,其使用整数切片的时候和上面字符串索引的要求一致,都是 元素 切片,包含两个端点、端点不允许有重复值
df_loc_slice_demo = df_demo.copy() # 复制下来
df_loc_slice_demo.index = range(df_demo.shape[0],0,-1) #把所以设置为全部元素记录数的降序
df_loc_slice_demo.loc[5:3]# 定位器切片,两个端点都包含
School Grade Gender Weight Transfer
5 Fudan University Junior Female 46.0 N
4 Tsinghua University Senior Female 50.0 N
3 Shanghai Jiao Tong University Senior Female 45.0 N
df_loc_slice_demo.loc[3:5]
# 没有返回,说明不是整数位置切片,要根据索引排序来切片
School Grade Gender Weight Transfer
####布尔索引
传入 loc
的布尔列表与 DataFrame
长度相同,且列表为 True
的位置所对应的行会被选中, False
则会被剔除
# 选出体重超过70kg的学生
df_demo.loc[df_demo.Weight>70].head()
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Mei Sun | Shanghai Jiao Tong University | Senior | Male | 89.0 | N |
Gaojuan You | Fudan University | Sophomore | Male | 74.0 | N |
Xiaopeng Zhou | Shanghai Jiao Tong University | Freshman | Male | 74.0 | N |
Xiaofeng Sun | Tsinghua University | Senior | Male | 71.0 | N |
Qiang Zheng | Shanghai Jiao Tong University | Senior | Male | 87.0 | N |
isin
**方法返回的布尔列表等价写出# 选出所有大一和大四的同学信息
df_demo.loc[df_demo.Grade.isin(['Freshman', 'Senior'])].head()
#isin是dataframe的一个方法
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Gaopeng Yang | Shanghai Jiao Tong University | Freshman | Female | 46.0 | N |
Changqiang You | Peking University | Freshman | Male | 70.0 | N |
Mei Sun | Shanghai Jiao Tong University | Senior | Male | 89.0 | N |
Xiaoli Qian | Tsinghua University | Freshman | Female | 51.0 | N |
Qiang Chu | Shanghai Jiao Tong University | Freshman | Female | 52.0 | N |
#选出复旦大学中体重超过70kg的大四学生,或者北大男生中体重超过80kg的非大四的学生
school1 = df_demo.School == 'Fudan University'
grade1 = df_demo.Grade == 'Senior'
weight1 = df_demo.Weight > 70
FD = school1 & grade1 & weight1
school2 = df_demo.School == 'Peking University'
grade2 = df_demo.Grade == 'Senior'
weight2 = df_demo.Weight > 80
BD = school2 & (~grade2) & weight2 # (~grade2)这里是取反
df_demo.loc[FD | BD]
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Qiang Han | Peking University | Freshman | Male | 87.0 | N |
Chengpeng Zhou | Fudan University | Senior | Male | 81.0 | N |
Changpeng Zhao | Peking University | Freshman | Male | 83.0 | N |
Chengpeng Qian | Fudan University | Senior | Male | 73.0 | Y |
DataFrame.select_dtypes
参数:
include : 标量(类型)
exclude : 列表
标量或类似列表的内容,包括/排除 的dtypes或字符串的选择。必须至少提供这些参数之一
* 要选择所有数字类型,请使用np.number或'number'
* 要选择字符串,您必须使用objectdtype,但请注意,这将返回所有object dtype 列
* 查看numpy dtype 层次结构
* 要选择日期时间,请np.datetime64使用'datetime'或 'datetime64'
* 要选择时间增量,请np.timedelta64使用'timedelta'或 'timedelta64'
* 要选择 Pandas 分类数据类型,请使用'category'
* 要选择 Pandas datetimetz dtypes,请使用'datetimetz'(0.20.0 中的新功能)或'datetime64[ns, tz]'
df_demo.select_dtypes(include=['float64','object']).head()
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Gaopeng Yang | Shanghai Jiao Tong University | Freshman | Female | 46.0 | N |
Changqiang You | Peking University | Freshman | Male | 70.0 | N |
Mei Sun | Shanghai Jiao Tong University | Senior | Male | 89.0 | N |
Xiaojuan Sun | Fudan University | Sophomore | Female | 41.0 | N |
Gaojuan You | Fudan University | Sophomore | Male | 74.0 | N |
字符串dtypes是不允许的,使用’object’代替
必须以前面的四种合法形式之一为返回值,并且函数的输入值为DataFrame本身(支持使用 lambda 表达式)
def condition(x):
condition_1_1 = x.School == 'Fudan University'
condition_1_2 = x.Grade == 'Senior'
condition_1_3 = x.Weight > 70
condition_1 = condition_1_1 & condition_1_2 & condition_1_3
condition_2_1 = x.School == 'Peking University'
condition_2_2 = x.Grade == 'Senior'
condition_2_3 = x.Weight > 80
condition_2 = condition_2_1 & (~condition_2_2) & condition_2_3# (~condition_2_2) 取反
result = condition_1 | condition_2
return result
df_demo.loc[condition]
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Qiang Han | Peking University | Freshman | Male | 87.0 | N |
Chengpeng Zhou | Fudan University | Senior | Male | 81.0 | N |
Changpeng Zhao | Peking University | Freshman | Male | 83.0 | N |
Chengpeng Qian | Fudan University | Senior | Male | 73.0 | Y |
slice()
返回切片对象,主要作用在切片操作函数里的参数传递,由于函数无法返回(如 start: end: step )的切片形式,故返回切片时要用 slice
对象进行包装df_demo.loc[lambda x: slice('Gaojuan You', 'Gaoqiang Qian')]#start:end:step
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Gaojuan You | Fudan University | Sophomore | Male | 74.0 | N |
Xiaoli Qian | Tsinghua University | Freshman | Female | 51.0 | N |
Qiang Chu | Shanghai Jiao Tong University | Freshman | Female | 52.0 | N |
Gaoqiang Qian | Tsinghua University | Junior | Female | 50.0 | N |
对于 Series 也可以使用 loc 索引,其遵循的原则与 DataFrame 中用于行筛选的 loc[*] 完全一致
在对表或者序列赋值时,应当在使用一层索引器后直接进行赋值操作,这样做是由于进行多次索引后赋值是赋在临时返回的 copy 副本上的,而没有真正修改元素从而报出 SettingWithCopyWarning
警告。
df_chain[df_chain.A!=0].B = 1
'''
这样使用会出问题的原因就是索引后数据在内存中
再去直接调用属性并赋值pandas就会报出警告并且'不执行'这个语句
但是可以使用索引器来达到这个目的
'''
C:\Python310\lib\site-packages\pandas\core\generic.py:5516: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
self[name] = value
但是可以使用索引器来达到这个目的
df_chain.loc[df_chain.A!=0,'B'] = 1
df_chain
A B
0 0 0
1 1 1
2 -1 1
针对位置进行筛选/查找,在相应的 * 位置处一共也有五类合法对象,分别是:整数、整数列表、整数切片、布尔列表以及函数,函数的返回值必须是前面的四类合法对象中的一个,其输入同样也为 DataFrame
本身
df_demo.iloc[1, 1] # 第二行第二列
'Freshman'
df_demo.iloc[[0, 1], [0, 1]] # 前两行前两列
School | Grade | |
---|---|---|
Name | ||
Gaopeng Yang | Shanghai Jiao Tong University | Freshman |
Changqiang You | Peking University | Freshman |
df_demo.iloc[1:4, 2:4] # 切片不包含结束端点
Gender | Weight | |
---|---|---|
Name | ||
Changqiang You | Male | 70.0 |
Mei Sun | Male | 89.0 |
Xiaojuan Sun | Female | 41.0 |
df_demo.iloc[lambda x: slice(1, 4)]
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Changqiang You | Peking University | Freshman | Male | 70.0 | N |
Mei Sun | Shanghai Jiao Tong University | Senior | Male | 89.0 | N |
Xiaojuan Sun | Fudan University | Sophomore | Female | 41.0 | N |
布尔列表
在使用布尔列表的时候要特别注意,不能传入 Series
而必须传入序列的 values
,否则会报错。因此,在使用布尔筛选的时候还是应当优先考虑 loc 的方式
df_demo.iloc[(df_demo.Weight>80).values].head()
# .values 将布尔的每个值传入索引器
School | Grade | Gender | Weight | Transfer | |
---|---|---|---|---|---|
Name | |||||
Mei Sun | Shanghai Jiao Tong University | Senior | Male | 89.0 | N |
Qiang Zheng | Shanghai Jiao Tong University | Senior | Male | 87.0 | N |
Qiang Han | Peking University | Freshman | Male | 87.0 | N |
Chengpeng Zhou | Fudan University | Senior | Male | 81.0 | N |
Feng Han | Shanghai Jiao Tong University | Sophomore | Male | 82.0 | N |
对
Series
而言同样也可以通过 iloc 返回相应位置的值或子序列
pandas可以支持字符串形式传入 query
方法来查询数据,表达式执行结果必须返回布尔列表
优点:使用query方法可以无需重复使用DataFrame
的列名来索引,但一般使用的代码长度尽量较少(在不降低可读性的前提下)
df.query('((School == "Fudan University")&'
' (Grade == "Senior")&'
' (Weight > 70))|'
'((School == "Peking University")&'
' (Grade != "Senior")&'
' (Weight > 80))')
School | Grade | Name | Gender | Weight | Transfer | |
---|---|---|---|---|---|---|
38 | Peking University | Freshman | Qiang Han | Male | 87.0 | N |
66 | Fudan University | Senior | Chengpeng Zhou | Male | 81.0 | N |
99 | Peking University | Freshman | Changpeng Zhao | Male | 83.0 | N |
131 | Fudan University | Senior | Chengpeng Qian | Male | 73.0 | Y |
在 query 表达式中,自动帮用户注册了所有来自
DataFrame
的列名,所有属于该Series
的方法都可以被调用,和正常的函数调用并没有区别
对于含有空格的列名,需要使用 ‘col name
’ 的(加引号)方式进行引用。
or, and, or, is in, not in
df.query('(Grade not in ["Freshman", "Sophomore"])
and (Gender == "Male")').head()
School | Grade | Name | Gender | Weight | Transfer | |
---|---|---|---|---|---|---|
2 | Shanghai Jiao Tong University | Senior | Mei Sun | Male | 89.0 | N |
16 | Tsinghua University | Junior | Xiaoqiang Qin | Male | 68.0 | N |
17 | Tsinghua University | Junior | Peng Wang | Male | 65.0 | N |
18 | Tsinghua University | Senior | Xiaofeng Sun | Male | 71.0 | N |
21 | Shanghai Jiao Tong University | Senior | Xiaopeng Shen | Male | 62.0 | NaN |
==
和 !=
分别表示元素出现在列表或没有出现在列表,等价于 is in
和 not in
df.query('Grade == ["Junior", "Senior"]').head()
School | Grade | Name | Gender | Weight | Transfer | |
---|---|---|---|---|---|---|
2 | Shanghai Jiao Tong University | Senior | Mei Sun | Male | 89.0 | N |
7 | Tsinghua University | Junior | Gaoqiang Qian | Female | 50.0 | N |
9 | Peking University | Junior | Juan Xu | Female | NaN | N |
11 | Tsinghua University | Junior | Xiaoquan Lv | Female | 43.0 | N |
12 | Shanghai Jiao Tong University | Senior | Peng You | Female | 48.0 | NaN |
@
符号low, high =70, 80
df.query('Weight.between(@low, @high)').head()
School | Grade | Name | Gender | Weight | Transfer | |
---|---|---|---|---|---|---|
1 | Peking University | Freshman | Changqiang You | Male | 70.0 | N |
4 | Fudan University | Sophomore | Gaojuan You | Male | 74.0 | N |
10 | Shanghai Jiao Tong University | Freshman | Xiaopeng Zhou | Male | 74.0 | N |
18 | Tsinghua University | Senior | Xiaofeng Sun | Male | 71.0 | N |
35 | Peking University | Freshman | Gaoli Zhao | Male | 78.0 | N |
想要对样本或特征进随机抽样就可以用 sample
函数
sample(n , axis , frac , replace , weights)
n:抽样数量
axis:抽样方向(0为行,1为列)
frac:抽样比例(1为100%)
replace:是否放回(True/False)
weights:每个样本抽样的相对概率
df_sample = pd.DataFrame({'id': list('abcde'),'value': [1, 2, 3, 4, 90]})
df_sample
id | value | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | c | 3 |
3 | d | 4 |
4 | e | 90 |
示例:
df_sample.sample(3, replace = True, weights = df_sample.value)
'''
抽样数量为3,有放回,"weights是把vaolue整列的记录数除以整列的和"
'''
id | value | |
---|---|---|
4 | e | 90 |
4 | e | 90 |
4 | e | 90 |
#先创建一个表,用来示例,之后会讲到
np.random.seed(0)
multi_index = pd.MultiIndex.from_product([list('ABCD'),df.Gender.unique()], names=('School', 'Gender'))# 以笛卡尔积创建行索引
multi_column = pd.MultiIndex.from_product([['Height', 'Weight'],df.Grade.unique()], names=('Indicator', 'Grade'))# 以笛卡尔积创建列索引
df_multi = pd.DataFrame(np.c_[(np.random.randn(8,4)*5 + 163).tolist(),(np.random.randn(8,4)*5 + 65).tolist()],index = multi_index,columns = multi_column).round(1)#创建表
df_multi
Indicator Height Weight
Grade Freshman Senior Sophomore Junior Freshman Senior Sophomore Junior
School Gender
A Female 171.8 165.0 167.9 174.2 60.6 55.1 63.3 65.8
Male 172.3 158.1 167.8 162.2 71.2 71.0 63.1 63.5
B Female 162.5 165.1 163.7 170.3 59.8 57.9 56.5 74.8
Male 166.8 163.6 165.2 164.7 62.5 62.8 58.7 68.9
C Female 170.5 162.0 164.6 158.7 56.9 63.9 60.5 66.9
Male 150.2 166.3 167.3 159.3 62.4 59.1 64.9 67.1
D Female 174.3 155.7 163.2 162.1 65.3 66.5 61.8 63.2
Male 170.7 170.3 163.8 164.9 61.6 63.2 60.9 56.4
多级索引与单层索引的表一样,具备元素值,行索引,列索引三个部分,行索引和列索引都是**MultiIndex
类型,只不过索引中的元素是元组型** 而不是单层索引中的标量
names
和 values
获得df_multi.index.names#名字就是最外层的索引
FrozenList(['School', 'Gender'])
df_multi.columns.names#名字就是最外层的索引
FrozenList(['Indicator', 'Grade'])
df_multi.index.values#值属性就是里面内层的索引
array([('A', 'Female'), ('A', 'Male'), ('B', 'Female'), ('B', 'Male'),
('C', 'Female'), ('C', 'Male'), ('D', 'Female'), ('D', 'Male')],
dtype=object)
df_multi.columns.values#值属性就是里面内层的索引
array([('Height', 'Freshman'), ('Height', 'Senior'),
('Height', 'Sophomore'), ('Height', 'Junior'),
('Weight', 'Freshman'), ('Weight', 'Senior'),
('Weight', 'Sophomore'), ('Weight', 'Junior')], dtype=object)
get_level_values(n)
获得df_multi.index.get_level_values(0) # 里面的参数是层数,以0开始
Index(['A', 'A', 'B', 'B', 'C', 'C', 'D', 'D'], dtype='object', name='School')
# 先把索引设置成第一列和第二列
df_multi = df.set_index(['School', 'Grade'])
df_multi.head()
Name | Gender | Weight | Transfer | ||
---|---|---|---|---|---|
School | Grade | ||||
Shanghai Jiao Tong University | Freshman | Gaopeng Yang | Female | 46.0 | N |
Peking University | Freshman | Changqiang You | Male | 70.0 | N |
Shanghai Jiao Tong University | Senior | Mei Sun | Male | 89.0 | N |
Fudan University | Sophomore | Xiaojuan Sun | Female | 41.0 | N |
Sophomore | Gaojuan You | Male | 74.0 | N |
loc
和 iloc
方法可以完全照搬,只需把标量的位置替换成对应的元组df_sorted = df_multi.sort_index()#先排序
df_sorted.loc[('Fudan University', 'Junior')].head()
Name Gender Weight Transfer
School Grade
Fudan University Junior Yanli You Female 48.0 N
Junior Chunqiang Chu Male 72.0 N
Junior Changfeng Lv Male 76.0 N
Junior Yanjuan Lv Female 49.0 NaN
Junior Gaoqiang Zhou Female 43.0 N
df_sorted.loc[[('Fudan University', 'Senior'),('Shanghai Jiao Tong University', 'Freshman')]].head()
Name Gender Weight Transfer
School Grade
Fudan University Senior Chengpeng Zheng Female 38.0 N
Senior Feng Zhou Female 47.0 N
Senior Gaomei Lv Female 34.0 N
Senior Chunli Lv Female 56.0 N
Senior Chengpeng Zhou Male 81.0 N
df_sorted.loc[df_sorted.Weight > 70].head() # 布尔列表也是可用的
Name Gender Weight Transfer
School Grade
Fudan University Freshman Feng Wang Male 74.0 N
Junior Chunqiang Chu Male 72.0 N
Junior Changfeng Lv Male 76.0 N
Senior Chengpeng Zhou Male 81.0 N
Senior Chengpeng Qian Male 73.0 Y
df_sorted.loc[lambda x:('Fudan University','Junior')].head()
Name Gender Weight Transfer
School Grade
Fudan University Junior Yanli You Female 48.0 N
Junior Chunqiang Chu Male 72.0 N
Junior Changfeng Lv Male 76.0 N
Junior Yanjuan Lv Female 49.0 NaN
Junior Gaoqiang Zhou Female 43.0 N
df_sorted.loc[('Fudan University', 'Senior'):].head()
'''
('Fudan University', 'Senior')这是一个整体,代表这些行后面的所有内容(:)
'''
Name Gender Weight Transfer
School Grade
Fudan University Senior Chengpeng Zheng Female 38.0 N
Senior Feng Zhou Female 47.0 N
Senior Gaomei Lv Female 34.0 N
Senior Chunli Lv Female 56.0 N
Senior Chengpeng Zhou Male 81.0 N
df_unique = df.drop_duplicates(subset=['School','Grade']).set_index(['School', 'Grade'])
df_unique.head()
Name | Gender | Height | Weight | Transfer | Test_Number | Test_Date | Time_Record | ||
---|---|---|---|---|---|---|---|---|---|
School | Grade | ||||||||
Shanghai Jiao Tong University | Freshman | Gaopeng Yang | Female | 158.9 | 46.0 | N | 1 | 2019/10/5 | 0:04:34 |
Peking University | Freshman | Changqiang You | Male | 166.5 | 70.0 | N | 1 | 2019/9/4 | 0:04:20 |
Shanghai Jiao Tong University | Senior | Mei Sun | Male | 188.9 | 89.0 | N | 2 | 2019/9/12 | 0:05:22 |
Fudan University | Sophomore | Xiaojuan Sun | Female | NaN | 41.0 | N | 2 | 2020/1/3 | 0:04:08 |
Tsinghua University | Freshman | Xiaoli Qian | Female | 158.0 | 51.0 | N | 1 | 2019/10/31 | 0:03:47 |
df_unique.sort_index().loc[('Fudan University', 'Senior'):].head()
'''
sort_index()先以索引进行排序
loc[('Fudan University', 'Senior'):] 定位('Fudan University', 'Senior')这一行后输出这一行和后面所有内容
'''
Name | Gender | Weight | Transfer | ||
---|---|---|---|---|---|
School | Grade | ||||
Fudan University | Senior | Chengpeng Zheng | Female | 38.0 | N |
Sophomore | Xiaojuan Sun | Female | 41.0 | N | |
Peking University | Freshman | Changqiang You | Male | 70.0 | N |
Junior | Juan Xu | Female | NaN | N | |
Senior | Changli Lv | Female | 41.0 | N |
:
表示。其中,每一层需要选中的元素用列表存放,传入 loc 的形式为 [(level_0_list, level_1_list), cols]
res = df_multi.loc[(['Peking University', 'Fudan University'],['Sophomore', 'Junior']), :]
'''
['Peking University', 'Fudan University']与['Sophomore', 'Junior']都是条件,但是必须指定列
['Peking University', 'Fudan University']是第一层索引
['Sophomore', 'Junior']是第二层索引
'''
res.head()
Name Gender Weight Transfer
School Grade
Peking University Sophomore Changmei Xu Female 43.0 N
Sophomore Xiaopeng Qin Male NaN N
Sophomore Mei Xu Female 39.0 N
Sophomore Xiaoli Zhou Female 55.0 N
Sophomore Peng Han Female 34.0 NaN
引入 IndexSlice
对象就能解决对每层进行切片,也允许将切片和布尔列表混合使用这个问题
Slice 对象一共有两种形式:
第一种为 loc [ idx [ * , * ] ]
型
第二种为 loc [ idx [ * , * ] , idx [ * , * ] ]
型
# 构造一个索引不重复的表来学习
np.random.seed(0)
L1,L2 = ['A','B','C'],['a','b','c']
mul_index1 = pd.MultiIndex.from_product([L1,L2],names=('Upper', 'Lower'))
L3,L4 = ['D','E','F'],['d','e','f']
mul_index2 = pd.MultiIndex.from_product([L3,L4],names=('Big', 'Small'))
df_ex = pd.DataFrame(np.random.randint(-9,10,(9,9)),index=mul_index1,columns=mul_index2)
df_ex
Big D E F
Small d e f d e f d e f
Upper Lower
A a 3 6 -9 -6 -6 -2 0 9 -5
b -3 3 -8 -3 -2 5 8 -4 4
c -1 0 7 -4 6 6 -9 9 -6
B a 8 5 -2 -9 -8 0 -9 1 -6
b 2 9 -7 -9 -9 -5 -4 -3 -1
c 8 6 -5 0 1 -8 -8 -2 0
C a -6 -3 2 5 9 -9 5 -6 3
b 1 2 -5 -3 -5 6 -6 3 -5
c -1 5 6 -6 6 4 7 8 -4
silce
对象,先要进行定义idx = pd.IndexSlice
loc [ idx [ * , * ] ]
型
这种情况并不能进行多层分别切片,前一个 *
表示行的选择,后一个 *
表示列的选择,与单纯的 loc
是类似的
df_ex.loc[idx['C':, ('D', 'f'):]]
'''
idx:
'C'行之后的所有
('D', 'f')列之后的所有
如果不加冒号,这两个都会成为条件
'''
Big D E F
Small f d e f d e f
Upper Lower
C a 2 5 9 -9 5 -6 3
b -5 -3 -5 6 -6 3 -5
c 6 -6 6 4 7 8 -4
另外,也支持布尔序列的索引
df_ex.loc[idx[:'A', lambda x:x.sum()>0]] # 列和大于0
Big D F
Small d e e
Upper Lower
A a 3 6 9
b -3 3 -4
c -1 0 9
loc [ idx [ * , * ] , idx [ * , * ] ]
型
这种情况能够分层进行切片,前一个 idx
指代的是行索引,后一个是列索引
df_ex.loc[idx[:'A', 'b':], idx['E':, 'e':]]
'''
:'A' - 第一层行索引切到A , 'b': - 第二层行索引从b开始后面的所有(这里被第一层A限制了,所有才只有b,c)
'E': - 第一层列索引从E开始切到后面所有 , 'e': - 第二层列索引从e开始切到后面所有(因为第一层切出两个,所以分别从两个的e开始切)
'''
Big E F
Small e f e f
Upper Lower
A b -2 5 -4 4
c 6 6 9 -6
此方法不支持使用函数
常用的有 from_tuples , from_arrays , from_product
三种方法,他们都是 pd.MultiIndex
对象下的函数
from_tuples
根据传入由元组组成的列表进行构造my_tuple = [('a','cat'),('a','dog'),('b','cat'),('b','dog')]
pd.MultiIndex.from_tuples(my_tuple, names=['First','Second'])
MultiIndex([('a', 'cat'),
('a', 'dog'),
('b', 'cat'),
('b', 'dog')],
names=['First', 'Second'])
from_arrays
根据传入列表对相应层进行构造my_array = [list('aabb'), ['cat', 'dog']*2]
pd.MultiIndex.from_arrays(my_array, names=['First','Second'])
MultiIndex([('a', 'cat'),
('a', 'dog'),
('b', 'cat'),
('b', 'dog')],
names=['First', 'Second'])
from_product
根据给定多个列表的笛卡尔积进行构造
笛卡尔积: 就是两个列表的每个元素与另一个列表的每个元素相乘(这里是组合)
my_list1 = ['a','b']
my_list2 = ['cat','dog']
pd.MultiIndex.from_product([my_list1,my_list2],names=['First','Second'])
MultiIndex([('a', 'cat'),
('a', 'dog'),
('b', 'cat'),
('b', 'dog')],
names=['First', 'Second'])
##索引的常用方法
#创建一个3层索引便于学习
np.random.seed(0)
L1,L2,L3 = ['A','B'],['a','b'],['alpha','beta']
mul_index1 = pd.MultiIndex.from_product([L1,L2,L3],names=('Upper', 'Lower','Extra'))
L4,L5,L6 = ['C','D'],['c','d'],['cat','dog']
mul_index2 = pd.MultiIndex.from_product([L4,L5,L6],names=('Big', 'Small', 'Other'))
df_ex = pd.DataFrame(np.random.randint(-9,10,(8,8)),index=mul_index1,columns=mul_index2)
df_ex
Big C D
Small c d c d
Other cat dog cat dog cat dog cat dog
Upper Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
beta -9 -5 -4 -3 -1 8 6 -5
b alpha 0 1 -8 -8 -2 0 -6 -3
beta 2 5 9 -9 5 -6 3 1
索引层交换由 swaplevel
和 reorder_levels
完成,前者只能交换两个层,而后者可以交换任意层,两者都可以指定交换轴,即行索引或列索引
swaplevel
交换两个层'''
DataFrame.swaplevel(i=- 2, j=- 1, axis=0)
相会交换索引中的i层和j层,默认是交换索引的两个最内层
参数:
i, j: int 或 str
交换的索引的两个层级。可以将级别名称作为字符串传递。
axis:{0 或 'index',1 或 'columns'},默认 0
交换级别的轴。0 或 'index' 表示按行,1 或 'columns' 表示按列。
'''
df_ex.swaplevel(0,2,axis=1).head() # 列索引的第一层和第三层交换
Other cat dog cat dog cat dog cat dog
Small c c d d c c d d
Big C C C C D D D D
Upper Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
reorder_levels
交换任意层级'''
DataFrame.reorder_levels(order, axis=0)
使用输入顺序重新排列索引层级。 不能降低或复制层级
参数
order: int列表 或 str的列表
代表新级别顺序的列表。通过数字(位置)或按键(标签)来参考水平。
axis:{0 或 'index',1 或 'columns'},默认 0
在哪里重新排序级别。
'''
df_ex.reorder_levels([2,0,1],axis=0).head() # 列表数字指代原来索引中的层
Big C D
Small c d c d
Other cat dog cat dog cat dog cat dog
Extra Upper Lower
alpha A a 3 6 -9 -6 -6 -2 0 9
beta A a -5 -3 3 -8 -3 -2 5 8
alpha A b -4 4 -1 0 7 -4 6 6
beta A b -9 9 -6 8 5 -2 -9 -8
alpha B a 0 -9 1 -6 2 9 -7 -9
这里只涉及 行或列索引 内部的交换
droplevel
方法df_ex.droplevel(1,axis=1)
Big C D
Other cat dog cat dog cat dog cat dog
Upper Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
beta -9 -5 -4 -3 -1 8 6 -5
b alpha 0 1 -8 -8 -2 0 -6 -3
beta 2 5 9 -9 5 -6 3 1
###属性的修改
rename_axis
可以对索引层的名字进行修改,常用的修改方式是传入字典的映射df_ex.rename_axis(index={'Upper':'Changed_row'},columns={'Other':'Changed_Col'}).head()
Big C D
Small c d c d
Changed_Col cat dog cat dog cat dog cat dog
Changed_row Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
rename
可以对索引的值进行修改,如果是多级索引需要指定层号(level)df_ex.rename(columns={'cat':'not_cat'},level=2).head()
Big C D
Small c d c d
Other not_cat dog not_cat dog not_cat dog not_cat dog
Upper Lower Extra
A a alpha 3 6 -9 -6 -6 -2 0 9
beta -5 -3 3 -8 -3 -2 5 8
b alpha -4 4 -1 0 7 -4 6 6
beta -9 9 -6 8 5 -2 -9 -8
B a alpha 0 -9 1 -6 2 9 -7 -9
也可以给**rename
传入函数**,其输入的值就是索引
df_ex.rename(index=lambda x:str.upper(x),level=2).head()
Big C D
Small c d c d
Other cat dog cat dog cat dog cat dog
Upper Lower Extra
A a ALPHA 3 6 -9 -6 -6 -2 0 9
BETA -5 -3 3 -8 -3 -2 5 8
b ALPHA -4 4 -1 0 7 -4 6 6
BETA -9 9 -6 8 5 -2 -9 -8
B a ALPHA 0 -9 1 -6 2 9 -7 -9
对于整个索引的元素替换,可以利用迭代器实现
'''
iter():生成迭代器
next() 返回迭代器的下一个项目
next() 函数要和生成迭代器的 iter() 函数一起使用
'''
new_values = iter(list('abcdefgh'))
df_ex.rename(index=lambda x:next(new_values),level=2)
Big C D
Small c d c d
Other cat dog cat dog cat dog cat dog
Upper Lower Extra
A a a 3 6 -9 -6 -6 -2 0 9
b -5 -3 3 -8 -3 -2 5 8
b c -4 4 -1 0 7 -4 6 6
d -9 9 -6 8 5 -2 -9 -8
B a e 0 -9 1 -6 2 9 -7 -9
f -9 -5 -4 -3 -1 8 6 -5
b g 0 1 -8 -8 -2 0 -6 -3
h 2 5 9 -9 5 -6 3 1
map
达到更改索引值
它是定义在 Index
上的方法
它传入的不是层的标量值,而是直接传入索引的元组
df_temp = df_ex.copy()
new_idx = df_temp.index.map(lambda x: (x[0],x[1],str.upper(x[2])))
print(new_idx)
#Python upper() 方法将字符串中的小写字母转为大写字母。
#把index放进map里面运行
df_temp.index = new_idx
df_temp.head()
MultiIndex([('A', 'a', 'ALPHA'),
('A', 'a', 'BETA'),
('A', 'b', 'ALPHA'),
('A', 'b', 'BETA'),
('B', 'a', 'ALPHA'),
('B', 'a', 'BETA'),
('B', 'b', 'ALPHA'),
('B', 'b', 'BETA')],
names=['Upper', 'Lower', 'Extra'])
Big C D
Small c d c d
Other cat dog cat dog cat dog cat dog
Upper Lower Extra
A a ALPHA 3 6 -9 -6 -6 -2 0 9
BETA -5 -3 3 -8 -3 -2 5 8
b ALPHA -4 4 -1 0 7 -4 6 6
BETA -9 9 -6 8 5 -2 -9 -8
B a ALPHA 0 -9 1 -6 2 9 -7 -9
#构建新表便于学习
df_new = pd.DataFrame({'A':list('aacd'),'B':list('PQRT'),'C':[1,2,3,4]})
df_new
A | B | C | |
---|---|---|---|
0 | a | P | 1 |
1 | a | Q | 2 |
2 | c | R | 3 |
3 | d | T | 4 |
set_index
设置索引
主要参数是append
,表示是否保留原来的索引,直接把设定的索引添加到原来的索引内层
df_new.set_index('A')#直接把A列设置为索引层
B | C | |
---|---|---|
A | ||
a | P | 1 |
a | Q | 2 |
c | R | 3 |
d | T | 4 |
df_new.set_index('A', append=True)#列索引A被添加到内层
B | C | ||
---|---|---|---|
A | |||
0 | a | P | 1 |
1 | a | Q | 2 |
2 | c | R | 3 |
3 | d | T | 4 |
如果 想要添加索引的列 没有出现在其中,那么可以直接在参数中传入相应的 Series
my_index = pd.Series(list('WXYZ'), name='D')
df_new = df_new.set_index(['A', my_index])
#my_index 插入了列名为D的列
df_new
B | C | ||
---|---|---|---|
A | D | ||
a | W | P | 1 |
X | Q | 2 | |
c | Y | R | 3 |
d | Z | T | 4 |
reset_index
重设索引
主要参数是drop
,表示是否要把去掉的索引层丢弃,而不是添加到列中
df_new.reset_index(['D'])#没有丢弃去掉的索引,而是从第二层返回到了第一层
D | B | C | |
---|---|---|---|
A | |||
a | W | P | 1 |
a | X | Q | 2 |
c | Y | R | 3 |
d | Z | T | 4 |
df_new.reset_index(['D'], drop=True)#直接丢弃去掉的索引
B | C | |
---|---|---|
A | ||
a | P | 1 |
a | Q | 2 |
c | R | 3 |
d | T | 4 |
如果 reset_index()不加参数 ,就是重置dataframe的索引,由默认索引(0…,A…)代替
###变形
reindex
更改行索引
reindex_like
仿照传入的表索引作为自己的表索引
没有给出值的用**np.nan
**填充
reindex
df_reindex = pd.DataFrame({"Weight":[60,70,80],"Height":[176,180,179]},index=['1001','1003','1002'])
print('原表')
df_reindex
原表
Weight | Height | |
---|---|---|
1001 | 60 | 176 |
1003 | 70 | 180 |
1002 | 80 | 179 |
print('修改后')
df_reindex.reindex(index=['1001','1002','1003','1004'],columns=['Weight','Gender'])
修改后
Weight | Gender | |
---|---|---|
1001 | 60.0 | NaN |
1002 | 80.0 | NaN |
1003 | 70.0 | NaN |
1004 | NaN | NaN |
reindex_like
df_existed = pd.DataFrame(index=['1001','1002','1003','1004'],columns=['Weight','Gender'])
print('原表')
df_existed
原表
Weight | Gender | |
---|---|---|
1001 | NaN | NaN |
1002 | NaN | NaN |
1003 | NaN | NaN |
1004 | NaN | NaN |
print('修改后')
df_reindex.reindex_like(df_existed)
修改后
Weight | Gender | |
---|---|---|
1001 | 60.0 | NaN |
1002 | 80.0 | NaN |
1003 | 70.0 | NaN |
1004 | NaN | NaN |
###运算
经常会有一种利用集合运算来取出符合条件行的需求,对索引可以使用集合的运算
由于集合的元素是互异的,但是索引中可能有相同的元素,先用 unique
去重后再进行运算。
# 创建表
df_set_1 = pd.DataFrame([[0,1],[1,2],[3,4]],index = pd.Index(['a','b','a'],name='id1'))
df_set_2 = pd.DataFrame([[4,5],[2,6],[7,1]],index = pd.Index(['b','b','c'],name='id2'))
# 去重
id1, id2 = df_set_1.index.unique(), df_set_2.index.unique()
print(id1)
print(id2)
Index(['a', 'b'], dtype='object', name='id1')
Index(['b', 'c'], dtype='object', name='id2')
id1.intersection(id2)#交集
Index(['b'], dtype='object')
id1.union(id2)#并集
Index(['a', 'b', 'c'], dtype='object')
id1.difference(id2)#返回一个新的Index,其中Index不在给出元组里面
Index(['a'], dtype='object')
id1.symmetric_difference(id2)#返回两个index中不一样的元素
Index(['a', 'c'], dtype='object')
明确三个要素:分组依据 、 数据来源 、 操作及其返回结果
df.groupby(分组依据)[数据来源].使用操作
#读取表演示
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
df.head()
School | Grade | Name | Gender | Height | Weight | Transfer | Test_Number | Test_Date | Time_Record | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Shanghai Jiao Tong University | Freshman | Gaopeng Yang | Female | 158.9 | 46.0 | N | 1 | 2019/10/5 | 0:04:34 |
1 | Peking University | Freshman | Changqiang You | Male | 166.5 | 70.0 | N | 1 | 2019/9/4 | 0:04:20 |
2 | Shanghai Jiao Tong University | Senior | Mei Sun | Male | 188.9 | 89.0 | N | 2 | 2019/9/12 | 0:05:22 |
3 | Fudan University | Sophomore | Xiaojuan Sun | Female | NaN | 41.0 | N | 2 | 2020/1/3 | 0:04:08 |
4 | Fudan University | Sophomore | Gaojuan You | Male | 174.0 | 74.0 | N |
#按照性别统计身高中位数
df.groupby('Gender')['Height'].median()
Gender
Female 159.6
Male 173.4
Name: Height, dtype: float64
groupby
中传入相应列名构成的列表即可# 根据学校和性别进行分组
df.groupby(['School', 'Gender'])['Height'].mean()
School Gender
Fudan University Female 158.776923
Male 174.212500
Peking University Female 158.666667
Male 172.030000
Shanghai Jiao Tong University Female 159.122500
Male 176.760000
Tsinghua University Female 159.753333
Male 171.638889
Name: Height, dtype: float64
condition = df.Weight > df.Weight.mean()
df.groupby(condition)['Height'].mean()
Weight
False 159.034646
True 172.705357
Name: Height, dtype: float64
unique
值来分组,传入的序列都会被去重# 通过 drop_duplicates 就能知道具体的组类别
df[['School', 'Gender']].drop_duplicates()
School | Gender | |
---|---|---|
0 | Shanghai Jiao Tong University | Female |
1 | Peking University | Male |
2 | Shanghai Jiao Tong University | Male |
3 | Fudan University | Female |
4 | Fudan University | Male |
5 | Tsinghua University | Female |
9 | Peking University | Female |
16 | Tsinghua University | Male |
df.groupby([df['School'], df['Gender']])['Height'].mean()
#以上方去去重字段分组
School Gender
Fudan University Female 158.776923
Male 174.212500
Peking University Female 158.666667
Male 172.030000
Shanghai Jiao Tong University Female 159.122500
Male 176.760000
Tsinghua University Female 159.753333
Male 171.638889
Name: Height, dtype: float64
###Groupby对象
可以先将分组依据定义成对象
gb = df.groupby(['School', 'Grade'])
gb
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001C2A65BD420>
ngroups
属性获取分组个数gb.ngroups
16
groups
获取 组名映射到主索引列表 的字典res = gb.groups
res.keys()# 字典的值由于是索引,元素个数过多,此处只展示字典的键
dict_keys([('Fudan University', 'Freshman'), ('Fudan University', 'Junior'), ('Fudan University', 'Senior'), ('Fudan University', 'Sophomore'), ('Peking University', 'Freshman'), ('Peking University', 'Junior'), ('Peking University', 'Senior'), ('Peking University', 'Sophomore'), ('Shanghai Jiao Tong University', 'Freshman'), ('Shanghai Jiao Tong University', 'Junior'), ('Shanghai Jiao Tong University', 'Senior'), ('Shanghai Jiao Tong University', 'Sophomore'), ('Tsinghua University', 'Freshman'), ('Tsinghua University', 'Junior'), ('Tsinghua University', 'Senior'), ('Tsinghua University', 'Sophomore')])
size
统计每个组的元素个数(在DataFrame中是表长乘表宽)gb.size()
School Grade
Fudan University Freshman 9
Junior 12
Senior 11
Sophomore 8
Peking University Freshman 13
Junior 8
Senior 8
Sophomore 5
Shanghai Jiao Tong University Freshman 13
Junior 17
Senior 22
Sophomore 5
Tsinghua University Freshman 17
Junior 22
Senior 14
Sophomore 16
dtype: int64
get_group
直接获取所在组对应的行,必须给出组的具体名字gb.get_group(('Peking University', 'Freshman'))
School | Grade | Name | Gender | Height | Weight | Transfer | Test_Number | Test_Date | Time_Record | |
---|---|---|---|---|---|---|---|---|---|---|
1 | Peking University | Freshman | Changqiang You | Male | 166.5 | 70.0 | N | 1 | 2019/9/4 | 0:04:20 |
32 | Peking University | Freshman | Gaopeng Shi | Female | 162.9 | 48.0 | N | 1 | 2019/9/12 | 0:04:58 |
35 | Peking University | Freshman | Gaoli Zhao | Male | 175.4 | 78.0 | N | 2 | 2019/10/8 | 0:03:32 |
36 | Peking University | Freshman | Xiaojuan Qin | Male | NaN | 79.0 | Y | 1 | 2019/12/10 | 0:04:10 |
38 | Peking University | Freshman | Qiang Han | Male | 185.3 | 87.0 | N | 3 | 2020/1/7 | 0:03:58 |
45 | Peking University | Freshman | Quan Chu | Female | 154.7 | 43.0 | N | 1 | 2019/11/28 | 0:04:47 |
54 | Peking University | Freshman | Xiaojuan Chu | Male | 162.4 | 58.0 | Y | 3 | 2019/11/29 | 0:03:42 |
57 | Peking University | Freshman | Changquan Chu | Female | 159.6 | 45.0 | N | 2 | 2019/12/9 | 0:04:18 |
88 | Peking University | Freshman | Xiaopeng Han | Female | 164.1 | 53.0 | N | 1 | 2019/12/18 | 0:05:20 |
96 | Peking University | Freshman | Changmei Feng | Female | 163.8 | 56.0 | N | 3 | 2019/11/8 | 0:04:41 |
99 | Peking University | Freshman | Changpeng Zhao | Male | 181.3 | 83.0 | N | 2 | 2019/10/24 | 0:04:08 |
140 | Peking University | Freshman | Qiang Zhang | Female | 152.7 | 43.0 | N | 1 | 2019/11/30 | 0:05:27 |
185 | Peking University | Freshman | Chunmei Wang | Female | 151.2 | 43.0 | N | 2 | 2019/12/10 | 0:04:24 |
内置聚合函数
max/min/mean/median/count/all/any/idxmax/idxmin
mad/nunique/skew/quantile/sum/std/var/sem/size/prod
gb = df.groupby('Gender')['Height']
quantile
给定数据的四分位数'''
所谓四分位数;即把数值由小到大排列并分成四等份,处于三个分割点位置的数值就是四分位数。
第1四分位数 (Q1),又称“较小四分位数”,等于该样本中所有数值由小到大排列后第25%的数字。
第2四分位数 (Q2),又称“中位数”,等于该样本中所有数值由小到大排列后第50%的数字。
第3四分位数 (Q3),又称“较大四分位数”,等于该样本中所有数值由小到大排列后第75%的数字。
'''
gb.quantile(0.95)#给定数据(数组元素)的分位数
gb = df.groupby('Gender')[['Height', 'Weight']]
gb.max()
Height Weight
Gender
Female 170.2 63.0
Male 193.9 89.0
groupby对象必须聚合后才会输出DataFrame
传入函数并运行的是数据源
使用多个函数
当使用多个聚合函数时,需要用列表的形式把内置聚合函数对应的字符串传入,先前提到的所有字符串都是合法的
gb.agg(['sum', 'idxmax', 'skew'])
Height Weight
sum idxmax skew sum idxmax skew
Gender
Female 21014.0 28 -0.219253 6469.0 28 -0.268482
Male 8854.9 193 0.437535 3929.0 2 -0.332393
从结果看,此时列索引为多级索引,第一层为数据源,第二层为使用的聚合方法,分别逐一队列使用聚合,因此结果为6列
对特定的列使用特定的聚合函数
通过构造字典传入 agg 中实现
列名为键,聚合字符串或字符串列表为值
gb.agg({'Height':['mean','max'], 'Weight':'count'})#列名为键,聚合字符串为值,但是这里只是数据来源,不是分组依据,还是对性别进行分组
Height Weight
mean max count
Gender
Female 159.19697 170.2 135
Male 173.62549 193.9 54
自定义函数
必须注意传入函数的参数是之前数据源中的列,逐列进行计算
gb.agg(lambda x: x.mean()-x.min())
Height Weight
Gender
Female 13.79697 13.918519
Male 17.92549 21.759259
由于传入的是列,因此列上的方法和属性都是可以在函数中使用的,只需保证返回值是标量即可
def my_func(s):#传入的是列
res = 'High'
if s.mean() <= df[s.name].mean():
res = 'Low'
return res
gb.agg(my_func)
Height Weight
Gender
Female Low Low
Male High High
只需将上述函数的位置改写成元组,元组第一个元素为新名字,第二个位置为原来的函数,也可以使用聚合字符串和自定义函数
gb.agg([('range', lambda x: x.max()-x.min()),
('my_sum', 'sum')])
Height Weight
range my_sum range my_sum
Gender
Female 24.8 21014.0 29.0 6469.0
Male 38.2 8854.9 38.0 3929.0
gb.agg({'Height': [('my_func', my_func), 'sum'],
'Weight': lambda x:x.max()})
#Height对应两个聚合的元素
Height Weight
my_func sum <lambda>
Gender
Female Low 21014.0 63.0
Male High 8854.9 89.0
gb.agg([('my_sum', 'sum')])#必须加中括号
Height Weight
my_sum my_sum
Gender
Female 21014.0 6469.0
Male 8854.9 3929.0
gb.agg({'Height': [('my_func', my_func), 'sum'],
'Weight': [('range', lambda x:x.max())]})
Height Weight
my_func sum range
Gender
Female Low 21014.0 63.0
Male High 8854.9 89.0
#初始化
df = pd.read_csv(
'C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
gb = df.groupby('Gender')[['Height', 'Weight']]
传入的是数据源(与agg相同),按照列进行计算,且不能通过传入字典来对指定列使用特定的变换,运行完成后将其给DataFrame
填充
最常用的内置变换函数是累计函数:
cumcount / cumsum / cumprod / cummax / cummin
transform方法与这些是一样的
gb.cummax().head()#返回一个DataFrame或Series轴上的累积最大值
Height Weight
0 158.9 46.0
1 166.5 70.0
2 188.9 89.0
3 NaN 46.0
4 188.9 89.0
参数:
'''
DataFrameGroupBy.transform(func,*args,engine = None,engine_kwargs = None,** kwargs)
func:函数
*args:传入函数从参数
engine:引擎 默认None
'cython':通过 cython 的 C 扩展运行函数。
'numba': 通过从 numba.JIT 编译的代码运行函数。
None:默认为'cython'或全局设置compute.use_numba
engine_kwargs字典,默认None
对于'cython'引擎,不接受engine_kwargs
如果engine默认,那就不能接收字典
对于'numba'引擎,引擎可以接受nopython,nogil 和parallel字典键。
这些值必须是True或 False。引擎 的默认值engine_kwargs是并将应用
于函数'numba'{'nopython': True, 'nogil': False, 'parallel':
False}
'''
示例:
gb.transform(lambda x: (x-x.mean())/x.std()).head()
Height Weight
0 -0.058760 -0.354888
1 -1.010925 -0.355000
2 2.167063 2.089498
3 NaN -1.279789
4 0.053133 0.159631
transform
只能返回同长度的序列,实际上也可以返回标量(函数运行后返回单个值),这会使得结果会被广播道整个组gb.transform('mean').head() # 传入返回标量的函数也是可以的
#因为mean是平均值函数返回的是单值,在transform的作用下就会广播成每组求平均值后返回
df = pd.read_csv(
'C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
gb = df.groupby('Gender')[['Height', 'Weight']]
transform:
transform = gb.transform('mean')
Height Weight
0 159.19697 47.918519
1 173.62549 72.759259
2 173.62549 72.759259
3 159.19697 47.918519
4 173.62549 72.759259
'''
数据来源是['Height', 'Weight'],但是结果没有给出分组依据,而是把聚合结果直接填充到Gender对应的位置上(Female,Male对应的行填充了对应的值)
'''
agg:
agg = gb.agg('mean')
Height Weight
Gender
Female 159.19697 47.918519
Male 173.62549 72.759259
'''
直接返回分组结果,不会把值进行每行填充,所以它也不具备直接添加进源DataFrame的功能
'''
agg不具备直接添加进源表的功能,transform可以直接添加
groupby对象中定义了**filter
函数进行组的筛选**,传入的参数也是数据源,参数中的函数只允许返回布尔值
参数:
'''
DataFrameGroupBy.filter(func, dropna=True, *args, **kwargs)
返回DataFrame的副本,不包括过滤的元素。如果组中的元素为False,则会过滤。
参数:
func:函数,返回True/False
dropna:丢弃为False的组。默认为True
返回:DataFrame
'''
gb.filter(lambda x: x.shape[0] > 100).head()
#####apply
在设计上, apply 的自定义函数传入参数与 filter
完全一致,只不过后者只允许返回布尔值
# 人体的BMI指标
def BMI(x):
Height = x['Height']/100
Weight = x['Weight']
BMI_value = Weight/Height**2
return BMI_value.mean()
gb.apply(BMI)
apply函数根据返回值情况来输出不同的结果
1:返回标量
得到结果的是 Series
,索引与 agg
的结果一致
gb = df.groupby(['Gender','Test_Number'])[['Height','Weight']]
gb.apply(lambda x: 0)
Gender Test_Number
Female 1 0
2 0
3 0
Male 1 0
2 0
3 0
dtype: int64
gb.apply(lambda x: [0, 0]) # 虽然是列表,但是作为返回值仍然看作标量
Gender Test_Number
Female 1 [0, 0]
2 [0, 0]
3 [0, 0]
Male 1 [0, 0]
2 [0, 0]
3 [0, 0]
dtype: object
返回Series
得到结果是 DataFrame
,行索引与标量情况一致,列索引为 Series 的索引
gb.apply(lambda x: pd.Series([0,0],index=['a','b']))
a b
Gender Test_Number
Female 1 0 0
2 0 0
3 0 0
Male 1 0 0
2 0 0
3 0 0
返回DataFrame
得到结果是 DataFrame
,行索引最内层在每个组原先 agg 的结果索引上,再加一层返回的 DataFrame 行索引,同时分组结果 DataFrame 的列索引和返回的 DataFrame 列索引一致
gb.apply(lambda x: pd.DataFrame(np.ones((2,2)),index = ['a','b'],columns=pd.Index([('w','x'),('y','z')])))
w y
x z
Gender Test_Number
Female 1 a 1.0 1.0
b 1.0 1.0
2 a 1.0 1.0
b 1.0 1.0
3 a 1.0 1.0
b 1.0 1.0
Male 1 a 1.0 1.0
b 1.0 1.0
2 a 1.0 1.0
b 1.0 1.0
3 a 1.0 1.0
b 1.0 1.0
最后需要强调的是, apply 函数的灵活性是以牺牲一定性能为代价换得的,除非需要使用跨列处理的分组处理,否则应当使用其他专门设计的 groupby 对象方法,否则在性能上会存在较大的差距。同时,在使用聚合函数和变换函数时,也应当优先使用内置函数,它们经过了高度的性能优化,一般而言在速度上都会快于用自定义函数来实现。
所有的变形都是Excel的数据透视表
概念:
一个表把数据存入列中,他就是关于列的长表
一个表把数据作为列名,列中的元素是与这个列相关的特征数值,他就是关于列名的宽表
a = pd.DataFrame({'Gender':['F','F','M','M'],'Height':[163, 160, 175, 180]})#长表
print(a)
pd.DataFrame({'Height: F':[163, 160],'Height: M':[175, 180]})#宽表
Gender Height
0 F 163
1 F 160
2 M 175
3 M 180
Height: F Height: M
0 163 175
1 160 180
显然这两张表从信息上是完全等价的,它们包含相同的身高统计数值,只是这些数值的呈现方式不同,而其呈现方式主要又与性别一列选择的布局模式有关,即到底是以 long 的状态存储还是以 wide 的状态存储。因此, pandas 针对此类长宽表的变形操作设计了一些有关的变形函数。
#####长表变宽表
pivot
长表变宽表参数:
'''
DataFrame.pivot(index=None, columns=None, values=None)
根据列值重塑数据(生成一个“透视”表)。 使用来自指定索引/列的唯一值来形成结果DataFrame的轴,此函数不支持数据聚合
参数:
index:str 或 object 或 list(str) 可选
用作于新表的行索引。如果没有,则使用现有索引
columns:str 或 object 或 list(str)
用作于新表的列索引
values:str 或 object 或 前面的列表 可选
用作于新表的值 如果没有指定,将使用所有剩余的列,并且结果将具有分层索引的列
return:返回重构的 DataFrame
'''
创建表便于学习
df = pd.DataFrame({'Class':[1,1,2,2],'Name':['San Zhang','San Zhang','Si Li','Si Li'],'Subject':['Chinese','Math','Chinese','Math'],'Grade':[80,75,90,85]})
df
Class Name Subject Grade
0 1 San Zhang Chinese 80
1 1 San Zhang Math 75
2 2 Si Li Chinese 90
3 2 Si Li Math 85
变形最重要的三个要素:
变形后的行索引、需要转到列索引的列,以及这些列和行索引对应的数值
他们分别对应了pivot
方法中
index,columns,values
参数
列索引是column
对应的列的 唯一值(unique)
行索引是index
对应的列的 唯一值(unique)
而values
对应了想要展示的数值列
df.pivot(index='Name', columns='Subject', values='Grade')
Subject Chinese Math
Name
San Zhang 80 75
Si Li 90 85
由于pivot进行变形操作要满足唯一性要求,行列对应的值必须唯一,所以行列的组合必须是唯一的
df.loc[1, 'Subject'] = 'Chinese'#如果把列索引的Subject改成与值相同的Chinese就会报错
try:
df.pivot(index='Name',columns='Subject',values='Grade')
except Exception as e:
Err_Msg = e
Err_Msg
ValueError('Index contains duplicate entries, cannot reshape')
pivot
相关的三个参数允许传入列表,这也意味着会返回多级索引
创建表便于学习
df = pd.DataFrame({'Class':[1, 1, 2, 2, 1, 1, 2, 2],'Name':['San Zhang', 'San Zhang', 'Si Li', 'Si Li','San Zhang', 'San Zhang', 'Si Li', 'Si Li'],'Examination': ['Mid', 'Final', 'Mid', 'Final', 'Mid', 'Final', 'Mid', 'Final'],'Subject':['Chinese', 'Chinese', 'Chinese', 'Chinese', 'Math', 'Math', 'Math', 'Math'],'Grade':[80, 75, 85, 65, 90, 85, 92, 88],'rank':[10, 15, 21, 15, 20, 7, 6, 2]})
df
Class Name Examination Subject Grade rank
0 1 San Zhang Mid Chinese 80 10
1 1 San Zhang Final Chinese 75 15
2 2 Si Li Mid Chinese 85 21
3 2 Si Li Final Chinese 65 15
4 1 San Zhang Mid Math 90 20
5 1 San Zhang Final Math 85 7
6 2 Si Li Mid Math 92 6
7 2 Si Li Final Math 88 2
示例:
pivot_multi = df.pivot(index = ['Class', 'Name'],
columns = ['Subject','Examination'],
values = ['Grade','rank'])
'''
这其实就是数据透视表,把行和列放进去,对应的就是值,但是必须是唯一值
'''
pivot_multi
Grade rank
Subject Chinese Math Chinese Math
Examination Mid Final Mid Final Mid Final Mid Final
Class Name
1 San Zhang 80 75 90 85 10 15 20 7
2 Si Li 85 65 92 88 21 15 6 2
根据唯一性原则,新表的行索引等价于对index中的多列使用drop_duplicates
去重,而**列索引长度为values中的元素乘以columns的唯一组合数量(**与index类型)
pivot_table
不依赖唯一性条件的 长表变宽表
pivot
的使用依赖于唯一性条件,那如果不满足唯一性条件,那么必须通过聚合操作使得相同行列组合对应的多个值变为一个值。
创建表方便学习
df = pd.DataFrame({'Name':['San Zhang', 'San Zhang','San Zhang', 'San Zhang','Si Li', 'Si Li', 'Si Li', 'Si Li'],'Subject':['Chinese', 'Chinese', 'Math', 'Math','Chinese', 'Chinese', 'Math', 'Math'],'Grade':[80, 90, 100, 90, 70, 80, 85, 95]})
df
Name Subject Grade
0 San Zhang Chinese 80
1 San Zhang Chinese 90
2 San Zhang Math 100
3 San Zhang Math 90
4 Si Li Chinese 70
5 Si Li Chinese 80
6 Si Li Math 85
7 Si Li Math 95
参数:
'''
DataFrame.pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False, sort=True)
创建一个电子表格风格的数据透视表作为DataFrame,数据透视表中的层将存储在结果DataFrame的索引和列上的MultiIndex对象(分层索引)中
参数:
values:需要被聚合的列,可选
index:column 或 Grouper 或 array 或 上个列表
如果传入一个数组,它必须与数据的长度相同。 列表可以包含任何其他类型(
列表除外)。 在透视表索引上进行分组的键。 如果传入一个数组,则以与列值
相同的方式使用它
columns:column 或 Grouper 或 array 或 上个列表
如果传入一个数组,它必须与数据的长度相同。 列表可以包含任何其他类型(
列表除外)。 在透视表列上进行分组的键。 如果传入一个数组,则以与列值
相同的方式使用它
aggfunc:function 或 list(functions) 或 dict 默认为 numpy.mean
如果传递了函数列表,那么结果透视表将有层次结构列,它们的顶层是函数名(
从函数对象本身推断出来)。如果传递了dict,键是column to aggregate,值
是function或函数列表
fill_value:标量 默认NULL
用于替换缺失值的值(在结果数据透视表中,聚合后)
margins:布尔值,默认为 False
不要包括其条目全部为 NaN 的列。
margins_name:str, 默认 ‘All’
当边距为True时,包含总计的行/列的名称
observed:布尔值, 默认 False
这只适用于任何组别属于分类的情况。
如果为True:只显示分类组别的观察值。
如果为False:显示分类组别的所有值。
sortbool:布尔值, 默认 True
指定结果是否应该排序
return DataFrame
一个Excel风格的数据透视表
'''
最常用的参数就是 aggfunc
指定聚合
df.pivot_table(index = 'Name',
columns = 'Subject',
values = 'Grade',
aggfunc = 'mean')
Subject Chinese Math
Name
San Zhang 85 95
Si Li 75 90
这里aggfunc
传入的参数包含所有的聚合字符串,此外还可以传入以序列为输入 标量为输出的聚合函数来实现自定义操作
df.pivot_table(index = 'Name',
columns = 'Subject',
values = 'Grade',
aggfunc = lambda x:x.mean())
Subject Chinese Math
Name
San Zhang 85 95
Si Li 75 90
pivot_table具有边际汇总的功能,可以通过设置 margins=True
来实现,其中边际聚合方式与 aggfunc 中给出的聚合方法一致
边际汇总就是把所有值算出来之后再进行给出聚合字符串再算一遍
df.pivot_table(index = 'Name',
columns = 'Subject',
values = 'Grade',
aggfunc='mean',
margins=True)
Subject Chinese Math All
Name
San Zhang 85 95.0 90.00
Si Li 75 90.0 82.50
All 80 92.5 86.25
melt
宽表转长表创建表以便学习
df = pd.DataFrame({'Class':[1,2],
'Name':['San Zhang', 'Si Li'],
'Chinese':[80, 90],
'Math':[80, 75]})
df
Class Name Chinese Math
0 1 San Zhang 80 80
1 2 Si Li 90 75
参数:
'''
DataFrame.melt(id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None, ignore_index=True)
将DataFrame从宽格式Unpivot到长格式,可以选择保留标识符集。
参数:
id_vars:元组、列表或 ndarray,可选
用作标识符变量的列。
value_vars:元组、列表或 ndarray,可选
要取消透视的列。如果未指定,则使用所有未设置为id_vars的列。
var_name:标量
用于“变量”列的名称。如果 None 它使用 frame.columns.name或“变量”。
value_name:标量,默认“value”
用于“value”列的名称。
col_level: int 或 str,可选
如果列是 MultiIndex,则使用此级别来融化。
ignore_index:布尔值,默认为 True
如果为 True,则忽略原始索引。
如果为 False,则保留原始索引。
索引标签将根据需要重复。
Returns DataFrame
没有透视DataFrame.
'''
示例:
df_melted = df.melt(id_vars = ['Class', 'Name'],#需要保留不动的列
value_vars = ['Chinese', 'Math'],#要动的列(把这个值翻转过来,从字段到数值)
var_name = 'Subject',#反转字段后的列名(字段成为值之后需要给出新字段)
value_name = 'Grade')#因为反转了字段,字段下面的值也有反转,所以这个参数是反转后值的字段
#保留不动的列根据反转的字段来复制多少个
df_melted
Class Name Subject Grade
0 1 San Zhang Chinese 80
1 2 Si Li Chinese 90
2 1 San Zhang Math 80
3 2 Si Li Math 75
melt
和pivot
是一组互逆过程,那么就一定可以通过pivot操作把
df_melted转回df的形式
df_unmelted = df_melted.pivot(index = ['Class', 'Name'],
columns='Subject',
values='Grade')
df_unmelted # 下面需要恢复索引,并且重命名列索引名称
Subject Chinese Math
Class Name
1 San Zhang 80 80
2 Si Li 90 75
df_unmelted = df_unmelted.reset_index().rename_axis(columns={'Subject':''})
df_unmelted.equals(df)#测试两个对象是否包含相同的元素
True
DataFrame.equals
'''
DataFrame.equals(other)
测试两个对象是否包含相同的元素
此功能允许将两个 Series 或 DataFrame 相互比较,
以查看它们是否具有相同的形状和元素。同一位置的 NaN 被认为是相等的。
行/列索引不需要具有相同的类型,只要值被认为是相等的。对应的列必须具有相同的 dtype。
参数
other:Series 或者 DataFrame
要与第一个进行比较的其他 Series 或 DataFrame。
return 布尔
如果两个对象中的所有元素都相同,则为 True,否则为 False。
'''
wide_to_long
宽表转长表
创建表以便学习
df = pd.DataFrame({'Class':[1,2],'Name':['San Zhang', 'Si Li'],'Chinese_Mid':[80, 75], 'Math_Mid':[90, 85],'Chinese_Final':[80, 75], 'Math_Final':[90, 85]})
df
Class Name Chinese_Mid Math_Mid Chinese_Final Math_Final
0 1 San Zhang 80 90 80 90
1 2 Si Li 75 85 75 85
参数:
'''
pandas.wide_to_long(df, stubnames, i, j, sep='', suffix='\\d+')
参数
df:需要更改的DataFrame
stubnames:需要拆分字段的前字段
i:需要保留的字段
j:需要拆分字段的后字段的列名
sep:拆分的字段的拆分符号
suffix:拆分符号后的正则匹配
'''
示例1:
pd.wide_to_long(df,
stubnames=['Chinese', 'Math'],
i = ['Class', 'Name'],
j='Examination',
sep='_',
suffix='.+')
Chinese Math
Class Name Examination
1 San Zhang Mid 80 90
Final 80 90
2 Si Li Mid 75 85
Final 75 85
示例2:
res = pivot_multi.copy()
res.columns = res.columns.map(lambda x:'_'.join(x))
res = res.reset_index()
res = pd.wide_to_long(res, stubnames=['Grade', 'rank'],
i = ['Class', 'Name'],
j = 'Subject_Examination',
sep = '_',
suffix = '.+')
res
Grade rank
Class Name Subject_Examination
1 San Zhang Chinese_Mid 80 10
Chinese_Final 75 15
Math_Mid 90 20
Math_Final 85 7
2 Si Li Chinese_Mid 85 21
Chinese_Final 65 15
Math_Mid 92 6
Math_Final 88 2
str.join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。
示例3:
res = res.reset_index()
res[['Subject', 'Examination']] = res[
'Subject_Examination'].str.split('_', expand=True)
res = res[['Class', 'Name', 'Examination',
'Subject', 'Grade', 'rank']].sort_values('Subject')
res = res.reset_index(drop=True)
res
Class Name Examination Subject Grade rank
0 1 San Zhang Mid Chinese 80 10
1 1 San Zhang Final Chinese 75 15
2 2 Si Li Mid Chinese 85 21
3 2 Si Li Final Chinese 65 15
4 1 San Zhang Mid Math 90 20
5 1 San Zhang Final Math 85 7
6 2 Si Li Mid Math 92 6
7 2 Si Li Final Math 88 2
stack
参数:
'''
DataFrame.stack(level=- 1, dropna=True)
将列中的规定层堆叠到索引。
返回与当前 DataFrame 相比具有一个或多个新的最内层的多级索引的重构 DataFrame 或 Series。通过旋转当前数据框的列来创建新的最内层
- 如果列有一个级别,则输出是一个系列;
- 如果列有多个级别,则新的索引级别是从规定的级别获取的,
并且输出是一个 DataFrame。
参数
level:int,str,list,默认 -1
从列轴堆叠到索引轴的级别,定义为一个索引或标签,或者索引或标签的列表。
dropna:布尔值,默认为 True
是否删除结果帧/系列中缺少值的行。将列级别堆叠到索引轴上可以创建原始数据帧中缺少的索引和列值的组合。
return:DataFrame or Series
'''
unstack
参数:
'''
DataFrame.unstack(level=- 1, fill_value=None)
枢轴(必须是分层的)索引标签的级别。
返回具有新级别列标签的 DataFrame,其最内层由枢轴索引标签组成。
参数
level:int、str 或这些列表,默认 -1(最后一级)
要解栈的索引级别,可以传递级别名称。
fill_value:int、str 或 dict
如果unstack产生缺失值,则将NaN 替换为该值。
return:DataFrame or Series
'''
之前提到了利用swaplevel
或reorder_levels
进行索引内部的层交换,stack/unstack
就是行列索引交换,由于这种交换带来了DataFrame维度上的变化,因此属于变形操作
df = pd.DataFrame(np.ones((4,2)),
index = pd.Index([('A', 'cat', 'big'),
('A', 'dog', 'small'),
('B', 'cat', 'big'),
('B', 'dog', 'small')]),
columns=['col_1', 'col_2'])
#可能会产生缺失值
df
col_1 col_2
A cat big 1.0 1.0
dog small 1.0 1.0
B cat big 1.0 1.0
dog small 1.0 1.0
unstack
主要的参数是移动的层号,默认转化最内层,移动到列索引的最内层,同时支持同时转化多个层
df.unstack(2)#将最内层转化了,这里也可以写-1,他把第三个行索引转到列索引了
col_1 col_2
big small big small
A cat 1.0 NaN 1.0 NaN
dog NaN 1.0 NaN 1.0
B cat 1.0 NaN 1.0 NaN
dog NaN 1.0 NaN 1.0
df.unstack([0,2])#把第0层和第2层转到列索引(由行索引起步)
col_1 col_2
A B A B
big small big small big small big small
cat 1.0 NaN 1.0 NaN 1.0 NaN 1.0 NaN
dog NaN 1.0 NaN 1.0 NaN 1.0 NaN 1.0
pivot
中的唯一性要求,在stack/unstack
中必须保证被转为列索引的行索引层和被保留的行索引层构成的组合是唯一的,,破坏了唯一性,那么就会报错my_index = df.index.to_list()
my_index[1] = my_index[0]
df.index = pd.Index(my_index)
df
col_1 col_2
A cat big 1.0 1.0
big 1.0 1.0
B cat big 1.0 1.0
dog small 1.0 1.0
try:
df.unstack()
except Exception as e:
Err_Msg = e
Err_Msg
ValueError('Index contains duplicate entries, cannot reshape')
df = pd.DataFrame(np.ones((4,2)),
index = pd.Index([('A', 'cat', 'big'),
('A', 'dog', 'small'),
('B', 'cat', 'big'),
('B', 'dog', 'small')]),
columns=['index_1', 'index_2']).T
df
A B
cat dog cat dog
big small big small
index_1 1.0 1.0 1.0 1.0
index_2 1.0 1.0 1.0 1.0
df.stack()
A B
cat dog cat dog
index_1 big 1.0 NaN 1.0 NaN
small NaN 1.0 NaN 1.0
index_2 big 1.0 NaN 1.0 NaN
small NaN 1.0 NaN 1.0
unstack把行索引转到列索引 , stack把列索引转到行索引
聚合与变形的关系
在上面介绍的所有函数中,除了带有聚合效果的 pivot_table 以外,所有的函数在变形前后并不会带来 values 个数的改变,只是这些值在呈现的形式上发生了变化
读取表便于学习:
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
df.head()
School Grade Name Gender Height Weight Transfer Test_Number Test_Date Time_Record
0 Shanghai Jiao Tong University Freshman Gaopeng Yang Female 158.9 46.0 N 1 2019/10/5 0:04:34
1 Peking University Freshman Changqiang You Male 166.5 70.0 N 1 2019/9/4 0:04:20
2 Shanghai Jiao Tong University Senior Mei Sun Male 188.9 89.0 N 2 2019/9/12 0:05:22
3 Fudan University Sophomore Xiaojuan Sun Female NaN 41.0 N 2 2020/1/3 0:04:08
4 Fudan University Sophomore Gaojuan You Male 174.0 74.0 N 2 2019/11/6 0:05:22
crosstab
交叉两个或多个序列成为新的表参数:
'''
pandas.crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)
计算两个(或更多)因子的简单交叉表。默认情况下,除非传递值数组和聚合函数,否则会计算因子的频率表。
参数
index:array-like, Series, or list of arrays/Series
行中分组依据的值。
column:array-like, Series, or list of arrays/Series
列中分组依据的值。
values:数组,可选
根据因子聚合的值数组。需要指定aggfunc。
rownames,默认无
如果通过,则必须匹配通过的行数组数。
colnames序列,默认无
如果通过,则必须匹配通过的列数组的数量。
aggfunc函数,可选
如果指定,则还需要指定值。
margins布尔值,默认为 False
添加行/列边距(小计)。
margins_name str,默认“全部”
当边距为 True 时将包含总计的行/列的名称。
dropna布尔值,默认为 True
不要包括其条目全部为 NaN 的列。
normalize bool, {'all', 'index', 'columns'} 或 {0,1},默认 False
通过将所有值除以值的总和进行归一化。
- 如果通过 'all' 或True,将对所有值进行标准化。
- 如果通过“索引”将在每一行上标准化。
- 如果通过“列”将在每一列上进行规范化。
- 如果 margins 是True,也将规范化边距值。
'''
示例:
pd.crosstab(index = df.School, columns = df.Transfer)
Transfer N Y
School
Fudan University 38 1
Peking University 28 2
Shanghai Jiao Tong University 53 0
Tsinghua University 62 4
如果给出了values
参数,就必须指定aggfunc
聚合参数
pd.crosstab(index = df.School, columns = df.Transfer,
values = [0]*df.shape[0], aggfunc = 'count')#[0]*df.shape[0]只是把列表0乘以df.shape[0]就是第一维度,那这个表达式表示有第一维度的几个0
Transfer N Y
School
Fudan University 38.0 1.0
Peking University 28.0 2.0
Shanghai Jiao Tong University 53.0 NaN
Tsinghua University 62.0 4.0
可以使用pivot_table
进行等价操作,由于这里统计的是组合的频数,所以values
参数无论传入那一个列都不会影响最后的结果
df.pivot_table(index = 'School',
columns = 'Transfer',
values = 'Name',
aggfunc = 'count')
Transfer N Y
School
Fudan University 38.0 1.0
Peking University 28.0 2.0
Shanghai Jiao Tong University 53.0 NaN
Tsinghua University 62.0 4.0
crosstab
的对应位置传入的是具体序列,而pivot_table
传入的是被调用表的对应名字,若传入序列对应的值则会报错
explode
展开表
explode参数能够对某一列的元素进行纵向的展开,被展开的单元格必须存储为 **list, tuple, Series, np.ndarray
**中的类型
创建表以便学习
df_ex = pd.DataFrame({'A': [[1, 2],'my_str',{1, 2},pd.Series([3, 4])], 'B': 1})
df_ex
A B
0 [1, 2] 1
1 my_str 1
2 {1, 2} 1
3 0 3 1 4 dtype: int64 1
示例1:
df_ex.explode('A')#以A列把所有的拆分
A B
0 1 1
0 2 1
1 my_str 1
2 1 1
2 2 1
3 3 1
3 4 1
get_dummies
把类别特征转化为指示变量#对年级一列转为指示变量,属于某一个年级的对应列标记为1,否则为0:
pd.get_dummies(df.Grade).head()
Freshman Junior Senior Sophomore
0 1 0 0 0
1 1 0 0 0
2 0 0 1 0
3 0 0 0 1
4 0 0 0 1
##连接
pandas的表连接与SQL的表连接相同,提供how
参数来代表连接形式,分别为**左连接left,右连接right,内连接inner,外连接outer
**
merge()
参数:
'''
DataFrame.merge(right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
将DataFrame或命名的 Series 对象与数据库样式的连接合并。
命名的 Series 对象被视为具有单个命名列的 DataFrame。
连接是在 列或索引 上完成的。如果在列上连接列,DataFrame 索引将被 '忽略' 。
否则,如果加入索引上的索引或列上的索引,则索引将被传递。执行交叉合并时,不允许合并列规范。
warning:
如果两个键列都包含键为空值的行,则这些行将相互匹配。这与通常的 SQL 连接行为不同,并可能导致意外结果
参数:
right:DataFrame 或 普通的Series
how:连接方式{‘left’, ‘right’, ‘outer’, ‘inner’, ‘cross’}, 默认 ‘inner’
- left:仅使用左帧中的键,类似于 SQL 左外连接;保留密钥顺序。
- right:仅使用右框架中的键,类似于 SQL 右外连接;保留密钥顺序。
- 外部:使用来自两个帧的键并集,类似于 SQL 完全外部联接;按字典顺序对键进行排序。
- 内部:使用来自两个帧的键的交集,类似于 SQL 内部连接;保留左键的顺序。
- cross:从两个帧创建笛卡尔积,保留左键的顺序
on:标签 或 list
要连接的列或索引级别名称。 这些必须在两个 DataFrame 中都找到。
如果on为None并且没有在索引上合并,则默认为两个DataFrames中的列的交集。
left_on:标签 或 列表 或 数组
行列索引层级的名称连接到左DataFrame。 也可以是一个数
组或数组的列表长度的左DataFrame。 这些数组被当作列来处理。
right_on:标签 或 列表 或 数组
行列索引层级的名称连接到右DataFrame。也可以是一个数
组或数组列表的长度为正确的DataFrame。 这些数组被当作列来处理
left_index:布尔型 默认False
使用来自左DataFrame的索引作为连接键。 如果它是一个MultiIndex,
则其他DataFrame中的键的数量(索引或列的数量)必须与级别的数量匹配
right_index:布尔型 默认False
使用来自右DataFrame的索引作为连接键。 与left_index相同的注意事项
sort:布尔型 默认False
对结果DataFrame中的联接键按字典顺序排序。 如果为False,则连接键的顺序取决于连接类型(how关键字)
suffixes:列表 默认为 (“_x”, “_y”)
长度为2的序列,其中每个元素都是可选的字符串,指示要分别添加到左侧和右侧重叠列名的后缀。
传递None值而不是字符串来指示从左到右的列名应该保持原样,不带后缀。 至少有一个值不能为None
copy:布尔型 默认为 True
如果为False,尽可能避免复制
indicator:布尔型 或 str 默认值为 False
如果为True,则在输出DataFrame中添加一个名为“_merge”的列,该列包含关于每行源的信息。
通过提供一个字符串参数,可以给列一个不同的名称。 该列将有一个category类型的值为“left_only”,
用于观察其合并键只出现在左DataFrame,“right_only”用于观察其合并键只出现在右DataFrame,
如果观察的合并键在两个DataFrame中都发现,则为“both”。
validate: str 可选
如果指定,则检查merge是否为指定类型。
- " one_to_one "或" 1:1 ":检查合并键在左右数据集中是否唯一。
- " one_to_many "或" 1:m ":检查合并键是否唯一的左数据集。
- " many_to_one "或" m:1 ":检查合并键在右数据集中是否唯一。
- “many_to_many”或“m:m”:允许,但不进行检查。
return:DataFrame
合并了两个对象的DataFrame
'''
示例:
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Si Li','Wu Wang'],'Gender':['F','M']})
df1.merge(df2,on='Name',how='left')#依照Name列做左连接
Name Age Gender
0 San Zhang 20 NaN
1 Si Li 30 F
如果两个表中想要连接的列不具备相同的列名,可以通过 left_on
和 right_on
df1 = pd.DataFrame({'df1_name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'df2_name':['Si Li','Wu Wang'],'Gender':['F','M']})
df1.merge(df2,
left_on='df1_name',
right_on='df2_name',
how='left')
df1_name Age df2_name Gender
0 San Zhang 20 NaN NaN
1 Si Li 30 Si Li F
出现重复列名可用suffixes
参数指定
df1 = pd.DataFrame({'Name':['San Zhang'],'Grade':[70]})
df2 = pd.DataFrame({'Name':['San Zhang'],'Grade':[80]})
df1.merge(df2,
on='Name',
how='left',
suffixes=['_Chinese','_Math'])
Name Grade_Chinese Grade_Math
0 San Zhang 70 80
如果键不是唯一的,那么结果就会产生问题。举例中的行数很少,但如果实际数据中有几十万到上百万行的进行合并时,如果想要保证唯一性,除了用 duplicated 检查是否重复外, merge 中也提供了 validate 参数来检查连接的唯一性模式。这里共有三种模式,即一对一连接 1:1 ,一对多连接 1:m ,多对一连接 m:1 连接,第一个是指左右表的键都是唯一的,后面两个分别指左表键唯一和右表键唯一
join()
示例:
df1 = pd.DataFrame({'Age':[20,30]},index=pd.Series( ['San Zhang','Si Li'],name='Name'))
df2 = pd.DataFrame({'Gender':['F','M']},index=pd.Series(['Si Li','Wu Wang'],name='Name'))
df1.join(df2, how='left')
Age Gender
Name
San Zhang 20 NaN
Si Li 30 F
concat()
仍然关于索引连接,常用三个参数:axis,join,keys
分别表示拼接方向,连接形式,以及在新表中指示来自于哪一张旧表的名字意, join
和 keys
与之前提到的 join 函数和键的概念没有任何关系。
参数:
'''
pandas.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)
沿特定轴连接pandas对象,并沿a其他轴使用可选的设置逻辑。
还可以在连接轴上添加一层分层索引,如果标签在传递的轴号
上相同(或重叠),这可能很有用
参数
objs:Series 或 DataFrame 对象的序列或映射
如果传递了映射,则排序的键将用作键 参数,除非传递,在这
种情况下将选择值(见下文)。任何 None 对象都将被静默删除
,除非它们都是 None 在这种情况下将引发 ValueError 。
axis:{0/'index', 1/'columns'},默认 0
要连接的轴。
join:{'inner', 'outer'},默认 'outer'
如何处理其他轴(或轴)上的索引。
ignore_index:布尔值,默认为 False
如果为 True,则不要使用连接轴上的索引值。结果轴将标记为 0,
..., n - 1。如果您要连接对象,而连接轴没有有意义的索引信
息,这将非常有用。请注意,连接中仍然尊重其他轴上的索引值。
key:序列,默认无
如果通过了多个级别,则应包含元组。使用传递的键作为最外层构建层次索引。
level:列表,默认无
用于构造 MultiIndex 的特定级别(唯一值)。否则,它们将从密钥中推断出来。
mane:列表,默认无
生成的分层索引中的级别名称。
verify_integrity:bool,默认为 False
检查新的连接轴是否包含重复项。相对于实际的数据连接,这可能非常昂贵。
sort:布尔值,默认为 False
如果连接 为“外部”时未对齐,则对非连接轴进行排序。当已经保留了非串联轴的顺序时,这不起作用。join='inner'
在 1.0.0 版更改:默认情况下更改为不排序。
copy:bool,默认 True
如果为 False,则不要不必要地复制数据。
return object,objects
当沿着索引 ( axisSeries =0) 连接时, Series返回 a。当objs包含至少
一个 DataFrame时,DataFrame返回 a。当沿列连接时(axis=1),返回DataFramea 。
'''
默认状态下axis=0表示纵向连接两个表,常常用于多个样本的连接
默认状态下axis=1表示横向连接多个表,常用于多个字段或特征的拼接
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Wu Wang'], 'Age':[40]})
pd.concat([df1, df2])
Name Age
0 San Zhang 20
1 Si Li 30
0 Wu Wang 40
df2 = pd.DataFrame({'Grade':[80, 90]})
df3 = pd.DataFrame({'Gender':['M', 'F']})
pd.concat([df1, df2, df3], 1)
Name Age Grade Gender
0 San Zhang 20 80 M
1 Si Li 30 90 F
默认状态下join=outer
,表示保留所有列,并将不存在的值设置为缺失
df2 = pd.DataFrame({'Name':['Wu Wang'], 'Gender':['M']})
pd.concat([df1, df2])
Name Age Gender
0 San Zhang 20.0 NaN
1 Si Li 30.0 NaN
0 Wu Wang NaN M
df2 = pd.DataFrame({'Grade':[80, 90]}, index=[1, 2])
pd.concat([df1, df2], 1)# 1 是axis
Name Age Grade
0 San Zhang 20.0 NaN
1 Si Li 30.0 80.0
2 NaN NaN 90.0
pd.concat([df1, df2], axis=1, join='inner')
Name Age Grade
1 Si Li 30 80
当确认要使用多表连接的方向合并时,尤其是横向的合并,可以先用reset_index方法恢复默认整数索引再进行合并,防止出现由索引的误对起和重复索引的笛卡尔积带来的错误结果
key参数是可以标记生成表的数据来自那些表
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,21]})
df2 = pd.DataFrame({'Name':['Wu Wang'],'Age':[21]})
pd.concat([df1, df2], keys=['one', 'two'])#key是表明那些数据来自那些表
Name Age
one 0 San Zhang 20
1 Si Li 21
two 0 Wu Wang 21
如果想把序列追加到表的行末或者列末,可以分别使用append
和assign
方法
append
如果原表是默认整数索引,那么可以使用ignore_index=True
对新序列对应的索引自动标号,否则必须对Series指定name属性
s = pd.Series(['Wu Wang', 21], index = df1.columns)
df1.append(s, ignore_index=True)
Name Age
0 San Zhang 20
1 Si Li 21
2 Wu Wang 21
assign
一般通过df['new_col']=...
追加新列,缺点是会直接改动原表,所以assign返回的是一个临时副本
s = pd.Series([80, 90])
df1.assign(Grade=s)#追加列
Name Age Grade
0 San Zhang 20 80
1 Si Li 21 90
df1['Grade'] = s
df1
Name Age Grade
0 San Zhang 20 80
1 Si Li 21 90
compare()
它能够比较两个表或者序列的不同处并进行汇总展示
df1 = pd.DataFrame({'Name':['San Zhang', 'Si Li', 'Wu Wang'],'Age':[20, 21 ,21],'Class':['one', 'two', 'three']})
df2 = pd.DataFrame({'Name':['San Zhang', 'Li Si', 'Wu Wang'],'Age':[20, 21 ,21],'Class':['one', 'two', 'Three']})
df1.compare(df2)
Name Class
self other self other
1 Si Li Li Si NaN NaN
2 NaN NaN three Three
如果相同则会被填充为缺失值nan
,其中other
和self
分别代指传入的参数表和被调用的表自身
如果想要完整显示表中的所有元素的比较情况,可以设置keep_shape=True
df1.compare(df2, keep_shape=True)
Name Age Class
self other self other self other
0 NaN NaN NaN NaN NaN NaN
1 Si Li Li Si NaN NaN NaN NaN
2 NaN NaN NaN NaN three Three
combine
能够让两张表按照一定规则进行组合,在进行规则比较的时候列索引会自动对其
def choose_min(s1, s2):
s2 = s2.reindex_like(s1)
res = s1.where(s1<s2, s2)
res = res.mask(s1.isna()) # isna表示是否为缺失值,返回布尔序列
return res
df1 = pd.DataFrame({'A':[1,2], 'B':[3,4], 'C':[5,6]})
df2 = pd.DataFrame({'B':[5,6], 'C':[7,8], 'D':[9,10]}, index=[1,2])
df1.combine(df2, choose_min)
A B C D
0 NaN NaN NaN NaN
1 NaN 4.0 6.0 NaN
2 NaN NaN NaN NaN
DataFrame.mask() 替换条件为 True 的值
overtwrite
参数为False
可以保留被调用表中未出现在传入的参数表中的列,而不会设置为缺失值
df1.combine(df2, choose_min, overwrite=False)#A列是没有进行比较的
A B C D
0 1.0 NaN NaN NaN
1 2.0 4.0 6.0 NaN
2 NaN NaN NaN NaN
combine_first
方法,在对两张表组合时,若第二张表中的值在第一张表中对应索引位置的值不是缺失状态,那么就使用第一张表的值填充
df1 = pd.DataFrame({'A':[1,2], 'B':[3,np.nan]})
df2 = pd.DataFrame({'A':[5,6], 'B':[7,8]}, index=[1,2])
df1.combine_first(df2)
A B
0 1 3.0
1 2 7.0
2 6 8.0
###统计
isna
或 isnull
查看每个单元格是否缺失
读取表以便学习
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',
usecols = ['Grade', 'Name', 'Gender', 'Height','Weight', 'Transfer'])
df.isna().head()
Grade Name Gender Height Weight Transfer
0 False False False False False False
1 False False False False False False
2 False False False False False False
3 False False False True False False
4 False False False False False False
如果想要查看某一列缺失或者非缺失的行,可以利用 Series 上的 isna
或者 notna
进行布尔索引。
df[df.Height.isna()].head()
Grade Name Gender Height Weight Transfer
3 Sophomore Xiaojuan Sun Female NaN 41.0 N
12 Senior Peng You Female NaN 48.0 NaN
26 Junior Yanli You Female NaN 48.0 N
36 Freshman Xiaojuan Qin Male NaN 79.0 Y
60 Freshman Yanpeng Lv Male NaN 65.0 N
同时对几个列检查缺失情况可以用isna,notna
和any,all
的组合
'''
any()一个序列中满足一个True,则返回True;
all()一个序列中所有值为True时,返回True,否则为False
'''
参数:
'''
DataFrame.any(self, axis=0, bool_only=None, skipna=True, level=None, **kwargs)
DataFrame.all(self, axis=0, bool_only=None, skipna=True, level=None, **kwargs)
参数
参数
axis:{0 或 'index',1 或 'columns',无},默认 0
指示应减少哪个轴或多个轴。
0 / 'index' : 减少索引,返回一个以原始列标签为索引的系列。
1 / 'columns' :减少列,返回一个索引为原始索引的系列。
None:减少所有轴,返回一个标量。
bool_only:布尔值,默认None
仅包括布尔列。如果没有,将尝试使用所有内容,然后仅使用布尔数据。未针对系列实施。
skipna:布尔值,默认为 True
排除 NA/空值。如果整个行/列为 NA 且 skipna 为 True,则结果将为 False,与空行/列一样。
如果 skipna 为 False,则 NA 被视为 True,因为它们不等于零。
level: int 或 层级名称,默认无
如果轴是 MultiIndex(分层),则沿特定级别计数,折叠成一个系列。
Returns:Series or DataFrame
如果指定了level,则返回DataFrame;否则,返回Series
'''
示例1:
sub_set = df[['Height', 'Weight', 'Transfer']]
df[sub_set.isna().all(1)] # 全部缺失
Grade Name Gender Height Weight Transfer
102 Junior Chengli Zhao Male NaN NaN NaN
示例2:
df[sub_set.isna().any(1)].head() # 至少有一个缺失
Grade Name Gender Height Weight Transfer
3 Sophomore Xiaojuan Sun Female NaN 41.0 N
9 Junior Juan Xu Female 164.8 NaN N
12 Senior Peng You Female NaN 48.0 NaN
21 Senior Xiaopeng Shen Male 166.0 62.0 NaN
26 Junior Yanli You Female NaN 48.0 N
示例3:
df[sub_set.notna().all(1)].head() # 没有缺失
Grade Name Gender Height Weight Transfer
0 Freshman Gaopeng Yang Female 158.9 46.0 N
1 Freshman Changqiang You Male 166.5 70.0 N
2 Senior Mei Sun Male 188.9 89.0 N
4 Sophomore Gaojuan You Male 174.0 74.0 N
5 Freshman Xiaoli Qian Female 158.0 51.0 N
dropna
主要参数为方向**axis
(默认为0,即删除行),删除方式how
,删除的非缺失值个数阈值thresh
(非缺失值 没有达到这个数量的相应维度会被删除),备选的删除子集subset
,其中how
**主要有any
和all
两种参数可以选择
参数:
'''
DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
删除缺失值。
参数
axis:{0 或 'index',1 或 'columns'},默认 0
确定是否删除了包含缺失值的行或列。
0 或 'index' :删除包含缺失值的行。
1 或 'columns' :删除包含缺失值的列。
(在 1.0.0 版更改:将元组或列表传递到多个轴上。只允许使用单个轴。)
how:{'any', 'all'}, 默认 'any'
当我们至少有一个 NA 或全部 NA 时,确定是否从 DataFrame 中删除行或列。
'any' :如果存在任何 NA 值,则删除该行或列。
'all' :如果所有值都是 NA,则删除该行或列。
thresh: int,可选
删除的非缺失值个数阈值,非缺失值 没有达到这个数量的相应维度会被删除
其实就是删除条件
subset:列标签或标签序列,可选
要考虑的沿其他轴的标签,例如,如果您要删除行,这些将是要包含的列列表。
inplace:bool,默认 False
如果为 True,则在原地执行操作并返回 None。
'''
示例1:
res = df.dropna(how = 'any', subset = ['Height', 'Weight'])
res.shape
(174, 6)
示例2:
res = df.dropna(1, thresh=df.shape[0]-15) # 身高被删除
res.head()
#没有达到thresh的条件
Grade Name Gender Weight Transfer
0 Freshman Gaopeng Yang Female 46.0 N
1 Freshman Changqiang You Male 70.0 N
2 Senior Mei Sun Male 89.0 N
3 Sophomore Xiaojuan Sun Female 41.0 N
4 Sophomore Gaojuan You Male 74.0 N
不用dropna
也可以用布尔索引完成
res = df.loc[df[['Height', 'Weight']].notna().all(1)]
res.shape
(174, 6)
res = df.loc[:, ~(df.isna().sum()>15)]
res.head()
Grade Name Gender Weight Transfer
0 Freshman Gaopeng Yang Female 46.0 N
1 Freshman Changqiang You Male 70.0 N
2 Senior Mei Sun Male 89.0 N
3 Sophomore Xiaojuan Sun Female 41.0 N
4 Sophomore Gaojuan You Male 74.0 N
###填充
fillna
最常用三个参数:value,method,limit
其中value
为填充值,可以是标量,也可以是索引到元素的字典映射
method
为填充给方法,有用**前面的元素填充fill
和后面的元素填充bfill
**两种类型
limit
参数表示连续缺失值的最大填充次数
参数:
'''
DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)
使用指定的方法填充 NA/NaN 值
参数
value:标量、dict、Series 或 DataFrame
用于填充孔的值(例如 0),或者是值的 dict/Series/DataFrame,指定每个索引(对于 Series)或列(对于 DataFrame)使用哪个值。
不在 dict/Series/DataFrame 中的值将不会被填充。'此值不能是列表'。
method:{'backfill', 'bfill', 'pad', 'ffill', None},默认None
用于填充重新索引系列垫/填充中的孔的方法:
将最后一个有效观察向前传播到下一个有效回填/bfill:使用下一个有效观察来填充间隙。
axis:{0 或“索引”、1 或“列”}
沿其填充缺失值的轴。
inplace:bool,默认 False
如果为真,则就地填写。
注意:这将修改此对象上的任何其他视图(例如,DataFrame 中列的无复制切片)。
limit: int 默认None
如果指定了方法,则这是向前/向后填充的连续 NaN 值的最大数量。
换句话说,如果有超过这个数量的连续 NaN 的间隙,它只会被部分填充。
如果未指定方法,则这是沿整个轴将填充 NaN 的最大条目数。如果不是无,则必须大于 0。
downcast:dict,默认为 None
一个 item->dtype 的字典,如果可能的话,或者字符串 'infer',
它将尝试向下转换为适当的相等类型(例如,如果可能,float64 到 int64)
'''
创建表以便学习
s = pd.Series([np.nan, 1, np.nan, np.nan, 2, np.nan],list('aaabcd'))
s
示例1:
s.fillna(method='ffill') # 用前面的值向后填充
a NaN
a 1.0
a 1.0
b 1.0
c 2.0
d 2.0
dtype: float64
示例2:
s.fillna(method='ffill', limit=1) # 连续出现的缺失,最多填充一次
a NaN
a 1.0
a 1.0
b NaN
c 2.0
d 2.0
dtype: float64
示例3:
s.fillna(s.mean()) # value为标量
a 1.5
a 1.0
a 1.5
b 1.5
c 2.0
d 1.5
dtype: float64
示例4:
s.fillna({'a': 100, 'd': 200}) # 通过索引映射填充的值
a 100.0
a 1.0
a 100.0
b NaN
c 2.0
d 200.0
dtype: float64
有时为了更加合理地填充,需要先进行分组后再操作
df.groupby('Grade')['Height'].transform(lambda x: x.fillna(x.mean())).head()
0 158.900000
1 166.500000
2 188.900000
3 163.075862
4 174.000000
Name: Height, dtype: float64
对于 interpolate
而言,除了插值方法(默认为 linear 线性插值)之外,有与 fillna 类似的两个常用参数,一个是控制方向的 limit_direction ,另一个是控制最大连续缺失值插值个数的 limit 。其中,限制插值的方向默认为 forward ,这与 fillna 的 method 中的 ffill 是类似的,若想要后向限制插值或者双向限制插值可以指定为 backward 或 both 。
####基本概念
在 python 中的缺失值用 None 表示,该元素除了等于自己本身之外,与其他任何元素不相等
print(None == None)
None == False
True
False
在 numpy 中利用 np.nan 来表示缺失值,该元素除了不和其他任何元素相等之外,和自身的比较结果也返回 False
np.nan == np.nan
False
注意:虽然在对缺失序列或表格的元素进行比较操作的时候,
np.nan
的对应位置会返回**False
,但是在使用equals
函数进行两张表或两个序列的相同性检验时,会自动跳过两侧表都是缺失值的位置**,直接返回**True
**
'''
DataFrame.equals(other)
测试两个对象是否包含相同的元素。
此功能允许将两个 Series 或 DataFrame 相互比较,以查看它们是否具
有相同的形状和元素。同一位置的 NaN 被认为是相等的。
行/列索引不需要具有相同的类型,只要值被认为是相等的。对应的列必须
参数
other:Series或DataFrame
要与第一个进行比较的其他 Series 或 DataFrame。具有相同的 dtype。
return:bool
如果两个对象中的所有元素都相同,则为 True,否则为 False
'''
示例1:
s1 = pd.Series([1, np.nan])
s2 = pd.Series([1, 2])
s3 = pd.Series([1, np.nan])
s1 == 1
0 True
1 False
dtype: bool
示例2:
s1.equals(s2)
False
示例3:
s1.equals(s3)
True
在时间序列的对象中, pandas 利用 pd.NaT
来指代缺失值,它的作用和 np.nan
是一致的
pd.to_timedelta(['30s', np.nan]) # Timedelta中的NaT
TimedeltaIndex(['0 days 00:00:30', NaT], dtype='timedelta64[ns]', freq=None)
pd.to_datetime(['20200101', np.nan]) # Datetime中的NaT
DatetimeIndex(['2020-01-01', 'NaT'], dtype='datetime64[ns]', freq=None)
在 pandas 中可以看到 object 类型的对象,而 object 是一种混杂对象类型,如果出现了多个类型的元素同时存储在 Series 中,它的类型就会变成 object
NaT的问题根源在于np.nan本身是一种浮点型,如果浮点型和时间类型混合存储,就会成为object
因此,pandas尝试设计了一种新的缺失类型pd.NA以及三种Nullable序列类型来应对,它们分别是Int,boolean和strin
Nullable性质就是序列类型不受缺失值影响的类型
在**Int,boolean和strin
中存储缺失值**,pandas都会转为内置的pd.NA
示例1:
pd.Series([np.nan, 1], dtype = 'Int64') # "i"是大写的
0 <NA>
1 1
dtype: Int64
示例2:
pd.Series([np.nan, True], dtype = 'boolean')
0 <NA>
1 True
dtype: boolean
示例3:
pd.Series([np.nan, 'my_str'], dtype = 'string')
0 <NA>
1 my_str
dtype: string
如果在Int类型序列乘以小数,只会是浮点型
boolean
类型 与 python的bool
类型的区别1 . 带有缺失值的布尔列表无法进行索引器选择,,而**boolean
**会把缺失值看作False
s = pd.Series(['a', 'b'])
s_bool = pd.Series([True, np.nan])#不会把np.nan看成False+
s_boolean = pd.Series([True, np.nan]).astype('boolean')
# s[s_bool] # 报错
s[s_boolean]
0 a
dtype: object
2 . 在逻辑运算的时候bool类型在缺失处返回的永远是False
,而boolean
会根据逻辑运算是否能确定唯一结果来返回相应的值
s_boolean & True
0 True
1 <NA>
dtype: boolean
s_boolean | True
0 True
1 True
dtype: boolean
~s_boolean # 取反操作同样是无法唯一地判断缺失结果
0 False
1 <NA>
dtype: boolean
convert_dtypes
转为Nullable类型df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
df = df.convert_dtypes()
df.dtypes
School string
Grade string
Name string
Gender string
Height Float64
Weight Int64
Transfer string
Test_Number Int64
Test_Date string
Time_Record string
dtype: object
当调用函数sum,prod使用加法和乘法的时候,缺失数据等价于被分别视作0和1,即不改变原来的计算
s = pd.Series([2,3,np.nan,4,5])
s.sum()
14.0
s.prod()
120.0
当使用累计函数时,会自动跳过缺失值所处的位置
s.cumsum()
0 2.0
1 5.0
2 NaN
3 9.0
4 14.0
dtype: float64
除了np.nan**0
或 np.nan**1
这两种情况为确定值之外(结果为1.0
),所有运算返回结果全为缺失(pd.NA的行为与此一致),并且np.nan
在比较操作时一定返回False
,而**pd.NA
返回pd.NA
**
前者凡是缺失计算都设置为缺失值,后者缺失位置会被设置为0%
的变化率
diff
s.diff()
0 NaN
1 1.0
2 NaN
3 NaN
4 1.0
dtype: float64
pct_change()
s.pct_change()
0 NaN
1 0.500000
2 0.000000
3 0.333333
4 0.250000
dtype: float64
缺失值可以作为一个类别来处理,在分组(groupby
)里面的**get_dummies
函数来增加缺失类别**
创建表便于学习
df_nan = pd.DataFrame({'category':['a','a','b',np.nan,np.nan],'value':[1,3,5,7,9]})
df_nan
category value
0 a 1
1 a 3
2 b 5
3 NaN 7
4 NaN 9
示例:
#先分组
df_nan.groupby('category',dropna=False)['value'].mean() # pandas版本大于1.1.0
category
a 2.0
b 5.0
NaN 8.0
Name: value, dtype: float64
pd.get_dummies(df_nan.category, dummy_na=True)
a b NaN
0 1 0 0
1 1 0 0
2 0 1 0
3 0 0 1
4 0 0 1
str 对象是定义在 Index 或 Series 上的属性,与python中的str模块类似
var = 'abcd'
str.upper(var) # Python内置str模块
'ABCD'
s = pd.Series(['abcd', 'efg', 'hi'])
s.str.upper() # pandas中str对象上的upper方法
0 ABCD
1 EFG
2 HI
dtype: object
###string类型
str.split()
第一个参数为**正则表达式
,第二个参数为从左到右最大拆分**字数n
,是否展开为多个列expand
s = pd.Series(['上海市黄浦区方浜中路249号','上海市宝山区密山路5号'])
s.str.split('[市区路]')#正则表达式
0 [上海, 黄浦, 方浜中, 249号]
1 [上海, 宝山, 密山, 5号]
dtype: object
s.str.split('[市区路]', n=2, expand=True)#n最大拆分次数,expend是否展开多个列
0 1 2
0 上海 黄浦 方浜中路249号
1 上海 宝山 密山路5号
str.join()
用某个链接把Series
中的字符串列表连起来,列表中出现了非字符串元素则返回缺失值
s = pd.Series([['a','b'], [1, 'a'], [['a', 'b'], 'c']])
s.str.join('-')#因为出现非字符串元素,所以返回了缺失值
0 a-b
1 NaN
2 NaN
dtype: object
str.cat()
用于合并两个序列,主要参数为**连接符sep,连接形式join,缺失值代替符号na_rep
,其中连接形式默认为以索引为键的左连接**
s1 = pd.Series(['a','b'])
s2 = pd.Series(['cat','dog'])
s1.str.cat(s2,sep='-')
0 a-cat
1 b-dog
dtype: object
s2.index = [1, 2]
s1.str.cat(s2, sep='-', na_rep='?', join='outer')#na_rep缺失值代替符号
0 a-?
1 b-cat
2 ?-dog
dtype: object
str.contains()
返回每个字符串是否符合正则表达式的布尔索引
s = pd.Series(['my cat', 'he is fat', 'railway station'])
s.str.contains('\s\wat')#给出正则模式,查找包含了这个正则的字符串元素,如果找得到就返回True
0 True
1 True
2 False
dtype: bool
str.startswith()
返回以给定模式开始的布尔序列
str.endwith()
返回以给定模式结束的布尔序列
他们都不支持正则表达式
s.str.startswith('my')#指定开始字符
0 True
1 False
2 False
dtype: bool
s.str.endswith('t')#指定结束字符
0 True
1 True
2 False
dtype: bool
str.match()
返回每组字符串是否符合正则表达式的布尔序列
s.str.match('m|h')
0 True
1 True
2 False
dtype: bool
s.str[::-1].str.match('ta[f|g]|n') # 反转后匹配
0 False
1 True
2 True
dtype: bool
当然,这些也能通过在 str.contains 的正则中使用 ^ 和
$
来实现
s.str.contains('^[m|h]')
0 True
1 True
2 False
dtype: bool
返回索引的匹配函数
str.find()
返回从左到右第一次匹配的位置索引,未找到则返回-1
str.rfind()
返回从右到左第一次匹配的位置索引,未找到则返回-1
s = pd.Series(['This is an apple. That is not an apple.'])
s.str.find('apple')
0 11
dtype: int64
s.str.rfind('apple')
0 33
dtype: int64
str.replace()
str.replace
和 replace
并不是一个函数,在使用字符串替换时应当使用前者
参数:
'''
Series.str.replace(pat, repl, n=- 1, case=None, flags=0, regex=None)
替换系列/索引中每次出现的模式/正则表达式
参数
pat:str或编译的正则表达式
字符串可以是字符序列或正则表达式。
repl:str或可调用
替换ment字符串或可调用对象。可调用对象传递正则表达式匹配对象,
并且必须返回要使用的替换字符串。见re.sub()。
n:int,默认 -1(全部)
从一开始就进行的更换次数。
case:布尔值,默认无
确定替换是否区分大小写:
如果为 True,则区分大小写(如果pat是字符串,则为默认值)
设置为 False 不区分大小写
如果pat是已编译的正则表达式,则无法设置。
flags:int,默认 0(无标志)
正则表达式模块标志,例如 re.IGNORECASE。如果pat是已编译的正则表达式,则无法设置。
regex:bool,默认 True
确定传入的模式是否是正则表达式:
如果为 True,则假定传入的模式是正则表达式。
如果为False ,则将模式视为文字字符串
如果pat是已编译的正则表达式或repl是可调用的,则不能设置为 False 。
'''
s = pd.Series(['a_1_b','c_?'])
s.str.replace('\d|\?', 'new', regex=True)#regex是否使用正则表达式
0 a_new_b
1 c_new
dtype: object
注意:group(k)代表匹配到第k个子组
创建表便于学习
s = pd.Series(['上海市黄浦区方浜中路249号',
'上海市宝山区密山路5号',
'北京市昌平区北农路2号'])
pat = '(\w+市)(\w+区)(\w+路)(\d+号)'
city = {'上海市': 'Shanghai', '北京市': 'Beijing'}
district = {'昌平区': 'CP District',
'黄浦区': 'HP District',
'宝山区': 'BS District'}
road = {'方浜中路': 'Mid Fangbin Road',
'密山路': 'Mishan Road',
'北农路': 'Beinong Road'}
创建字符串替换函数:
#创建字符替换函数
def my_func(m):
str_city = city[m.group(1)]
str_district = district[m.group(2)]
str_road = road[m.group(3)]
str_no = 'No. ' + m.group(4)[:-1]
return ' '.join([str_city,
str_district,
str_road,
str_no])
s.str.replace(pat, my_func, regex=True)
0 Shanghai HP District Mid Fangbin Road No. 249
1 Shanghai BS District Mishan Road No. 5
2 Beijing CP District Beinong Road No. 2
dtype: object
#创建正则表达式并给每个组命名
pat = '(?P<市名>\w+市)(?P<区名>\w+区)(?P<路名>\w+路)(?P<编号>\d+号)'
#<>中间的就是组的名字
def my_func(m):
str_city = city[m.group('市名')]
str_district = district[m.group('区名')]
str_road = road[m.group('路名')]
str_no = 'No. ' + m.group('编号')[:-1]
return ' '.join([str_city,
str_district,
str_road,
str_no])
s.str.replace(pat, my_func, regex=True)
0 Shanghai HP District Mid Fangbin Road No. 249
1 Shanghai BS District Mishan Road No. 5
2 Beijing CP District Beinong Road No. 2
dtype: object
str.extract(regex)
用正则表达式提取字符串(只匹配一个)
pat = '(\w+市)(\w+区)(\w+路)(\d+号)'
s.str.extract(pat)
0 1 2 3
0 上海市 黄浦区 方浜中路 249号
1 上海市 宝山区 密山路 5号
2 北京市 昌平区 北农路 2号
pat = '(?P<市名>\w+市)(?P<区名>\w+区)(?P<路名>\w+路)(?P<编号>\d+号)'
s.str.extract(pat)
市名 区名 路名 编号
0 上海市 黄浦区 方浜中路 249号
1 上海市 宝山区 密山路 5号
2 北京市 昌平区 北农路 2号
str.extractall()
它会把所有符合条件的模式全部匹配出来,如果存在多个结果,则以多级索引的方式存储
s = pd.Series(['A135T15,A26S5','B674S2,B25T6'], index = ['my_A','my_B'])
pat = '[A|B](\d+)[T|S](\d+)'
s.str.extractall(pat)
0 1
match
my_A 0 135 15
1 26 5
my_B 0 674 2
1 25 6
pat_with_name = '[A|B](?P\d+)[T|S](?P\d+)'
s.str.extractall(pat_with_name)
0 1
match
my_A 0 135 15
1 26 5
my_B 0 674 2
1 25 6
str.findall()
也是把所有符合条件的模式全部匹配出来,但是它把结果存入列表中
s.str.findall(pat)
my_A [(135, 15), (26, 5)]
my_B [(674, 2), (25, 6)]
dtype: object
str.upper
(小写变大写)str.lower
(大写变小写)str.swapcase
(小写变大写,大写变小写)str.capitalize
(句首大写,其余都小写)str.title
(单词首字母大写,其余都小写) pd.to_numeric
对字符格式的数值进行快速转换和筛选,其主要参数包括 errors
和 downcast
分别代表了非数的处理模式和转换类型。其中,对于不能转换为数值的有三种 errors
选项, raise
, coerce
, ignore
分别表示直接报错、设为缺失以及保持原来的字符串
s = pd.Series(['1', '2.2', '2e', '??', '-2.1', '0'])
pd.to_numeric(s, errors='ignore')
0 1
1 2.2
2 2e
3 ??
4 -2.1
5 0
dtype: object
pd.to_numeric(s, errors='coerce')
0 1.0
1 2.2
2 NaN
3 NaN
4 -2.1
5 0.0
dtype: float64
coerce
快速查看非数值型的行**s[pd.to_numeric(s, errors='coerce').isna()]
2 2e
3 ??
dtype: object
count
和 len
的作用分别是返回出现正则表达式匹配的次数和字符串的长度
s = pd.Series(['cat rat fat at', 'get feed sheet heat'])
s.str.count('[r|f]at|ee')
0 2
1 2
dtype: int64
s.str.len()
0 14
1 19
dtype: int64
除空型
strip()
去除两侧空格
rstrip()
去除右侧空格
lstrip()
去除左侧空格
填充型
pad()
可以选定字符串长度,填充的方向和填充内容
s = pd.Series(['a','b','c'])
s.str.pad(5,'left','*')
0 ****a
1 ****b
2 ****c
dtype: object
left,right,both
,both
是两边一起填充
rjust,ljust,center
来等效完成
ljust
是右填充,rjust
是左填充
zfill
来实现例如证券代码读入的时候会把”000007”作为数值7来处理
s = pd.Series([7, 155, 303000]).astype('string')
s.str.zfill(6)
0 000007
1 000155
2 303000
dtype: string
分类类型:category
可以用astype()
方法直接转为category
类型
读取表格便于学习
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',
usecols = ['Grade', 'Name', 'Gender', 'Height', 'Weight'])
s = df.Grade.astype('category')
s.head()
0 Freshman
1 Freshman
2 Senior
3 Sophomore
4 Sophomore
Name: Grade, dtype: category
Categories (4, object): ['Freshman', 'Junior', 'Senior', 'Sophomore']
分类类型中定义了cat对象,与str类似,可以使用属性和方法
s.cat
<pandas.core.arrays.categorical.CategoricalAccessor object at 0x000001C2A8498970>
分类类型具有两个部分:
1 . categories
类别本身(以Index类型存储)
2 . ordered
是否有序
s.cat.categories#类别本身
Index(['Freshman', 'Junior', 'Senior', 'Sophomore'], dtype='object')
s.cat.ordered#是否有序
False
codes
用来访问类别被赋予的唯一整数编号
s.cat.codes.head()
0 0
1 0
2 2
3 3
4 3
dtype: int8
####增,删,改
注意:
Index
类型是无法用index_obj[0] = item
来修改的
add_categories
类别的增加s = s.cat.add_categories('Graduate') # 增加一个毕业生类别
s.cat.categories
Index(['Freshman', 'Junior', 'Senior', 'Sophomore', 'Graduate'], dtype='object')
remove_categories
删除类别
原来的序列中该类会被设置为缺失
s = s.cat.remove_categories('Freshman')
s.cat.categories
Index(['Junior', 'Senior', 'Sophomore', 'Graduate'], dtype='object')
s.head()
0 NaN
1 NaN
2 Senior
3 Sophomore
4 Sophomore
Name: Grade, dtype: category
Categories (4, object): ['Junior', 'Senior', 'Sophomore', 'Graduate']
set_categories
设置序列的类别
原先的类别会被覆盖,不满足就会设置为缺失
s = s.cat.set_categories(['Sophomore','PhD']) # 新类别为大二学生和博士
s.cat.categories
Index(['Sophomore', 'PhD'], dtype='object')
s.head()
0 NaN
1 NaN
2 NaN
3 Sophomore
4 Sophomore
Name: Grade, dtype: category
Categories (2, object): ['Sophomore', 'PhD']
remove_unused_categories
删除未出现在序列中的类别s = s.cat.remove_unused_categories() # 移除了未出现的博士生类别
s.cat.categories#序列中只有Sophomore
Index(['Sophomore'], dtype='object')
rename_categories
更改类别
以字典的方式更改类别
这个方法会对原序列的对应值也进行相应修改
s = s.cat.rename_categories({'Sophomore':'本科二年级学生'})
s.head()
0 NaN
1 NaN
2 NaN
3 本科二年级学生
4 本科二年级学生
Name: Grade, dtype: category
Categories (1, object): ['本科二年级学生']
###有序分类
as_unordered
有序类别
reorder_categories
无序类别
无序类别:
传入的参数必须是由当前序列的无序类别构成的列表,不能够增加新的类别,也不能缺少原来的类别,并且**必须指定参数 ordered=True
**,否则方法无效
s = df.Grade.astype('category')
s = s.cat.reorder_categories(['Freshman', 'Sophomore','Junior', 'Senior'],ordered=True)#无序
s.head()
0 Freshman
1 Freshman
2 Senior
3 Sophomore
4 Sophomore
Name: Grade, dtype: category
Categories (4, object): ['Freshman' < 'Sophomore' < 'Junior' < 'Senior']
s.cat.as_unordered().head()
0 Freshman
1 Freshman
2 Senior
3 Sophomore
4 Sophomore
Name: Grade, dtype: category
Categories (4, object): ['Freshman', 'Sophomore', 'Junior', 'Senior']
如果不想指定
ordered=True
参数,那么可以先用s.cat.as_ordered()
转化为有序类别,再利用reorder_categories
进行具体的相对大小调整。
只需把列的类型修改为 category
后,再赋予相应的大小关系,就能正常地使用 sort_index
和 sort_values
进行排序
==
, !=
, >,>=,<,<=
都能进行比较,返回布尔型
cut
参数:
'''
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise', ordered=True)
将值分箱到离散区间中
参数
x:array-like
要装箱的输入数组。必须是一维的。
bins:int、sequence of scalars(标量序列) 或 IntervalIndex
要装箱依据的条件。
int :定义 x 范围内等宽条柱的数量。x 的范围在每侧扩展 0.1%,以包括 x 的最小值和最大值。
sequence of scalars(标量序列) :定义允许非均匀宽度的条柱边。不扩展 x 的范围。
IntervalIndex(间隔索引) :定义要使用的确切条柱。请注意,条柱的间隔索引必须是非重叠的。
right:布尔型 默认为 True
指示条柱是否包含最右边。如果(默认值),则条柱指示 (1,2]、(2,3]、(3,4)。当条柱是
间隔索引时,将忽略此参数。right == True[1, 2, 3, 4]
labels:array 或 False,默认值"None"
指定返回的条柱的标签。长度必须与生成的条柱相同。如果为 False,则仅返回条柱的整数指示符。
这会影响输出容器的类型(见下文)。当条柱是间隔索引时,将忽略此参数。如果为 True,则引发错误。当排序=False时,必须提供标签。
retbins:bool 默认 False
是否退回垃圾箱。当箱作为标量提供时很有用。
precision:int 默认值 3
存储和显示库标签的精度。
include_lowest:布尔型,默认为 False
第一个间隔是否应为左包含区间。
duplicates:{默认 ‘raise’, ‘drop’},可选
如果条柱边不唯一,请提高 ValueError 或删除非唯一边。
ordered:布尔,默认为 True
标签是否订购。适用于返回的类型"分类"和"系列"(使用分类 dtype)。如果为 True,则将对生成的
分类进行排序。如果为 False,则生成的分类将是无序的(必须提供标签)。
返回
out:Categoryial, Series, or ndarray
一个类似数组的对象,表示 x 的每个值的相应 bin。类型取决于标签的值。
None(默认值):为系列 x 返回一个系列,为所有其他输入返回一个分类。其中存储的值为间隔 dtype。
标量序列 :返回序列 x 的序列或所有其他输入的类别。其中存储的值是序列中的任何类型。
False :返回整数的 ndarray。
bins:numpy.ndarray 或 IntervalIndex.
计算的或指定的条柱。仅当 retbins=True 时才返回。对于标量或序列条柱,这是一个包含计算箱的 ndarray。
如果设置重复项 = 丢弃,则条柱将丢弃非唯一条柱。对于间隔索引条柱,这等于条柱。
'''
最重要的参数是 bins
,传入整数 n
代表把整个传入数组的按照最大和最小值等间距地分为 n
段
区间默认是左开右闭,需要在调整时把最小值包含进去
pandas中的解决方案是在值最小的区间左端点再减去**0.001*(max-min)
**
指定左闭右开时,需要把 right
参数设置为 False
,相应的区间调整方法是在值最大的区间右端点再加上 **0.001*(max-min)
**
示例1:
s = pd.Series([1,2])
pd.cut(s, bins=2)
'''
因为要包含最小值1,所以pandas做了 1-0.001*(2-1) 这个运算(1是左端点)
'''
0 (0.999, 1.5]
1 (1.5, 2.0]
dtype: category
Categories (2, interval[float64]): [(0.999, 1.5] < (1.5, 2.0]]
示例2:
pd.cut(s, bins=2, right=False)#right左闭右开
'''
因为要包含最大值2,所以pandas做了 2+0.001*(2-1) 这个运算(2是右端点)
'''
0 [1.0, 1.5)
1 [1.5, 2.001)
dtype: category
Categories (2, interval[float64]): [[1.0, 1.5) < [1.5, 2.001)]
指定区间分割点
给bins
一个列表,np.infty
表示无穷大
pd.cut(s, bins=[-np.infty, 1.2, 1.8, 2.2, np.infty])
0 (-inf, 1.2]
1 (1.8, 2.2]
dtype: category
Categories (4, interval[float64]): [(-inf, 1.2] < (1.2, 1.8] < (1.8, 2.2] < (2.2, inf]]
分割点常用参数
labels
:指定区间名字
retbins
:是否返回分割点(默认False)
指定True之后会返回两个对象,第一个是区间分区,第二个是分割点数组,可以用索引访问
s = pd.Series([1,2])
res = pd.cut(s, bins=2, labels=['small', 'big'], retbins=True)
res[0]
0 small
1 big
dtype: category
Categories (2, object): ['small' < 'big']
res[1] # 该元素为返回的分割点
array([0.999, 1.5 , 2. ])
qcut
参数:
'''
pandas.qcut(x, q, labels=None, retbins=False, precision=3, duplicates='raise')
基于分位数的离散化函数。
根据排名或基于样本分位数将变量离散化为大小相等的桶
参数:
x:array-like
要装箱的输入数组。必须是一维的。
q:int 或 list(float)
分位数。10 用于十分位数,4 用于四分位数等。交替排列的分位数,例如 [0, .25, .5, .75, 1.] 用于四分位数。
labels:array或False,默认None
用作结果箱的标签。必须与生成的 bin 长度相同。如果为 False,则仅返回 bin 的整数指示符。如果为 True,则引发错误。
retbins:bool 默认 False
是否退回垃圾箱。当箱作为标量提供时很有用。
precision:int 默认 3
存储和显示库标签的精度。
duplicates:{默认 ‘raise’, ‘drop’},可选
如果条柱边不唯一,请提高 ValueError 或删除非唯一边
return:
out:如果标签为 False,则输出分类或系列或整数数组返回类型(分类或系列)取决于输入:如果输入是系列,则为类别类型系列,否则为分类。当返回分类数据时,bin 表示为类别。
bins:浮点数的ndarray
仅当retbins为 True 时才返回
'''
qcut
只是把bins
参数改成q
,q
参数是指quantile
,这里的 q
为整数 n
时,指按照 n
等分位数把数据分箱,还可以传入浮点列表指代相应的分位数分割点
s = df.Weight
pd.qcut(s, q=[0,0.2,0.8,1]).head()
0 (44.0, 69.4]
1 (69.4, 89.0]
2 (69.4, 89.0]
3 (33.999, 44.0]
4 (69.4, 89.0]
Name: Weight, dtype: category
Categories (3, interval[float64]): [(33.999, 44.0] < (44.0, 69.4] < (69.4, 89.0]]
####区间构造
三要素:左端点,右端点,开闭状态
开闭状态可以指定 right, left, both, neither
中的一类
my_interval = pd.Interval(0, 1, 'right')
my_interval
Interval(0, 1, closed='right')
函数:pd.Interval()
此函数创建的对象属性:
属性包含了 mid, length, right, left, closed
,分别表示中点、长度、右端点、左端点和开闭状态
使用 in
可以判断元素是否属于区间
使用 overlaps
可以判断两个区间是否有交集
pd.IntervalIndex
对象
**from_breaks
**传入列表,每个元素依次为左右端点
pd.IntervalIndex.from_breaks([1,3,6,10], closed='both')
IntervalIndex([[1, 3], [3, 6], [6, 10]],
closed='both',
dtype='interval[int64]')
from_arrays
传入两个列表,两个列表的元素为对应形式成立区间
pd.IntervalIndex.from_arrays(left = [1,3,6,10],
right = [5,4,9,11],
closed = 'neither')
IntervalIndex([(1, 5), (3, 4), (6, 9), (10, 11)],
closed='neither',
dtype='interval[int64]')
**from_tuples
**传入元组的列表,每个元组为一个区间
pd.IntervalIndex.from_tuples([(1,5),(3,4),(6,9),(10,11)],
closed='neither')
IntervalIndex([(1, 5), (3, 4), (6, 9), (10, 11)],
closed='neither',
dtype='interval[int64]')
interval_range
生成等差区间
参数:start, end, periods, freq
起点、终点、区间个数和区间长度
pd.interval_range(start=1,end=5,periods=8)
IntervalIndex([(1.0, 1.5], (1.5, 2.0], (2.0, 2.5], (2.5, 3.0], (3.0, 3.5], (3.5, 4.0], (4.0, 4.5], (4.5, 5.0]],
closed='right',
dtype='interval[float64]')
pd.interval_range(end=5,periods=8,freq=0.5)
IntervalIndex([(1.0, 1.5], (1.5, 2.0], (2.0, 2.5], (2.5, 3.0], (3.0, 3.5], (3.5, 4.0], (4.0, 4.5], (4.5, 5.0]],
closed='right',
dtype='interval[float64]')
Interval
类型的列表组成传入其中转为区间索引,那么所有的区间会被强制转为指定的 closed
类型,因为 pd.IntervalIndex
只允许存放同一种开闭区间的 Interval
对象my_interval
Interval(0, 1, closed='right')
my_interval_2
Interval(0.5, 1.5, closed='left')
pd.IntervalIndex([my_interval, my_interval_2], closed='left')
IntervalIndex([[0.0, 1.0), [0.5, 1.5)],
closed='left',
dtype='interval[float64]')
如果想要具体利用 cut
或者 qcut
的结果进行分析,那么需要先将其转为该种索引类型
id_interval = pd.IntervalIndex(pd.cut(s, 3))
IntervalIndex
的常用属性:left, right, mid, length
,分别表示左右端点、两端点均值和区间长度
id_demo = id_interval[:5] # 选出前5个展示
id_demo
IntervalIndex([(33.945, 52.333], (52.333, 70.667], (70.667, 89.0], (33.945, 52.333], (70.667, 89.0]],
closed='right',
name='Weight',
dtype='interval[float64]')
示例:
id_demo.left
Float64Index([33.945, 52.333, 70.667, 33.945, 70.667], dtype='float64')
contains
和 overlaps
,分别指逐个判断每个区间是否包含某元素,以及是否和一个 pd.Interval
对象有交集
id_demo.contains(4)
array([False, False, False, False, False])
id_demo.overlaps(pd.Interval(40,60))
array([ True, True, False, True, False])
将日期格式转换成Timestamp类型:pd.Timestamp()
ts = pd.Timestamp('2020/1/1')
ts
Timestamp('2020-01-01 00:00:00')
Timestamp类型的属性:year, month, day, hour, min, second
Timestamp类型表示的时间范围最大是:585
年
pd.Timestamp.max
和 pd.Timestamp.min
可以获取时间戳表示的范围
to_datetime
能够把时间戳格式转化为datetime64[ns]
类型的时间序列
pd.to_datetime(['2020-1-1', '2020-1-3', '2020-1-6'])
DatetimeIndex(['2020-01-01', '2020-01-03', '2020-01-06'], dtype='datetime64[ns]', freq=None)
读取表便于学习
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
s = pd.to_datetime(df.Test_Date)
s.head()
0 2019-10-05
1 2019-09-04
2 2019-09-12
3 2020-01-03
4 2019-11-06
Name: Test_Date, dtype: datetime64[ns]
时间戳格式如果不满足转换,可以使用**format
****强制转换**进行匹配
temp = pd.to_datetime(['2020\\1\\1','2020\\1\\3'],format='%Y\\%m\\%d')
temp
DatetimeIndex(['2020-01-01', '2020-01-03'], dtype='datetime64[ns]', freq=None)
列表传入返回
DatetimeIndex
对象Series传入返回**
datetime64[ns]
**类型
把表的多列时间属性拼接转为时间序列,但是列名必须与给定的属性关键词相同
df_date_cols = pd.DataFrame({'year': [2020, 2020],
'month': [1, 1],
'day': [1, 2],
'hour': [10, 20],
'minute': [30, 50],
'second': [20, 40]})
pd.to_datetime(df_date_cols)
0 2020-01-01 10:30:20
1 2020-01-02 20:50:40
dtype: datetime64[ns]
date_range
生成连续间隔时间的一种方法
参数:``start, end, freq, periods`分别表示开始时间,结束时间,时间间隔,时间戳个数
注意:开始或结束日期如果作为端点,如果计算到端点则它会被包含
pd.date_range('2020-1-1','2020-1-21', freq='10D') # 包含
DatetimeIndex(['2020-01-01', '2020-01-11', '2020-01-21'], dtype='datetime64[ns]', freq='10D')
pd.date_range('2020-1-1','2020-2-28', freq='10D')
DatetimeIndex(['2020-01-01', '2020-01-11', '2020-01-21', '2020-01-31','2020-02-10', '2020-02-20'],
dtype='datetime64[ns]', freq='10D')
pd.date_range('2020-1-1','2020-2-28', periods=6) # 由于结束日期无法取到,freq不为10天
DatetimeIndex(['2020-01-01 00:00:00', '2020-01-12 14:24:00',
'2020-01-24 04:48:00', '2020-02-04 19:12:00',
'2020-02-16 09:36:00', '2020-02-28 00:00:00'],
dtype='datetime64[ns]', freq=None)
这里的
freq
参数与DateOffset
对象紧密相关
**asfreq
**方法
改变序列采样频率
datetime64[ns]
本质上可以理解为一个大整数,对于一个该类型的序列,可以使用max, min, mean
,来取得最大时间戳、最小时间戳和“平均”时间戳
datetime64[ns].dt
datetime64[ns]
上的属性
大致分为三类操作:取出时间相关的属性、判断时间戳是否满足条件、取整操作
取出时间相关的属性:``date, time, year, month, day, hour,minute, second, microsecond, nanosecond, dayofweek, dayofyear, weekofyear, daysinmonth, quarter,**其中
daysinmonth, quarter` 分别表示该月一共有几天和季度。**
s = pd.Series(pd.date_range('2020-1-1','2020-1-3', freq='D'))
s.dt.daysinmonth
dayofweek
返回周中的星期情况(周一为0、周二为1)
s.dt.dayofweek
0 2
1 3
2 4
dtype: int64
month_name, day_name
返回英文的月名和星期名,注意它们是方法而不是属性
s.dt.month_name()
0 January
1 January
2 January
dtype: object
判断时间戳是否满足条件
测试是否为月/季/年的第一天或者最后一天
s.dt.is_year_start # 还可选 is_quarter/month_start
0 True
1 False
2 False
dtype: bool
s.dt.is_year_end # 还可选 is_quarter/month_end
0 False
1 False
2 False
dtype: bool
取整操作
round, ceil, floor
四舍五入,进入,舍去
公共参数为 freq
,常用的包括 H, min, S
(小时、分钟、秒),所有可选的 freq
s = pd.Series(pd.date_range('2020-1-1 20:35:00',
'2020-1-1 22:35:00',
freq='45min'))
####切片与索引
索引都是以布尔索引为开始
切片都是用索引器[]
s[(idx.is_month_start|idx.is_month_end).values].head()
2020-01-01 1
2020-01-31 0
2020-02-01 1
2020-02-29 1
2020-03-01 0
dtype: int32
s[idx.dayofweek.isin([5,6]).values].head()
2020-01-04 1
2020-01-05 0
2020-01-11 0
2020-01-12 1
2020-01-18 1
dtype: int32
s['2020-07'].head()
2020-07-01 0
2020-07-02 1
2020-07-03 0
2020-07-04 0
2020-07-05 0
Freq: D, dtype: int32
s['2020-05':'2020-7-15'].head()
2020-05-01 0
2020-05-02 1
2020-05-03 0
2020-05-04 1
2020-05-05 1
Freq: D, dtype: int32
s['2020-05':'2020-7-15'].tail()
2020-07-11 0
2020-07-12 0
2020-07-13 1
2020-07-14 0
2020-07-15 1
Freq: D, dtype: int32
pd.Timedelta
是两个时间戳的差
pd.Timedelta(days=1, minutes=25)# 需要注意加s
Timedelta('1 days 00:25:00')
pd.Timedelta('1 days 25 minutes') # 字符串生成
Timedelta('1 days 00:25:00')
pd.to_timedelta
生成时间差序列,类型为 timedelta64[ns]
s = pd.to_timedelta(df.Time_Record)
s.head()
0 0 days 00:04:34
1 0 days 00:04:20
2 0 days 00:05:22
3 0 days 00:04:08
4 0 days 00:05:22
Name: Time_Record, dtype: timedelta64[ns]
pd.timedelta_range
时间差序列,与``date_range`具有一致的参数
pd.timedelta_range('0s', '1000s', freq='6min')
TimedeltaIndex(['0 days 00:00:00', '0 days 00:06:00', '0 days 00:12:00'], dtype='timedelta64[ns]', freq='6T')
pd.timedelta_range('0s', '1000s', periods=3)
TimedeltaIndex(['0 days 00:00:00', '0 days 00:08:20', '0 days 00:16:40'], dtype='timedelta64[ns]', freq=None)
####dt对象
Timedelta
序列也定义了dt对象
属性:days, seconds, mircroseconds, nanoseconds
这里的
seconds
不是指单纯的秒,而是对天数取余后剩余的秒数
s.dt.seconds.head()
0 274
1 260
2 322
3 248
4 322
Name: Time_Record, dtype: int64
直接对应秒数:total_seconds
s.dt.total_seconds().head()
0 274.0
1 260.0
2 322.0
3 248.0
4 322.0
Name: Time_Record, dtype: float64
取整函数也是可以在 dt
对象上使用
pd.to_timedelta(df.Time_Record).dt.round('min').head()
0 0 days 00:05:00
1 0 days 00:04:00
2 0 days 00:05:00
3 0 days 00:04:00
4 0 days 00:05:00
Name: Time_Record, dtype: timedelta64[ns]
####Timedelta的运算
三类:与标量的乘法运算、与时间戳的加减法运算、与时间差的加减法与除法运算
预设:
td1 = pd.Timedelta(days=1)
td2 = pd.Timedelta(days=3)
ts = pd.Timestamp('20200101')
ts - td1
Timestamp('2019-12-31 00:00:00')
td1 * 2
Timedelta('2 days 00:00:00')
时间差序列的运算
td1 = pd.timedelta_range(start='1 days', periods=5)
td2 = pd.timedelta_range(start='12 hours',freq='2H',periods=5)
ts = pd.date_range('20200101', '20200105')
示例1:
td1 * 5
TimedeltaIndex(['5 days', '10 days', '15 days', '20 days', '25 days'], dtype='timedelta64[ns]', freq='5D')
示例2:
td1 * pd.Series(list(range(5))) # 逐个相乘
0 0 days
1 2 days
2 6 days
3 12 days
4 20 days
dtype: timedelta64[ns]
示例3:
td1 + ts # 逐个相加
DatetimeIndex(['2020-01-02', '2020-01-04', '2020-01-06', '2020-01-08',
'2020-01-10'],
dtype='datetime64[ns]', freq=None)
**pd.offsets
**定义offset对象
日期偏置是一种和日历相关的特殊时间差
示例:
pd.Timestamp('20200831') + pd.offsets.WeekOfMonth(week=0,weekday=0)
Timestamp('2020-09-07 00:00:00')
+
获取最近的下一个日期
-
获取最近的上一个日期
pd.Timestamp('20200907') - pd.offsets.BDay(30)
Timestamp('2020-07-27 00:00:00')
pd.Timestamp('20200907') + pd.offsets.MonthEnd()
Timestamp('2020-09-30 00:00:00')
CDay
特殊的offset对象
参数:
holidays
传入了需要过滤的日期列表
weekmask
传入的是三个字母的星期缩写构成的星期字符串,其作用是只保留字符串中出现的星期
my_filter = pd.offsets.CDay(n=1,weekmask='Wed Fri',holidays=['20200109'])
dr = pd.date_range('20200108', '20200111')
dr.to_series().dt.dayofweek
2020-01-08 2
2020-01-09 3
2020-01-10 4
2020-01-11 5
Freq: D, dtype: int64
[i + my_filter for i in dr]
[Timestamp('2020-01-10 00:00:00'),
Timestamp('2020-01-10 00:00:00'),
Timestamp('2020-01-15 00:00:00'),
Timestamp('2020-01-15 00:00:00')]
不要使用部分
Offset
: 在当前版本下由于一些
bug
,不要使用Day
级别以下的Offset
对象,比如Hour, Second
等,请使用对应的Timedelta
对象来代替
偏执字符串就是Offset的缩写,作为类型一并给freq参数使用
示例:
pd.date_range('20200101','20200331', freq='MS') # 月初
DatetimeIndex(['2020-01-01', '2020-02-01', '2020-03-01'], dtype='datetime64[ns]', freq='MS')
pd.date_range('20200101','20200201',freq='WOM-1MON') # 每月第一个周一
DatetimeIndex(['2020-01-06'], dtype='datetime64[ns]', freq='WOM-1MON')
上面的这些字符串,等价于使用的 Offset
对象
时序的滑窗函数,即把滑动窗口用 freq
关键词代替
**shift
**函数可以指定freq单位进行滑动( datetime64
为索引的序列)
s.shift(freq='50D').head()
2020-02-20 -1
2020-02-21 -2
2020-02-22 -1
2020-02-25 -1
2020-02-26 -2
dtype: int32
diff
datetime64[ns]
的序列进行 diff
后就能够得到 timedelta64[ns]
的序列
my_series = pd.Series(s.index)
my_series.head()
0 2020-01-01
1 2020-01-02
2 2020-01-03
3 2020-01-06
4 2020-01-07
dtype: datetime64[ns]
my_series.diff(1).head()
0 NaT
1 1 days
2 1 days
3 3 days
4 1 days
dtype: timedelta64[ns]
pd.resample
与groupby用法类似,是对时间序列分组计算的分组对象
s.resample('10D').mean().head()
2020-01-01 -2.000000
2020-01-11 -3.166667
2020-01-21 -3.625000
2020-01-31 -4.000000
2020-02-10 -0.375000
Freq: 10D, dtype: float64
重采样也可以使用**apply
**
s.resample('10D').apply(lambda x:x.max()-x.min()).head() # 极差
2020-01-01 3
2020-01-11 4
2020-01-21 4
2020-01-31 2
2020-02-10 4
Freq: 10D, dtype: int32
resample边界处理
起始值的计算方法:从给定的最小时间戳的午夜0点开始,一直增加freq
,加到不超过这个时间戳,就被设置为起始值
每次累加的freq参数作为分割节点进行分组,区间为左闭右开
idx = pd.date_range('20200101 8:26:35', '20200101 9:31:58', freq='77s')
data = np.random.randint(-1,2,len(idx)).cumsum()
s = pd.Series(data,index=idx)
s.head()
2020-01-01 08:26:35 -1
2020-01-01 08:27:52 -1
2020-01-01 08:29:09 -2
2020-01-01 08:30:26 -3
2020-01-01 08:31:43 -4
Freq: 77S, dtype: int32
下面对应的第一个组起始值为
08:24:00
,其是从当天0点增加72个freq=7 min
得到的,如果再增加一个freq
则超出了序列的最小时间戳08:26:35
s.resample('7min').mean().head()
2020-01-01 08:24:00 -1.750000
2020-01-01 08:31:00 -2.600000
2020-01-01 08:38:00 -2.166667
2020-01-01 08:45:00 0.200000
2020-01-01 08:52:00 2.833333
Freq: 7T, dtype: float64
指定origin
为start
:最小时间戳开始依次增加 freq
进行分组
s.resample('7min', origin='start').mean().head()
2020-01-01 08:26:35 -2.333333
2020-01-01 08:33:35 -2.400000
2020-01-01 08:40:35 -1.333333
2020-01-01 08:47:35 1.200000
2020-01-01 08:54:35 3.166667
Freq: 7T, dtype: float64
M, A, Q, BM, BA, BQ, W
这七个是取对应区间的最后一个时间戳s = pd.Series(np.random.randint(2,size=366),index=pd.date_range('2020-01-01','2020-12-31'))
s.resample('M').mean().head()
2020-01-31 0.451613
2020-02-29 0.448276
2020-03-31 0.516129
2020-04-30 0.566667
2020-05-31 0.451613
Freq: M, dtype: float64
s.resample('MS').mean().head() # 结果一样,但索引不同
2020-01-01 0.451613
2020-02-01 0.448276
2020-03-01 0.516129
2020-04-01 0.566667
2020-05-01 0.451613
Freq: MS, dtype: float64
归属人:我怕是有点打脑壳
严禁转载