使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True(是重复的)
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
data = [[100,100,100],[90,90,88],[100,100,100],[90,90,87],[100,100,100]]
columns = ['python','c++','java']
index = list('ABCDE')
df = DataFrame(data=data,index=index,columns=columns)
df
python | c++ | java | |
---|---|---|---|
A | 100 | 100 | 100 |
B | 90 | 90 | 88 |
C | 100 | 100 | 100 |
D | 90 | 90 | 87 |
E | 100 | 100 | 100 |
df.duplicated(keep="first") # 告诉我们 当前行是否重复
# 参数默认是 keep="first" 保留开始的 意思是如果发现很多重复的元素 第一个不算重复的 后面的才是 某一行重复 就返回True
结果为:
A False
B False
C True
D False
E True
dtype: bool
df.duplicated(keep="last") # keep last 如果遇到重复的元素 最后一个不算重复的 前面的才算重复 这一行重复了 就是True
结果为:
A True
B False
C True
D False
E False
dtype: bool
df.duplicated(keep=False) # 只要有和别人完全一样的 不管在开头还是结尾 都算重复 这一行如果是重复的就返回 True
结果为:
A True
B False
C True
D False
E True
dtype: bool
df.drop_duplicates() # {'first', 'last', False}, default 'first'
python | c++ | java | |
---|---|---|---|
A | 100 | 100 | 100 |
B | 90 | 90 | 88 |
D | 90 | 90 | 87 |
df.drop_duplicates(keep="last")
python | c++ | java | |
---|---|---|---|
B | 90 | 90 | 88 |
D | 90 | 90 | 87 |
E | 100 | 100 | 100 |
df.drop_duplicates(keep=False)
python | c++ | java | |
---|---|---|---|
B | 90 | 90 | 88 |
D | 90 | 90 | 87 |
映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定
包含三种操作:
使用replace()函数,对values进行替换操作
s1 = Series(data = [100,'peppa',np.nan,'chengdu'])
s1
结果为:
0 100
1 peppa
2 NaN
3 chengdu
dtype: objec
单值替换 普通替换
s1.replace(to_replace="peppa",value="佩琪")
结果为:
0 100
1 佩琪
2 NaN
3 chengdu
dtype: object
单值替换 字典替换( )
s1.replace({"chengdu":"成都"})
结果为:
0 100
1 peppa
2 NaN
3 成都
dtype: object
多值替换 列表替换 s1.replace([要替换的值1,要替换的值2,…],[替换成什么1,替换成什么2,…])
s1.replace([100,np.nan],["满分","空值"])
结果为:
0 满分
1 peppa
2 空值
3 chengdu
dtype: object
多值替换 字典替换( { 要替换的值:替换成什么,要替换的值:替换成什么 } )
s1.replace({100:"满分","peppa":"佩琪"})
结果为:
0 满分
1 佩琪
2 NaN
3 chengdu
dtype: object
Series参数说明:
s2 = Series(data=np.array([80,100,100,100,89,78]))
s2
结果为:
0 80
1 100
2 100
3 100
4 89
5 78
dtype: int32
如果指定value不好 还可以找值来填充
s2.replace(to_replace=100,method="bfill") # 从后面找值来替换当前值
结果为:
0 80
1 89
2 89
3 89
4 89
5 78
dtype: int32
s2.replace(to_replace=100,method="ffill") # 从前面找
结果为:
0 80
1 80
2 80
3 80
4 89
5 78
dtype: int32
s2.replace(to_replace=100,method="ffill",limit=1) # limit 指定是最多往前或者往后找几个, 如果找不到就不填充了 ,limit 默认是None不限制
结果为:
0 80
1 80
2 100
3 100
4 89
5 78
dtype: int32
单值替换
多值替换
df = pd.read_excel("../data/data.xls",sheet_name=0)
df
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
A | 甲 | NaN | NaN | NaN | Beijing |
B | 乙 | 69.0 | 142.0 | 29 | Beijing |
C | 丙 | 111.0 | 7.0 | 2 | Beijing |
D | 丁 | 139.0 | 19.0 | 125 | shanghai |
E | 戊 | 12.0 | 66.0 | Beijing | shanghai |
普通的单值替换
df.replace(to_replace='Beijing',value='北京')
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
A | 甲 | NaN | NaN | NaN | 北京 |
B | 乙 | 69.0 | 142.0 | 29 | 北京 |
C | 丙 | 111.0 | 7.0 | 2 | 北京 |
D | 丁 | 139.0 | 19.0 | 125 | shanghai |
E | 戊 | 12.0 | 66.0 | 北京 | shanghai |
按列指定单值换目标值 ({列索引,待替换值},目标值)
df.replace({4:'Beijing'},'首都')
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
A | 甲 | NaN | NaN | NaN | 首都 |
B | 乙 | 69.0 | 142.0 | 29 | 首都 |
C | 丙 | 111.0 | 7.0 | 2 | 首都 |
D | 丁 | 139.0 | 19.0 | 125 | shanghai |
E | 戊 | 12.0 | 66.0 | Beijing | shanghai |
多值替换 列表替换,replace([要替换的1,要替换的2…],[替换成1,替换成2])
df.replace([66,'甲','shanghai'],[100,'first','上海'])
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
A | first | NaN | NaN | NaN | Beijing |
B | 乙 | 69.0 | 142.0 | 29 | Beijing |
C | 丙 | 111.0 | 7.0 | 2 | Beijing |
D | 丁 | 139.0 | 19.0 | 125 | 上海 |
E | 戊 | 12.0 | 100.0 | 北京 | 上海 |
多值替换 字典替换,replace({要替换的1:替换成的值1,要替换的2:替换成的值2,…}) 可以将没有的值也放在这里 不会报错 将来可以整个项目使用一个过滤器,我们可以在 字典里面写很多值 字典中的值即使找不到也不会报错
df.replace({66:100,'乙':'second','Beijing':'BEIJING','没有的值':'也可以放'})
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
A | 甲 | NaN | NaN | NaN | BEIJING |
B | second | 69.0 | 142.0 | 29 | BEIJING |
C | 丙 | 111.0 | 7.0 | 2 | BEIJING |
D | 丁 | 139.0 | 19.0 | 125 | shanghai |
E | 戊 | 12.0 | 100.0 | BEIJING | shanghai |
注意:DataFrame中,无法使用method和limit参数
============================================
练习19:
假设张三李四的成绩单里有满分的情况,老师认为是作弊,把所有满分的情况(包括150,300分)都记0分,如何实现?
============================================
data = [[150,300],[150,300]]
index = ["张三","李四"]
columns = ["数学","理综"]
df = DataFrame(data,index,columns)
df
数学 | 理综 | |
---|---|---|
张三 | 150 | 300 |
李四 | 150 | 300 |
替换多个
df.replace({150:0,300:0})
df.replace([150,300],[0,0])
数学 | 理综 | |
---|---|---|
张三 | 0 | 0 |
李四 | 0 | 0 |
单值替换
df1 = df.replace(to_replace=150,value=0)
df1 = df.replace({"数学":150},0)
数学 | 理综 | |
---|---|---|
张三 | 0 | 300 |
李四 | 0 | 300 |
df1.replace(to_replace=300,value=0)
df1.replace({"理综":300},0)
数学 | 理综 | |
---|---|---|
张三 | 0 | 300 |
李四 | 0 | 300 |
注意 map()中不能使用sum之类的函数,for循环
score = pd.read_excel('./data.xls',sheet_name=1)
score
姓名 | 语文 | 数学 | python | php | |
---|---|---|---|---|---|
0 | 小明 | 90 | 98 | 90 | 98 |
1 | 小红 | 44 | 89 | 44 | 89 |
2 | 小芳 | 98 | 90 | 90 | 98 |
3 | 小李 | 89 | 44 | 44 | 89 |
4 | 李元芳 | 78 | 98 | 98 | 87 |
5 | 狄仁杰 | 66 | 44 | 44 | 89 |
映射字典
map_dic = {'小明':'北京','小红':'上海','小芳':'北京',
'小李':'广州','李元芳':'成都','狄仁杰':'成都'}
map函数不是DataFrame的方法,而是Sereis对象的方法, 可以传入映射字典
score["姓名"].map(map_dic)
结果为:
0 北京
1 上海
2 北京
3 广州
4 成都
5 成都
Name: 姓名, dtype: object
score["所在城市"] = score["姓名"].map(map_dic) # 可以传入字典
score
姓名 | 语文 | 数学 | python | php | 所在城市 | |
---|---|---|---|---|---|---|
0 | 小明 | 90 | 98 | 90 | 98 | 北京 |
1 | 小红 | 44 | 89 | 44 | 89 | 上海 |
2 | 小芳 | 98 | 90 | 90 | 98 | 北京 |
3 | 小李 | 89 | 44 | 44 | 89 | 广州 |
4 | 李元芳 | 78 | 98 | 98 | 87 | 成都 |
5 | 狄仁杰 | 66 | 44 | 44 | 89 | 成都 |
还可以传入 拉姆达表达式 如 lambda x:x+10
score["python"]= score["python"].map(lambda x:x+10)
score #python数据加10
姓名 | 语文 | 数学 | python | php | 所在城市 | |
---|---|---|---|---|---|---|
0 | 小明 | 90 | 98 | 100 | 98 | 北京 |
1 | 小红 | 44 | 89 | 54 | 89 | 上海 |
2 | 小芳 | 98 | 90 | 100 | 98 | 北京 |
3 | 小李 | 89 | 44 | 54 | 89 | 广州 |
4 | 李元芳 | 78 | 98 | 108 | 87 | 成都 |
5 | 狄仁杰 | 66 | 44 | 54 | 89 | 成都 |
还可以传入自定义函数
def fn(x):
return x-20
score["php"]= score["php"].map(fn) #这里一定要注意,是把函数名传入,千万不要加小括号去调用
score
姓名 | 语文 | 数学 | python | php | 所在城市 | |
---|---|---|---|---|---|---|
0 | 小明 | 90 | 98 | 100 | 18 | 北京 |
1 | 小红 | 44 | 89 | 54 | 9 | 上海 |
2 | 小芳 | 98 | 90 | 100 | 18 | 北京 |
3 | 小李 | 89 | 44 | 54 | 9 | 广州 |
4 | 李元芳 | 78 | 98 | 108 | 7 | 成都 |
5 | 狄仁杰 | 66 | 44 | 54 | 9 | 成都 |
data = np.random.randint(0,150,size=(5,3))
columns = ['python','java','php']
index = ['peppa','mery','tom','jack','rose']
df = DataFrame(data,index,columns)
df
python | java | php | |
---|---|---|---|
peppa | 23 | 98 | 81 |
mery | 33 | 31 | 74 |
tom | 59 | 24 | 101 |
jack | 56 | 143 | 96 |
rose | 94 | 13 | 89 |
def map_score(x):
if x>120:
return "exellent"
elif x<90:
return "failed"
else:
return "pass"
df["phpx"]= df["php"].map(map_score)
df
python | java | php | phpx | |
---|---|---|---|---|
peppa | 23 | 98 | 81 | failed |
mery | 33 | 31 | 74 | failed |
tom | 59 | 24 | 101 | pass |
jack | 56 | 143 | 96 | pass |
rose | 94 | 13 | 89 | failed |
对DataFrame的索引名进行更改,仍然是新建一个字典
score = pd.concat((df,df),keys=['A','B'],axis=1)
score
A | B | |||||||
---|---|---|---|---|---|---|---|---|
python | java | php | phpx | python | java | php | phpx | |
peppa | 23 | 98 | 81 | failed | 23 | 98 | 81 | failed |
mery | 33 | 31 | 74 | failed | 33 | 31 | 74 | failed |
tom | 59 | 24 | 101 | pass | 59 | 24 | 101 | pass |
jack | 56 | 143 | 96 | pass | 56 | 143 | 96 | pass |
rose | 94 | 13 | 89 | failed | 94 | 13 | 89 | failed |
map_dic = {'peppa':'帅气','mery':'美丽','python':'蟒蛇',
'java':'咖啡','php':'拍黄片','A':'上','B':'下'}
score.rename(map_dic) # 默认是替换 行的名称
A | B | |||||||
---|---|---|---|---|---|---|---|---|
python | java | php | phpx | python | java | php | phpx | |
帅气 | 23 | 98 | 81 | failed | 23 | 98 | 81 | failed |
美丽 | 33 | 31 | 74 | failed | 33 | 31 | 74 | failed |
tom | 59 | 24 | 101 | pass | 59 | 24 | 101 | pass |
jack | 56 | 143 | 96 | pass | 56 | 143 | 96 | pass |
rose | 94 | 13 | 89 | failed | 94 | 13 | 89 | failed |
score.rename(columns=map_dic) # 指定columns可以对列名称进行替换
上 | 下 | |||||||
---|---|---|---|---|---|---|---|---|
蟒蛇 | 咖啡 | 拍黄片 | phpx | 蟒蛇 | 咖啡 | 拍黄片 | phpx | |
peppa | 23 | 98 | 81 | failed | 23 | 98 | 81 | failed |
mery | 33 | 31 | 74 | failed | 33 | 31 | 74 | failed |
tom | 59 | 24 | 101 | pass | 59 | 24 | 101 | pass |
jack | 56 | 143 | 96 | pass | 56 | 143 | 96 | pass |
rose | 94 | 13 | 89 | failed | 94 | 13 | 89 | failed |
score.rename(columns=map_dic,level=0) # 通过level参数 可以指定具体对哪一层级进行替换
上 | 下 | |||||||
---|---|---|---|---|---|---|---|---|
python | java | php | phpx | python | java | php | phpx | |
peppa | 23 | 98 | 81 | failed | 23 | 98 | 81 | failed |
mery | 33 | 31 | 74 | failed | 33 | 31 | 74 | failed |
tom | 59 | 24 | 101 | pass | 59 | 24 | 101 | pass |
jack | 56 | 143 | 96 | pass | 56 | 143 | 96 | pass |
rose | 94 | 13 | 89 | failed | 94 | 13 | 89 | failed |
score.rename(columns=map_dic,level=1) # 0 是最外层
A | B | |||||||
---|---|---|---|---|---|---|---|---|
蟒蛇 | 咖啡 | 拍黄片 | phpx | 蟒蛇 | 咖啡 | 拍黄片 | phpx | |
peppa | 23 | 98 | 81 | failed | 23 | 98 | 81 | failed |
mery | 33 | 31 | 74 | failed | 33 | 31 | 74 | failed |
tom | 59 | 24 | 101 | pass | 59 | 24 | 101 | pass |
jack | 56 | 143 | 96 | pass | 56 | 143 | 96 | pass |
rose | 94 | 13 | 89 | failed | 94 | 13 | 89 | failed |
score.rename(columns=map_dic,level=-1)
A | B | |||||||
---|---|---|---|---|---|---|---|---|
蟒蛇 | 咖啡 | 拍黄片 | phpx | 蟒蛇 | 咖啡 | 拍黄片 | phpx | |
peppa | 23 | 98 | 81 | failed | 23 | 98 | 81 | failed |
mery | 33 | 31 | 74 | failed | 33 | 31 | 74 | failed |
tom | 59 | 24 | 101 | pass | 59 | 24 | 101 | pass |
jack | 56 | 143 | 96 | pass | 56 | 143 | 96 | pass |
rose | 94 | 13 | 89 | failed | 94 | 13 | 89 | failed |
使用rename()函数替换行索引
使用 df.describe() 函数查看每一列的描述性统计量
data = np.random.randn(1000,5)
df = DataFrame(data)
df
df.describe()
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
count | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 |
mean | -0.041642 | 0.013773 | 0.014445 | 0.019873 | 0.042694 |
std | 1.025455 | 1.013594 | 0.983300 | 1.006718 | 0.968992 |
min | -2.977845 | -3.063590 | -3.032535 | -2.888868 | -3.191746 |
25% | -0.703325 | -0.712109 | -0.645296 | -0.644217 | -0.597502 |
50% | -0.054138 | 0.057187 | 0.001426 | 0.020060 | 0.057830 |
75% | 0.664146 | 0.704886 | 0.653665 | 0.690365 | 0.725881 |
max | 3.777147 | 3.113222 | 3.149599 | 3.305668 | 3.050308 |
使用std()函数可以求得DataFrame对象每一列的标准差
df.std()
结果为:
0 1.025455
1 1.013594
2 0.983300
3 1.006718
4 0.968992
dtype: float64
根据每一列或行的标准差,对DataFrame元素进行过滤。
借助any()或all()函数, 测试是否有True,有一个或以上返回True,反之返回False
对每一列应用筛选条件,去除标准差太大的数据
# 寻找异常数据 太大的 或者 太小的
df.mean() # 各个列的平均值 是一个Series
df - df.mean() # DataFrame - Series DataFrame中的每一行都和Series做减法 对应的列相减
df - df.mean() > 3*df.std()
(df - df.mean() > 3*df.std()).any()
(df - df.mean() > 3*df.std()).any(axis=1) #
df[(df - df.mean() > 3*df.std()).any(axis=1)] #找到异常的行
删除特定索引df.drop(labels,inplace = True)
drop_idx = df[(df - df.mean() > 3*df.std()).any(axis=1)].index
df.drop(drop_idx).shape
============================================
练习:
新建一个形状为10000*3的标准正态分布的DataFrame(np.random.randn),去除掉所有满足以下情况的行:其中任一元素绝对值大于3倍标准差
============================================
可以借助np.random.permutation()函数随机排序
data = np.random.randint(0,100,size=(5,5))
index = list('ABCDE')
columns = list('甲乙丙丁戊')
df = DataFrame(data=data,index=index,columns=columns)
df
甲 | 乙 | 丙 | 丁 | 戊 | |
---|---|---|---|---|---|
A | 19 | 22 | 59 | 34 | 79 |
B | 43 | 71 | 71 | 25 | 77 |
C | 46 | 63 | 43 | 14 | 66 |
D | 89 | 46 | 86 | 33 | 40 |
E | 36 | 79 | 66 | 68 | 67 |
df.take([3,2,1]) # 按照索引去取行 顺序随意 还可以重复 还可以不完全
甲 | 乙 | 丙 | 丁 | 戊 | |
---|---|---|---|---|---|
D | 89 | 46 | 86 | 33 | 40 |
C | 46 | 63 | 43 | 14 | 66 |
B | 43 | 71 | 71 | 25 | 77 |
df.take([3,3,3,3])
甲 | 乙 | 丙 | 丁 | 戊 | |
---|---|---|---|---|---|
D | 89 | 46 | 86 | 33 | 40 |
D | 89 | 46 | 86 | 33 | 40 |
D | 89 | 46 | 86 | 33 | 40 |
D | 89 | 46 | 86 | 33 | 40 |
np.random.permutation(5)
结果为:
array([3, 1, 4, 2, 0])
df.take(np.random.permutation(5)) # 随机排序 (行不会少 也不会重复 只是顺序随机变换)
甲 | 乙 | 丙 | 丁 | 戊 | |
---|---|---|---|---|---|
B | 43 | 71 | 71 | 25 | 77 |
D | 89 | 46 | 86 | 33 | 40 |
C | 46 | 63 | 43 | 14 | 66 |
A | 19 | 22 | 59 | 34 | 79 |
E | 36 | 79 | 66 | 68 | 67 |
当DataFrame规模足够大时,直接使用np.random.randint()函数,就配合take()函数实现随机抽样
df.take(np.random.randint(0,5,size=2)) # 随机抽样
甲 | 乙 | 丙 | 丁 | 戊 | |
---|---|---|---|---|---|
B | 43 | 71 | 71 | 25 | 77 |
C | 46 | 63 | 43 | 14 | 66 |
数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。
数据分类处理:
数据分类处理的核心:
- groupby()函数
- groups属性查看分组情况
In [547]:
df = DataFrame({'item':['苹果','香蕉','橘子','香蕉','橘子','苹果','苹果'],
'price':[4,3,3,2.5,4,2,2.8],
'color':['red','yellow','yellow','green','green','green','yello'],
'weight':[12,20,50,30,20,44,37]})
df
item | price | color | weight | |
---|---|---|---|---|
0 | 苹果 | 4.0 | red | 12 |
1 | 香蕉 | 3.0 | yellow | 20 |
2 | 橘子 | 3.0 | yellow | 50 |
3 | 香蕉 | 2.5 | green | 30 |
4 | 橘子 | 4.0 | green | 20 |
5 | 苹果 | 2.0 | green | 44 |
6 | 苹果 | 2.8 | yello | 37 |
df.groupby("item").groups
结果为:
{'橘子': Int64Index([2, 4], dtype='int64'),
'苹果': Int64Index([0, 5, 6], dtype='int64'),
'香蕉': Int64Index([1, 3], dtype='int64')}
df.groupby("item")["weight"].sum() #各类水果的总重量
结果为:
item
橘子 70
苹果 93
香蕉 50
Name: weight, dtype: int64
df2 = DataFrame(df.groupby("item")["weight"].sum())
df2
weight | |
---|---|
item | |
橘子 | 70 |
苹果 | 93 |
香蕉 | 50 |
pd.merge(df,df2,on="item",how="outer",suffixes=["","_total"])
item | price | color | weight | weight_total | |
---|---|---|---|---|---|
0 | 苹果 | 4.0 | red | 12 | 93 |
1 | 苹果 | 2.0 | green | 44 | 93 |
2 | 苹果 | 2.8 | yello | 37 | 93 |
3 | 香蕉 | 3.0 | yellow | 20 | 50 |
4 | 香蕉 | 2.5 | green | 30 | 50 |
5 | 橘子 | 3.0 | yellow | 50 | 70 |
6 | 橘子 | 4.0 | green | 20 | 70 |