pandas数据处理
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
# 原始数据最基本的操作一定包括如下三步
# 1.空值的处理
# 2.重复值的处理
# 3.异常值的处理
# 一、重复值的处理
df1 = DataFrame({
"name": ["lucy", "tom", "jack", "tony", "mery", "rose", "black"],
"python": np.random.randint(0,150,size=7),
"java": np.random.randint(0,150,size=7),
"php": np.random.randint(0,150,size=7),
})
df1
df1.loc[7] = df1.loc[0].copy()
df1.loc[4] = df1.loc[0].copy()
df1
# 查看重复行
# DataFrame对象.duplicated()
# 比较的是行的上下是否重复,而非列
# 默认保留第一个重复值keep="first",也可以keep="last"指定最后一个作为重复值
df1.duplicated(keep="last")
# df1.drop([0,4])
# 删除重复行
# DataFrame对象.drop_duplicates()
# 也有inplace参数
# df1.drop_duplicates(keep="first")
df1
df1.loc[6,"name"] = "tom"
df1.loc[7] = ["black",13,89,36]
df1
# 查询python,java,php成绩租同的行
df1.loc[df1.duplicated(subset=["python", "java", "php"])]
# 查询名字重复的数据
df1.duplicated(subset=["name"])
# 二、映射
# 1.映射一:replace
# 适用:replace对Series和DataFrame都是适用的(pandas对象)
# fillna()
# replace属于fillna的高级版本
df1
# 直接替换字符串
df1.replace(to_replace="tom", value="TOM")
# 替换数字
df1.replace(to_replace=13.0, value=23)
# 列表替换
df1.replace(to_replace=["lucy","tom","jack"], value=["LUCY","TOM","JACK"])
# 使用字典替换
map_dic = {
"lucy": "LUCY",
"mery": "MERY",
"tom": "TOM"
}
df1.replace(to_replace=map_dic)
# 使用字典处理某一列(特殊用法)
df1["old_name"] = df1["name"]
# 会将两列的Lucy都替换
# df1.replace(to_replace="lucy", value="LUCY")
# 只替换name行的lucy
df1.replace(to_replace={"name":"lucy"}, value="LUCY")
df1
# 正则替换
df1.replace(to_replace=r"t.*", regex=True, value="ContainT")
# 练习:假设张三李四的课表里有满分的情况,老师认为是作弊,把所有满分的情况(包括150,300分)都记0分,如何实现?
# df1.drop("old_name",axis=1,inplace=True)
df1.replace({13.0: 0,
89.0: 0})
# 在Series中replace有个特殊用法(已经被弃用,未来版本会移除)
name = df1.name
name
name.replace(to_replace="tom", method="ffill")
# 2.map是Series的函数,所以通常被用来对某一列进行整体的映射处理
df1
df1.duplicated()
df1.name.values
# 想给每个学生添加一个地址列
# 映射字典中多的话没事,少的话为NaN
map_dic = {
'lucy':"北京",
'tom':"上海",
'jack':"北京",
'tony':"上海",
'mery':"上海",
'rose':"北京",
'tom':"上海",
'black':"北京"
}
# map函数是Series的函数
# df1.name.map(map_dic)
df1["address"] = df1.name.map(map_dic)
df1
def map_name(name):
return map_dic.get(name,name)
# map_dic.get("noname","noname")
map_name("noname")
# map可以接收函数
# 这样写会遍历name列中每一个元素作为map_name的参数
df1["name"].map(map_name)
df1
# 练习,将成绩变为5分制
def score_5(score):
if score > 90:
return "A"
elif score > 80:
return "B"
elif score > 70:
return "C"
elif score >= 60:
return "D"
else:
return "E"
# pd.to_numeric(df1['java'], errors='coerce')
df1
# df1["java"] = df1["java"].map(score_5)
df1["php_5"] = df1["php"].map(score_5)
df1
df1["name"] = df1.name.map(lambda name: f"{name}_1")
df1
# transform()只接收函数,不接收字典(和map一样,只不过功能更少)
df1.name.transform(lambda name: f"{name}_2")
# 练习:新增两列,分别为张三、李四的成绩状态,如果分数低于90,则为"failed",如果分数高于120,则为"excellent",其他则为"pass
df2 = DataFrame({
"name": ["张三","李四"],
"语文": np.random.randint(0,150,2),
"数学": np.random.randint(0,150,2),
"英语": np.random.randint(0,150,2),
})
df2
def score_map(score):
if score < 90:
return "failed"
elif score > 120:
return "excellent"
else:
return "pass"
# 删除列表中第一个元素三种方式:切片,pop,del
columns = df2.columns
for column in columns[1:]:
df2[column] = df2[column].map(score_map)
df2
# 更便捷
# 对一个DataFrame做遍历的时候,默认就是遍历它的列标签
for column in df2:
print(column)
# 完全可以把一个DataFrame当成字典来遍历
for k,v in df2.items():
print(k)
print(v)
# 3.rename()函数:替换索引
df2
# columns参数替换列索引
df2.rename(columns={"name":"姓名"})
df2.set_index("name",inplace=True)
df2
# index参数替换行索引
df2.rename(index={"张三":"tom","李四":"jack"})
# mapper参数要配合axis参数
mapper = {
"张三":"tom",
"李四":"jack",
"语文":"文学",
"英语":"外语",
"上学期":"first class",
"下学期":"second class"
}
df2.rename(mapper=mapper) # 默认替换行索引
df2.rename(mapper=mapper, axis=1) # 替换列索引
total = pd.concat((df2,df2),axis=1,keys=["上学期","下学期"])
# level参数控制多级索引
# 默认将一级索引和二级索引都替换了
total.rename(mapper=mapper,axis=1)
# 只想替换最外层索引
total.rename(mapper=mapper,axis=1,level=-2)
# 也可以(适合字段少)(推荐)(速度快)
df2.columns = ["chinese","math","english"]
df2
总结
- replace()属于fillna()的强化版,解决值的替换
字符串,数字,列表,字典,正则
适用于Series,DataFrame(pandas对象) - map()是Series对象的操作方法,只解决一列的映射问题
字典,函数,lambda表达式
适用于Series - rename()解决索引替换
字典,函数
# 三、使用聚合操作对数据异常值检测和过滤
df1.dtypes
df1.head()
df1
# 使用describe()函数查看每一列的描述性统计量
# 只对可以运算的列有效
"""
python php
count 7.000000 7.000000
mean 62.714286 75.142857
std 50.015712 45.175320
min 3.000000 22.000000
25% 20.000000 31.500000
50% 71.000000 98.000000
75% 93.500000 108.000000
max 138.000000 127.000000
"""
df1.describe()
"""
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 name 7 non-null object
1 python 7 non-null int32
2 java 7 non-null object
3 php 7 non-null int32
4 php_5 7 non-null object
dtypes: int32(2), object(3)
memory usage: 352.0+ bytes
"""
df1.info()
# 尊重业务的需求 5000 10000
# 异常值通用的界定办法:如果数据是呈标准正态分布的,/data/ > 3 * /data.std()/
# 离群点的检测::数值型的数据都可以使用离群点的方式来检测异常
data = np.random.randn(1000)
# 异常值界定-练习
# 例如,3.14e+2 等于 314,5.67e-3 等于 0.00567。
data[np.abs(data) > 3 * data.std()]
# 异常值界定-练习
# 任意一行至少存件个数的绝对值大于该数所处列的3倍标准差,即认定为满足异常值条件
df3 = DataFrame(np.random.randn(1000,3), columns=list("ABC"))
bool_list = (df3 > 3 * df3.std()).any(axis=1)
df3.loc[bool_list]
drop_index = df3.loc[bool_list].index
# 删除这几行
df3.drop(drop_index)
# 四、排序
# 使用.take()函数排序
df4 = DataFrame(np.random.randint(0,100,(5,5)), columns=list("ABCDE"))
df4
# 类似于numpy的列表访问
# 默认是行
df4.take([0,1,0,1])
# 列
df4.take([0,1,0,1], axis=1)
# 随机抽样
# 打乱行
df4.take(np.random.permutation(5))
# 当DataFrame规模足够大时,直接使用np.random.randint()函数,就配合take()函数实现随机抽样
df5 = DataFrame(np.random.randint(0,100,(1000,3)), columns=list("ABC"))
df5
df5.take(np.random.randint(0,1000,5))
# 五、数据分类/组处理【重点】
# 根据attack_range分组,产生一个分组对象
heros = pd.read_excel('hero_xlsx')
group_obj = heros.groupby("attack_range")
# 分组之后一定是聚合,聚合运算只保留可运算的列
# 查看分组对象的信息
group_obj.groups
group_obj.mean()
group_obj.mean()["hp_growth"]
group_obj.mean()[["hp_growth","hp_max"]]
# 对不同的列进行不同的聚合操作
grouped_obj.agg({"hp_growth":"mean", "hp_max":"max"})
grouped_obj["hp_growth"].mean()
h1 = hero[["name","hp_max","mp_max","attack_range","role_main"]].copy()
avg = DataFrame(h1.groupby("attack_range")["hp_max"].mean())
# 合并
pd.merge(h1,avf,left_on="attack_range", right_index=True, suffixes=["","_avg "])
# 通过多个字段分组
group_obj1 = h1.groupbuy(["attack_range","role_main"])
group_obj1.groups
group_obj1.agg({"hp_max": "mean"}).unstack(level=-2, fill_value=0) # 透视表:某两个字段的交叉关系
# group_obj1.agg({"hp_max": "mean", "mp_max": "mean"}).unstack(level=-2, fill_value=0)
# 透视表(是解决交叉关系的)
pd.pivot_table(data=hl,values="hp_max",index="role_main", columns="attack_range", aggfunc="mean", fill_value=0)
# 交叉表(特殊透视表)(是解决频率统计的)
# 交叉表(cross-tabulation,简称crosstab)是一种用于计算分组频率的特殊透视表。
pd.crosstab(index=h1["role_main"], column=h1["attack_range"])
# 六、高级数据聚合
h1.groupby("role_main")["mp_max"].mean()
# 使用.apple
# np.mean也可为自定义函数
h1.groupby("role_main")["mp_max"].apple(np.mean)
# 分组对象的合闲委差受的是个分组
# 定制一个最大值和平均值的差的聚合函数
def group_function(x):
return x.max() - x.mean()
df6 = DataFrame(h1.groupby("role_main")["mp_max"].apple(group_function))
df6.coulumns = ["max-mean"]
pd.merge(h1.df6,left_on="role_main",right_index=True)
# transform
# 与apple相比作用一样,返回值有些变化(没去重),所以用apple就行
df6 = DataFrame(h1.groupby("role_main")["mp_max"].transform(group_function))
作者:cloud-2-jane
出处:https://www.cnblogs.com/cloud-2-jane/articles/18609830
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架