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

总结

  1. replace()属于fillna()的强化版,解决值的替换
    字符串,数字,列表,字典,正则
    适用于Series,DataFrame(pandas对象)
  2. map()是Series对象的操作方法,只解决一列的映射问题
    字典,函数,lambda表达式
    适用于Series
  3. 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 国际」许可协议进行许可。

posted @   一只大学生  阅读(31)  评论(0编辑  收藏  举报
编辑推荐:
· 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 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示