大数据竞赛基础知识


numpy

一、创建ndarray

import numpy as np
print(np.__version__)

1. 使用np.array()由python list创建

import numpy as np
n1 = np.array([1,2,3,4,5])
print(n1)
print(type(n1))

2. 使用np的函数创建

1. np.ones(shape, dtype=None, order=’C’)

  • 生成由1组成的数组
  • shape可以指定数字或元祖
import numpy as np
n1 = np.ones(shape = (2,3),dtype=np.int16)
print(n1)

2. np.zeros(shape, dtype=float, order=’C’)

  • 生成由0组成的数组
  • shape可以指定数字或元祖
import numpy as np
n1 = np.zeros(shape=(4,5),dtype=np.int16)
print(n1)

3. np.full(shape, fill_value, dtype=None, order=’C’)

  • 生成自定义填充内容的数组
  • shape可以指定数字或元祖
  • fill_value指定填充内容,格式为数字
import numpy as np
n1 = np.full(shape = (3,5),fill_value=9,dtype=int)
print(n1)

4. np.eye(N, M=None, k=0, dtype=float)

  • 对角线为1其他的位置为0
  • N,M指定行数列数
  • k代表偏移值,为正右偏移,为负左偏移
import numpy as np
n1 = np.eye(5,5,-1)
print(n1)

5. np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

  • 对一个数值区间进行等分
  • start,stop起始值
  • num等分的份数
  • endpoint是否使用末尾值
  • retstep是否显示步长
import numpy as np
n1 = np.linspace(0,100,20)
print(n1)

6. np.arange([start, ]stop, [step, ]dtype=None)

  • 生成一个等差数列
  • start,stop起始值
  • step步长默认为1
import numpy as np
n1 = np.arange(0,100,10)
print(n1)

7. np.random.randint(low, high=None, size=None, dtype=’l’)

  • 在一个指定的数值区间内生成随机整数的数组
  • low,high最大值最小值
  • size数组样式,可以为数字或数组
import numpy as np
n1 = np.random.randint(10,20,size = 10)
print(n1)

8.np.random.random(size=None)

  • 生成0到1的随机数
import numpy as np
n1 = np.random.random(size = 10)
print(n1)

9. np.random.randn(d0, d1, …, dn)

  • 生成标准正态分布的样本集
  • 标准正太分布 np.random.normal()
import numpy as np
n1 = np.random.randn(4,4)
print(n1)

二、ndarray属性

  • ndim : 维度(数组每次新增的轴,也就是最外围的维度,都为 0,也就是axis = 0都是新增的维度)
  • shape : 形状
  • size : 数组元素的个数
  • dtype : 元素类型
    1)int(整数):包括 8-64 位的长度;
    2)float(浮点数):包括 16-64 位的长度;
    3)unit(无符号整数):包括 8-64 位的长度;
    4)bool(布尔类型)。
import numpy as np
n1 = np.array([[1,2,3,4,5,6],[10,11,12,13,14,15]])
print(n1.ndim,n1.shape,n1.size,n1.dtype)

三、操作

1. 索引

下标索引

import numpy as np
l1 = [[1,2,3,4,5],[10,11,12,13,14]]
n1 = np.array(l1)
#两种方法等效
print(n1[0][0])
print(n1[0,0])

布尔索引

import numpy as np

l1 = [[1,2,3,4,5],[10,1,12,13,14]]
n1 = np.array(l1)

# 通过数组的逻辑运算后,我们得到的结果是一个与原数组维度和长度都一样的布尔数组
print(n1<3)
# 布尔索引即通过一个布尔数组来索引目标数组,找出目标数组中与布尔数组中值为 True 的对应的数据
print(n1[n1<3])

注意:符合条件的元素会以一维数组的形式返回,通过布尔索引,我们可以很快找出数组中满足既定条件的部分元素。

2. 切片

import numpy as np
n2 = np.arange(10)
print(n2)
print(n2[-3:])
print(n2[::-1])
print(n2[4:7])
n3 = np.ones(shape = (5,5),dtype=np.int16)
print(n3)
print(n3[-3:,-1:])
print(n3[:,2:4])
print(n3[:,::-1])

3. 变形

  • n1.reshape()
  • 传入一个元祖
  • 改变的size必须和原size相同
import numpy as np
n4 = np.random.randint(100,150,size = 24).reshape((5,5))
print(n4)
print(n4.shape)
  • 参数-1为自动计算
  • 不能两个参数都为-1
import numpy as np
n4 = np.random.randint(100,150,size = 24).reshape((4,-1))
print(n4)
print(n4.shape)

4. 级联

np.concatenate() 级联需要注意的点:

  1. 级联的参数是列表:一定要加中括号或小括号
  2. 维度必须相同
  3. axis方向对应的形状可以不相符
  4. 级联的方向默认是shape这个tuple的第一个值所代表的维度方向
  5. 可通过axis参数改变级联的方向
函数 说明 备注
np.concatenate((n1,n2),axis=None) 级联 # axis指定级联方向取值0 or 1
np.hstack((n1,n2)) 水平级联 \
np.vstack((n1,n2)) 垂直级联 \
n1 = np.ones(shape = (2,3),dtype=np.int16)
print(n1)

n2 = np.zeros(shape=(2,3),dtype=np.int16)
print(n2)

print(np.concatenate((n1,n2),axis=0))

5. 切分

函数 说明
np.split 切分
np.vsplit 竖向切分
np.hsplit 横向切分
x = np.array([0,1,2,3,4,5,6,7,8])
print(np.split(x,3))

6. 副本

n2 = n1.copy()

四、方法

函数 NaN-safe Version 说明
n1.sum() np.nansum() 求和
n1.max() np.nanmax() 求最大值
n1.min() np.nanmin() 求最小值
n1.mean() np.anmean() 求平均数
n1.argmax() np.nanaremax() 最大值的索引
n1.argmin() np.nanargmin() 最小值的索引
np.prod() np.nanprod() 连乘
np.std() np.nanstd() 方差
import numpy as np
x = np.array([10,11,12,13,14])
print(x.sum())

五、向量运算

1.形状相同时

两个数组 a 和 b 形状相同,即满足a.shape == b.shape

import numpy as np

# 创建数组 a
a = np.array([[0, 0, 0],
              [10, 10, 10],
              [20, 20, 20]])

# 创建数组 b
b = np.array([[0, 0, 0],
              [10, 10, 10],
              [20, 20, 20]])

# 加法
result_1 = a + b
print(result_1)
# 乘法
result_2 = a*b
print(result_2)

2.形状不同时(广播机制)

广播:两个形状不同数组间运算时,它们对应维度的长度必须相同,或者其中一方为 1,才可以运算成功,否则就会报错。

#【重要】ndarray广播机制的两条规则
#规则一:为缺失的维度补1
#规则二:假定缺失元素用已有值填充
import numpy as np

# 创建数组 a
a = np.array([1, 2, 3])

# 创建标量 b
b = 2

# 数组 a 与标量 b 相乘,并将结果赋值给 result_3
result_3 = a*b 
print(result_3)
import numpy as np

# 创建数组 a
a = np.array([[0, 0, 0],
              [10, 10, 10],
              [20, 20, 20],
              [30, 30, 30]])
print(a.shape)
            
# 创建数组 b
b = np.array([0, 1, 2])
print(b.shape)
   
result_4 = a + b
print(result_4)

六、排序

函数 说明 备注
n.sort() 快速排序 np.sort()不改变输入
np.sort(n) 快速排序 ndarray.sort()本地处理,不占用空间,但改变输入
np.partition(a,k) 部分排序 当k为正时,我们想要得到最小的k个数
当k为负时,我们想要得到最大的k个数
import numpy as np

# 创建数组 a
a = np.array([1, 7, 3])

print(np.sort(a))
# 没有改变原数据
print(a)

print(a.sort())
# 改变原数据
print(a)

Pandas

import numpy as np
import pandas as pd
from pandas import Series,DataFrame

一、Series

Series是一种类似与一维数组的对象,由下面两个部分组成:

  • values:一组数据(ndarray类型)
  • index:相关的数据索引标签

1. Series的创建

1. 由列表或numpy数组创建

l2 = np.array([150,150,150,300])
s1 = Series(data = l2,index = ['语文','数学','英语','理综'])
print(s1)

还可以通过设置index参数指定索引

#默认索引为0到N-1的整数型索引
s1 = Series(np.arange(0,6,1),index = list('abcdef'))
print(s1)
s1.index = list('abcdef')
print(s1.index)

特别地,由ndarray创建的是引用,而不是副本。对Series元素的改变也会改变原来的ndarray对象中的元素。(列表没有这种情况)

# 列表
n1 = [1,2,3,4,5]
s1 = Series(n1)
print(s1)
n1[0] = 100
print(s1)
# numpy数组
n2 = np.array([10,11,12,13,14,15])
s2 = Series(n2)
print(s2)
n2[0] = 100
print(s2)

2. 由字典创建

  • Key作为index,value作为values
d1 = {'语文':150,'数学':150,'英语':150,'理综':300}
s1 = Series(d1)
print(s1)
  • 必须传入一维的数据,多维会报错
# 多维的数组 error
n1 = np.random.randn(3,2)
Series(n1)

2. Series的索引和切片

1. 索引

可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的仍然是一个Series类型)。分为显示索引和隐式索引:

(1) 显式索引:
  • 使用index中的元素作为索引值
s1 = Series(data = [1,2,3,4,5],index = list('ABCDE'))
print(s1['A'])
print(s1.loc['A'])
(2) 隐式索引:
  • 使用整数作为索引值
s1 = Series(data = [1,2,3,4,5],index = list('ABCDE'))
print(s1.iloc[0])
d1 = {'yuwen':150,'shuxue':150,'yingyu':150,'lizong':300}
s8 = Series(d1)
s8.index = ['理综','数学','英语','语文']
print(s8['数学'],s8.loc['数学'],s8.iloc[1])

2. 切片

a1 = np.array([1,2,3,4,5])
print(a1[1:3])
s1 = Series(data = [1,2,3,4,5],index = list('ABCDE'))
print(s1['A':'D'])
print(s1.loc['A':'D'])
# 使用.iloc[]注意,此时是右开区间
print(s1.iloc[0:4])

3. Series属性和方法

  1. 可以把Series看成一个定长的有序字典

  2. 可以通过shape、size、index、values等得到series的属性

  3. 可以使用head()tail()分别查看前n个和后n个值(当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况)

s1 = Series(data = [1,2,3,4,5,6,7],index = list('abcdefg'))
print(s1.head())
print(s1.tail())
  1. 可以使用pd.isnull()pd.notnull(),或自带isnull()notnull()函数检测缺失数据
# 返回的仍然是一个Series对象
s.isnull()
s.notnull()
  1. 求和函数
s1 = Series(data = [1,2,3,4],index = list('abcd'))
print(np.sum(s1))

4. Series的运算

  1. 适用于numpy的数组运算也适用于Series
  2. Series之间的运算
  • 在运算中自动对齐不同索引的数据
  • 如果索引不对应,则补NaN
  • NaN和任何数运算,结果都为NaN
s1 = Series(data = [1,2,3,4],index = list('abcd'))
s2 = Series(data = [5,6,7,8],index = list('cdef'))
s = s1 + s2
print(s)
print(s.isnull())
print(s.notnull())

我在这里补充一下

Series和列表类型都是用来装一列一维数据的容器,但其不仅运算速度快很多,也提供了很多方便的方法,做数据运算更加有效率,我们先来看看如果让列表中每个元素相加。

list1 = [1, 2, 3, 4]
list2 = [5, 6, 2, 3]
list_new = []

# 直接相加是列表的拼接
# list_new = list1 + list2
# print(list_new)

# 实现列表中的每一个元素相加
for i in range(len(list1)):
    list_new.append(list1[i] + list2[i])
print(list_new)

再看看Series是如何实现的,提供了哪些方法。

n1 = np.array([np.nan,2,3,4])
n2 = np.array([3,4,3,np.nan])
s1 = Series(n1)
s2 = Series(n2)
s1.add(s2,fill_value = 0)		#加
s1.sub(s2,fill_value = 0)		#减
s1.mul(s2,fill_value = 1)		#乘
s1.div(s2,fill_value = 1)		#除
#fill_value在元素中包nan时所替代的值

5.Series数据处理

import pandas as pd

series = pd.Series([1, 2, 3, 4])
# 使用 add 方法将每个元素加1
result = series.add(1)
print(result)

series = pd.Series(["Hello", "World", "!"])
# 使用 str.cat 方法将每个元素拼接成一个字符串
result = series.str.cat(sep=" ")
print(result)

data = pd.Series(['ABC123', 'DEF456', 'GHI789'])
# 使用正则表达式提取部分字符
pattern = r'(\d+)'  # 提取连续的数字
extracted_data = data.str.extract(pattern)

print(extracted_data)

二、DataFrame

DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。

  • 行索引:index
  • 列索引:columns
  • 值:values(numpy的二维数组)

1. DataFrame的创建

  • 最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。
  • 字典中的键所对应的值的长度是一样的,不然会报错。
  • 此外,DataFrame会自动加上每一行的索引(和Series一样)。
  • 同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。
  • DataFrame属性:values、columns、index、shape

通过字典创建

dic1 = {'name':['dancer','lucy','mery'],'age':[19,19,20],'address':['beijing','shanghai','guangzhou']}
# columns 列索引
df1 = DataFrame(data = dic1,index = [0,1,2])
print(df1)
dic1 = {'张三':[150,150,150,300],'李四':[0,0,0,0]}
indexs = ['语文','数学','英语','理综']

df1 = DataFrame(data = dic1,index = indexs)
print(df1)

通过numpy.ndarray创建

data = np.random.randint(0,150,size = 5*5).reshape((5,5))
index = ['dancer','lucy','mery','tom','jack']
columns = ['python','c++','c#','php','java']
df2 = DataFrame(data = data, index = index, columns = columns)
print(df2)
# 这里做一个实验,DataFrame的一列或者一行其实就是一个Series
print(type(df2))
print(type(df2['python']))
print(type(df2.loc['dancer']))

通过Series创建

s1 = Series(data = np.arange(0,10,1),index = list('abcdefghij'))
s1 = DataFrame(s1)
print(s1)

通过多维列表创建

data = [[150,0],[150,0],[150,0],[300,0]]
columns = ['张三','李四']
indexs = ['语文','数学','英语','理综']
df = DataFrame(data = data,columns = columns,index = indexs)
print(df)

注意:DataFrame的一列或者一行其实就是一个Series,Series可以看作一维的DataFrame。

2.DataFrame的索引

dic1 = {'张三':[120,130,140,300],'李四':[0,0,0,0]}
indexs = ['语文','数学','英语','理综']
df1 = DataFrame(data = dic1,index = indexs)
# 列索引返回的Series拥有原DataFrame相同的索引,且name属性就是相应的列名。
# 通过类似字典的方式
print(df1['张三'])
# 通过属性的方式
print(df1.张三)
# 行索引只支持loc或iloc方法进行索引
# 行索引返回一个Series,index为原来的columns。
# loc只能是显式索引
# iloc只能是隐式索引
print(df1.loc['数学'])
print(df1.iloc[3])
# 对元素索引
print(df1.loc['语文']['张三'])
print(df1.iloc[0]['张三'])
print(df1.loc['语文'].张三)
# 直接用中括号切片,[行切片,列切片]
print(df1.iloc[1:3,:1])
data = np.random.randint(0,150,size = (5,5))
columns = ['小明','小芳','小花','小红','小蔡']
indexs = ['语文','数学','英语','思想品德','社会']
df = DataFrame(data = data, columns = columns, index = indexs)
# 索引
print(df['小花'])
print(df.loc['语文'])
print(df.iloc[:,2:3])
# 赋值
df.loc['语文']['小明'] += 100
print(df)
# 求平均值
print(df.loc['社会'].mean())
print(df['小花'].mean())
# 副本
xiaoming = df['小明'].copy()
print(xiaoming)
df['小明'] = df['小花']
print(df)

3.DataFrame的级联

n1 = np.random.randint(0,100,25).reshape(5,5)
df1 = DataFrame(n1)
print(df1)
n2 = np.random.randint(0,100,36).reshape(6,6)
df2 = DataFrame(n2)
print(df2)

df3 = pd.concat((df1,df2),axis=1)
print(df3)

三、Pandas文件读写

1.读取

pandas提供了一些用于将表格型数据读取为DataFrame对象的函数,期中read_csv和read_table这两个使用最多

file = pd.read_csv("movie_data.csv")
print(file)
file = pd.read_json('movie_data.json')
print(file)
# sheet_name可以指定工作表
file = pd.read_excel('movie_data.xlsx')
print(file)

注意:如果读出来乱码,可能是编码问题,可选参数 encoding,常用编码utf-8

2. 写入

data = np.random.randint(0,150,size = (100,5))
df = DataFrame(data = data,columns=['python','c++','oc','java','php'])
# index默认为True,会默认把行索引也写入到文件
df.to_excel('score.xlsx',encoding = 'utf-8',index = False)

注意点

在以下的案例中,pd.read_csv 在读取的时候给我们又重新生成一个从 0 开始的整数索引,但是我们并不需要新的index,我们就希望存进去的时候什么样,读出来就什么样,你可以通过index_col指定哪一列为index。

import pandas as pd
from pandas import Series,DataFrame

data = [[150,0],[150,0],[150,0],[300,0]]
columns = ['张三','李四']
indexs = ['语文','数学','英语','理综']
df = DataFrame(data = data,columns = columns,index = indexs)
print(df)

df.to_csv('123.csv',encoding='utf-8')

file = pd.read_csv('123.csv',encoding='utf-8',index_col=0)
print(file)

3.读写sqlite文件

  • vscode可以安装sqlite插件
import sqlite3 as sqlite3
# 跟数据库建立连接
connection = sqlite3.connect('./db.sqlite')
# 读取数据库文件
data = pd.read_sql("select* from movie_data",connection)
print(data)
# 写入数据库
print(data.to_sql("score_data",connection,if_exists="replace"))

四、pandas数据处理

import numpy as np
import pandas as pd
from pandas import Series,DataFrame

分组聚合

数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。
数据分类处理:

  • 分组:先把数据分为几组
  • 用函数处理:为不同组的数据应用不同的函数以转换数据
  • 合并:把不同组得到的结果合并起来

数据分类处理的核心:

  • groupby()函数
  • groups属性查看分组情况
方法 作用
min() 最小值
max() 最大值
std() 标准差
mean() 平均值
median() 中位数
sum() 总和
count() 数量
value_count() 频数分布
grade_df = pd.DataFrame({'班级': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
                         '性别': ['男', '男', '女', '女', '女', '男', '男', '男', '女', '女'],
                         '眼镜': ['是', '否', '是', '否', '是', '是', '是', '否', '否', '否'],
                         '成绩': [95, 90, 96, 92, 94, 85, 87, 80, 81, 86]})
print(grade_df)

# 单层分组聚合
# 对班级进行分组聚合操作
#                     分组操作          聚合操作
grade_df1 = grade_df.groupby('班级')['成绩'].mean()
print(grade_df1)

# 多分层分组聚合
grade_df3 = grade_df.groupby(['班级', '性别'])['成绩'].mean()
print(grade_df3)

grade_df4 = grade_df.groupby(['性别', '班级'])['成绩'].mean()
print(grade_df4)
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]})
print(df)
# 可以通过groups属性查看分组情况,但是不要企图用DataFrame的方式展示数据
print(df.groupby('item').groups)
# 一般是进行聚合操作处理后在查看结果,这里展示查看总和的聚合操作
print(df.groupby('item').sum())
# 对weight求总和
weight_sum = DataFrame(df.groupby('item')['weight'].sum())
print(weight_sum)
# 求价格的平均值
price_mean = DataFrame(df.groupby('item')['price'].mean())
print(price_mean)
# 把总和跟df进行merge合并
# 'left_on'和'right_on'指定了左侧和右侧数据框中用于连接的列
result1 = pd.merge(df,weight_sum,how='outer',left_on='item',right_on='item',suffixes=['','_total'])
print(result1) 
# 把平均价格合并到总表里
result2 = pd.merge(result1,price_mean,how='outer',left_on='item',right_index=True,suffixes=['','_mean'])
print(result2)

使用列表进行多列分组,得到的结果是多层级索引

df = DataFrame(df.groupby(['item','color'])['weight'].max())
print(df)

练习:

  1. 以属性为列索引,创建一个DataFrame对象df

  2. 对df进行聚合操作,求出颜色为绿色的价格总和

  3. 对df进行聚合操作,求出萝卜的所有重量(包括白萝卜,胡萝卜,青萝卜)以及平均价格

  4. 使用merge合并总重量及平均价格

df1 = DataFrame({'item':['萝卜','白菜','冬瓜','辣椒','冬瓜','白菜','萝卜','辣椒'],
                'price':[4,3,3,2.5,4,2,2.8,3.5],
               'color':['red','yellow','yellow','green','green','green','red','yellow'],
               'weight':[12,20,50,30,20,44,37,25]})
print(df1)

sum = df1.groupby('color')['price'].sum()
print(sum)

weight_sum = df1.groupby('item')['weight'].sum()
price_mean = df1.groupby('item')['price'].mean()
print(weight_sum,price_mean)

# 先跟总重量合并
r1 = pd.merge(df1,DataFrame(weight_sum),how='outer',left_on='item',right_index=True,suffixes=['','_sum'])

# 跟平均价格合并
r2 = pd.merge(r1,DataFrame(price_mean),how='outer',left_on='item',right_index=True,suffixes=['','_mean'])

print(r2)

数据清洗

有两种丢失数据:

  1. None
    None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。
  2. np.nan(NaN)
    np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。
    但可以使用np.nan()函数来计算nan,此时视nan为0。
方法 作用
df.info() 查看摘要信息
df.describe() 查看描述信息
df.isna()/df.notnull() && df.isnull() /df.notnull() 查找缺失值
df.dropna(subset=[‘列名’]) 如果有缺失值,删除整行(可指定操作的列)
df.duplicated() 查找重复值
df.drop_duplicates() 删除重复值
df.fillna() 填充缺失值
df.sort_values(by=’列名’) 对某列数据进行排序
df.astype(int/str) 数据类型转换

查看描述信息

# 使用describe()函数查看每一列的描述性统计量
df1.describe()
print(df1.describe().loc['mean','rate'])

数据类型转换

data = pd.DataFrame({
    '姓名':['林某某', '许放羊', '王鱼'],
    '语文': [87, 82, 67],
    '数学':[73, 85, 90],
    '英语':['89', '95', '95']
})

# 计算每个人三门科目的总分
data['总分'] = data['语文'] + data['数学'] + data['英语'].astype(int)
print(data)

练习

# 总额 = 单价 x 数量
data = pd.DataFrame({
    '商品名':['猪头皮', '醋', '高压锅'],
    '单价': [10, 13, 800],
    '数量':['5', '2', '1']
    })

data['总额'] = data['单价'] * data['数量'].astype(int)
print(data)

数据筛选

data = pd.DataFrame({
    '姓名':['林某某', '许放羊', '王鱼'],
    '语文': [87, 82, 67],
    '数学':[73, 85, 90],
    '英语':['89', '95', '95']
})

# 筛选语文大于80的
data = data[(data['语文']>80)]
print(data)

删除重复元素

使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True

  • 使用drop_duplicates()函数删除重复的行
  • 使用duplicate()函数查看重复的行
data = {'name':['dancer','lucy','mery','dancer','jack','dancer'],'score':[100,98,78,100,87,100]}
score = DataFrame(data)
print(score)
# keep指定保留第一个还是最后一个,first保留第一个,last保留最后一个
# inplace True:修改数据的原始结构,Fasle不修改原始结构,产生新数据
# subset表示要对哪些列进去去重,如果不写默认为第一列
score1 = score.drop_duplicates(keep='last',inplace=False,subset=['name','score'])
print(score1)

过滤掉没用的行

data = {'Name': ['John', 'Alice', 'Bob'],
        'Age': [25, 30, 35],
        'Email': ['john@123.com', 'alice@example.com', 'bob@example.com']}
df = pd.DataFrame(data)

# 使用正则表达式过滤字符串
pattern = r'example'  # 过滤包含"example"的字符串
filtered_data = df[df['Email'].str.contains(pattern)]

print(filtered_data)

过滤掉每一行中没用的字符串

# 创建示例DataFrame
data = {'Name': ['John', 'Alice', 'Bob'],
        'Age': [25, 30, 35],
        'Email': ['john@example.com', 'alice@example.com', 'bob@example.com']}
df = pd.DataFrame(data)

# 使用正则表达式提取特定部分
pattern = r'(\w+)@'  # 提取@符号之前的部分
df['Email'] = df['Email'].str.extract(pattern, expand=False)

print(df)

综合练习

df = DataFrame(data = np.random.randint(5,150,size = 5*5).reshape((5,5)),columns=list('ABCDE'))
df['A'][0] = np.nan
df['E'].loc[1] = np.nan
df['B'] = np.nan
print(df)
# axis=0:index/行,axis=1:columns/列,默认为行
# how='all'表示一行中全为空才过滤,'any'表示有一个为空就过滤整行
df1 = df.dropna(axis=1,how='all')
print(df1)
# 对缺失的数据补0
df2 = df.fillna(0)
print(df2)
# 对指定列补指定的值
df3 = df.fillna({"A":10,"B":20})
print(df3)
# 用前面的值来填充,axis可以控制填充的方向
df4 = df.ffill(axis=1)
print(df4)
# 用后面的值来填充
df5 = df.bfill(axis=1)
print(df5)

替换

replace()函数:替换元素

  • 单值替换
    • 普通替换
    • 字典替换(推荐)
  • 多值替换
    • 列表替换
    • 字典替换(推荐)
单值替换
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(to_replace='dancer',value='DANCER')
print(s2)
替换数字
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(100,500)
print(s2)
替换空值

在Series里面,None值无法进行替换,np.nan是可以被替换和识别的

s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(np.nan,'空值')
print(s2)
使用字典替换
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(to_replace={'dancer':'DANCER'})
print(s2)
以后值替换
s2 = Series(data = [100,100,100,98,76],index=list('ABCDE'))
# method:对指定的值使用相邻的值填充,指定填充的方向,ffill是前面的值,bfill是后面的值
# limit 指定填充次数
# 注意:不要在使用value参数 method和limit参数不能在DataFrame中使用
sn = s2.replace(to_replace=100,method='bfill',limit=1)
print(sn)
列表替换
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
# 第一个列表是要替换的目标值
# 第二个列表是要替换的新值
# 注意:两个列表长度要匹配
sn = s1.replace(['dancer','susan',np.nan],['DANCER','SUSAN','空值'])
print(sn)

DataFrame替换操作

  • 单值替换
    • 普通替换
    • 按列指定单值替换{列标签:替换值}
  • 多值替换
    • 列表替换
    • 单字典替换(推荐)
data = np.random.randint(0,150,size = (5,5))
columns = ['Python','Java','C#','C++','PHP']
df = DataFrame(data = data, columns=columns)
print(df)
df['Python'] = ['优秀','优秀','不及格','不及格','中等']
df.loc[2] = None
df.loc[1,'PHP'] = '?'
print(df)
# 指定列索引替换
# df.replace(to_replace=np.nan,value=100)
# 第一个参数是一个字典,描述了要替换的值,键表示列名称,值表示要替换的目标值
# 第二个参数要替换的新数据
dn = df.replace({'Java':np.nan},100)
print(dn)
# 普通替换(不改变原数据)
# 搜寻整个表格当中与to_replace匹配的值,使用value进行替换
dn = df.replace(to_replace='?',value='未知数')
dn = df.replace(to_replace='优秀',value='一般')
print(dn)
# 列表替换
# 列表替换同Series的列表替换
df.replace(['优秀',np.nan,'?'],['一般','缺失','未知'])
# 做替换操作时,往往会创建一个范围比较大的字典
# None可以用作字典的键
# 在DataFrame的替换中,None可以匹配None和np.nan
# 在使用的时候要注意None 或np.nan的有效性
map_dic = {'aaa':'AAA','不及格':'有故事',np.nan:'123空值'}
df.replace(map_dic)

注意:DataFrame中,无法使用method和limit参数
练习:
假设张三李四的课表里有满分的情况,老师认为是作弊,把所有满分的情况(包括150,300分)都记0分,如何实现?

data = np.array([[150,139,120],[150,300,143],[300,120,87]])
column = ['语文','数学','物理']
index = ['张三','李四','王老五']
df = DataFrame(data = data, columns=column,index=index)
print(df)
map_dic = {150:0,300:0}
dfn = df.replace(map_dic)
print(dfn)

练习

import pandas as pd

data_7 = pd.DataFrame({'性别':['难', '女', '难', '女', '女'],
                       '城市':['.', '潮州市', '山头市', '汕尾市', '山头市'],
                       '年龄':[25, 26, 24, 25, 26],
                       '爱好':['蓝球', '跑步', '跳舞', '逛街', '读书']})


fix_typo = {'山头市':'汕头市', '蓝球':'篮球'}
# 对全部列的错字进行修改
data_7 = data_7.replace(fix_typo)
print(data_7)

fix_typo = {'山头市':'汕头市', '蓝球':'篮球'}
# 只对【城市】列的错字进行修改
data_7['城市'] = data_7['城市'].replace(fix_typo)

data_7['性别'] = data_7['性别'].replace({'难':'男'})
data_7['城市'] = data_7['城市'].replace({'.':'未知'})
print(data_7)

rename()函数:替换索引

使用rename()函数替换行索引

data = np.random.randint(0,150,size=(5,5))
columns = ['python','c','java','php','c++']
index = ['dancer','lucy','mery','tom','jack']
score = DataFrame(data = data,columns=columns, index=index)
print(score)

# 替换列索引,指定columns参数
name_dic = {'java':'JAVA','python':'PYTHON','c':'C','c++':'C加加','php':'PHP',
            'dancer':'DANCER','lucy':'LUCY','mery':'MERY','tom':'TOM','jack':'JACK'}
df = score.rename(columns=name_dic)
print(df)

# 替换行索引,指定index参数
name_dic = {'java':'JAVA','python':'PYTHON','c':'C','c++':'C加加','php':'PHP',
            'dancer':'DANCER','lucy':'LUCY','mery':'MERY','tom':'TOM','jack':'JACK'}
df = score.rename(index=name_dic)
print(df)
  • level 指定多维索引的维度
# 使用level参数来控制替换的索引层级
mul_df.rename(columns = mul_dic,level = 1)

映射

映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定

map()函数:新建一列

  • map(字典) 字典的键要足以匹配所有的数据,否则出现NaN
  • map()可以映射新一列数据
  • map()中可以使用lambd表达式
  • map()中可以使用方法,可以是自定义的方法
    注意 map()中不能使用sum之类的函数,for循环
data = [['dancer',190,200,135],['lucy',136,230,129],['Tom',99,87,135]]
columns = ['name','python','Java','C']
df = DataFrame(data=data,columns=columns)
print(df)
# 键值对一般要保证够用,不然会出现空值
number_list = {'dancer':'01','lucy':'02','tom':'03','Tom':'04'}
df['number'] = df['name'].map(number_list)
print(df)
# 使用字典进行匹配的方式
level_list = {190:'优秀',136:'良好',99:'一般'}
df['level'] = df['python'].map(level_list)
print(df)
data = [['dancer',190,200,135],['lucy',136,230,129],['Tom',99,87,135]]
columns = ['name','python','Java','C']
df = DataFrame(data=data,columns=columns)
print(df)
# 修改一列的值,使用函数
# 注意,不能使用sum这种使用循环实现的函数
def add_score(item):
    return item+10
df['python'] = df['python'].map(add_score)
print(df)
# 使用lambda表达式
lambda x : x+10
df['Java'] = df['Java'].map(lambda item : item-10)
print(df)

transform()函数

和map()类似

def transform_func(item):
    return item+10
df['python'] = df['python'].transform(transform_func)

练习:

新增两列,分别为张三、李四的成绩状态,如果分数低于90,则为”failed”,如果分数高于120,则为”excellent”,其他则为”pass”

【提示】使用函数作为map的参数

data = [['张三',93],['李四',67],['王五',130]]
score = DataFrame(data = data,columns=['name','python'])
print(score)

def transform_score(item):
    if item < 90:
        return 'failed'
    elif item < 120:
        return 'passed'
    else:
        return 'excellent'

score['成绩'] = score['python'].map(transform_score)
print(score)

agg()函数

import pandas as pd

foods_df = pd.DataFrame({
    '食品名': ['肚脐饼', '水晶饺', '擂茶', '肚脐饼', '擂茶'], 
    '单价': [2, 10, 12, 4, 20], 
    '数量': [20, '-', 35, 37, '-'], 
    '城市': ['潮州', '汕尾', '梅州', '深圳', '深圳']
    })

# 将【数量】列的“-”统一替换为 0;
def replace_info(data):
    if data == '-':
        data = 0
    return data

foods_df['数量'] = foods_df['数量'].agg(replace_info)
print(foods_df)

# 同时计算【单价】列的最小值和【数量】列的最大值
print(foods_df.groupby('食品名').agg({'单价': 'min', '数量': 'max'}))

排序

take排序

# take()函数接受一个索引列表,用数字表示
# axis指定维度,axis=0是index,axis=1是column,别忘了column也可以通过隐藏索引012
# axis=1的时候,可以列表长度可以少于列数,但是axis=0不行
data = [['dancer',190,200,135],['lucy',136,230,129],['Tom',99,87,135]]
columns = ['name','python','Java','C']
df = DataFrame(data=data,columns=columns)
print(df)
df = df.take([0,2,1])
print(df)
#可以借助np.random.permutation()函数随机排序
df = df.take(np.random.permutation(3))
print(df)

# sort_values排序
# ascending是否按照从小到大
df = df.sort_values(by='python',ascending=False)

sort_values排序

import pandas as pd

humans_df = pd.DataFrame({
    '姓名': ['小猿', '小马', '小鱼', '小猫', '小龙'], 
    '身高': ['165', '170', '160', '172', '178'], 
    '体重': [56, 45, 60, 40, 70]
    })

# sort_values排序
# ascending是否按照从小到大
# 数字字符串也可以进行排序
df = humans_df.sort_values(by='身高',ascending=False)
print(df)
# 只想提取出'身高'列,单独进行排序
df = df['身高'].sort_values(ascending=False)
print(df)
# 重置数据行索引
# drop是否保留原索引,默认False
df = df.reset_index(drop=True)
print(df)

seaborn

import seaborn as sns
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
import pandas as pd
from faker import Faker
import random

f = Faker(locale='zh_CN')

class_list = ['1班','2班','3班']
woman_list = []
for i in range(50):
    woman_list.append({
        'sex':'woman',
        'name':f.name(),
        'height': random.randint(150,170),
        'weight': random.randint(40,60),
        'class': random.choice(class_list)
    })

man_list = []
for i in range(50):
    man_list.append({
        'sex':'man',
        'name':f.name(),
        'height': random.randint(160,180),
        'weight': random.randint(50,70),
        'class': random.choice(class_list)
    })

student_list = woman_list + man_list
student_df = DataFrame(data=student_list)
print(student_df)

# 设置中文字体
plt.rcParams['font.family'] = 'Microsoft YaHei'

# 散点图
sns.relplot(x='height', y='weight', data=student_df)
# 可选参数hue,该参数通过图中的不同颜色表示不同含义,可以让我们在图中添加一个维度
sns.relplot(x='height', y='weight', data=student_df,hue='sex')
# 可选参数 size,它会根据传入数据的大小在散点图中生成大小不同的点
sns.relplot(x='height', y='weight', data=student_df,hue='sex',size='weight')
# 可选参数是style,它可以在某一维度上,用点的不同形状区分数据
sns.relplot(x='height', y='weight', data=student_df,hue='sex',size='weight',style='class')

# 折线图
sns.relplot(x='height', y='weight', data=student_df,kind='line')

# 直方图 kind默认为hist
sns.displot(x='height', data=student_df)
# 灰色是重合的部分
sns.displot(x='height', data=student_df,hue='sex')

# matplotlib
student_df.plot(x='height', y='weight',kind='scatter')
student_df.plot(x='height', y='weight',kind='line')

plt.show()

matplotlib

折线图

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from matplotlib import pyplot as plt
import matplotlib

# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'

students_grade = pd.DataFrame({'李健': [80, 85, 89, 91, 88, 95],
                               '王聪': [95, 92, 90, 85, 75, 80],
                               '过凡': [90, 91, 92, 91, 90, 91]
                              }, index=['2月', '3月', '4月', '5月', '6月', '7月'])
# 绘制多条折线图
# df.plot() 默认会将每一列数据用绘制成单条折线图,然后合并到同一张图上
# 如果那一列数据不是数字类型,将无法绘制
# figsize可以设置图标的大小(宽,高)
# rot可以将y轴的刻度逆时针旋转
students_grade.plot(kind='line',figsize=(7, 7),title='月考成绩',rot=90)

print(students_grade)

plt.show()

饼图

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from matplotlib import pyplot as plt
import matplotlib

# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'

grade_df = pd.DataFrame({'班级': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
                         '性别': ['男', '男', '女', '女', '男', '男', '男', '男', '女', '女'],
                         '眼镜': ['是', '否', '是', '否', '是', '是', '是', '否', '否', '否'],
                         '成绩': [95, 90, 96, 92, 94, 85, 87, 80, 81, 86]})
# print(grade_df)

# 获取频率分布
sex = grade_df['性别'].value_counts()/grade_df['性别'].value_counts().sum()
print(sex)
# 绘制频率分布的饼图
sex.plot(kind='pie',figsize=(7, 7), title='性别分布频数图')

plt.show()

柱状图

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from matplotlib import pyplot as plt
import matplotlib
from faker import Faker
import random

# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'

f = Faker(locale='zh_CN')

class_list = ['1班','2班','3班']
woman_list = []
for i in range(50):
    woman_list.append({
        'sex':'woman',
        'name':f.name(),
        'height': random.randint(150,170),
        'weight': random.randint(40,60),
        'class': random.choice(class_list)
    })

man_list = []
for i in range(50):
    man_list.append({
        'sex':'man',
        'name':f.name(),
        'height': random.randint(160,180),
        'weight': random.randint(50,70),
        'class': random.choice(class_list)
    })

student_list = woman_list + man_list
student_df = DataFrame(data=student_list)
weight_mean = student_df.groupby('class')['weight'].mean()
print(weight_mean)
# 降序排列weight_mean
weight_mean = weight_mean.sort_values(ascending=False)
weight_mean.plot(kind='bar')

plt.show()

综合案例

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import matplotlib.pyplot as plt
import matplotlib
from faker import Faker
import random

f = Faker(locale='zh_CN')

class_list = ['1班','2班','3班']
woman_list = []
for i in range(50):
    woman_list.append({
        'sex':'woman',
        'name':f.name(),
        'height': random.randint(150,170),
        'weight': random.randint(40,60),
        'class': random.choice(class_list)
    })

man_list = []
for i in range(50):
    man_list.append({
        'sex':'man',
        'name':f.name(),
        'height': random.randint(160,180),
        'weight': random.randint(50,70),
        'class': random.choice(class_list)
    })

# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'

student_list = woman_list + man_list
student_df = DataFrame(data=student_list)
# print(student_df)

# 散点图
student_df.plot(x='height', y='weight',kind='scatter')

# 折线图
# use_index是否要用行索引作为x轴的刻度值
student_df.plot(x='height', y='weight',figsize=(7,7),kind='line',use_index=False)

# 柱状图
student_df.head().plot(x='name', y='weight',kind='barh')
student_df.head().plot(x='name', y='weight',kind='bar')

# 饼图
# 获取班级的频率分布
class_count = student_df['class'].value_counts()/student_df['class'].value_counts().sum()
class_count.plot(kind='pie',title='班级分布',autopct='%.2f%%')

# 绘制岗位的频率分布条形图
class_count.plot(kind='bar', figsize=(13, 6), title='班级频率分布条形图')

plt.show()

sklearn

机器学习可以解决一种简单的问题——分类问题,那些数学的原理太过于高深,我也不懂,我就结合网上资料和AI,给你们弄了一个简单的案例,进行说明,相信你们看完这个案例,至少能够解决机器学习中最简单的分类问题。

机器学习曾经解决过一个经典的问题,对蚊子进行分类

20 世纪 80 年代,生物学家发现了两种蚊子,并把它们分别命名为库蚊和伊蚊,其中伊蚊会传播多种病原体。

他们想,能不能根据这两种蚊子翅长和触角长的数据,对新的未知类别的蚊子进行分类。

这是一个分类问题,目标是根据蚊子的特征(翅长、触角长)对蚊子进行分类。

机器学习其实就是对各种模型的正确使用,那些数学的原理不懂也影响不大,如果理解原理对选择模型肯定会有帮助,我其实还是尝试去学了一下,确实太难了,但是你至少得了解这个模型大概的算法,适不适合解决这类问题,我一开始尝试了很多模型都不对,然后把锅都扔给模型,抱怨这个模型怎么这么垃圾,这样是不对的。

上述问题最好的模型是K Nearest Neighbors(KNN 模型),他是一种近邻分类算法,在蚊子的分类问题中,KNN 算法的计算步骤是这样的:

1)计算未知蚊子与每个已知蚊子特征之间的距离。

2)选取合适的 K 值,找出距离中前 K 个最小值所对应的已知蚊子。

3)根据少数服从多数的原则,对新蚊子的类别进行预测。

未知蚊子与每个已知蚊子的距离在散点图中其实一目了然,大家看看程序预测得准不准吧。

import random  
import pandas as pd  
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
  
# 生成库蚊数据  
kuwen_data = [] 
for i in range(50):
    kuwen_data.append({ 
                       "翅长": random.uniform(2.2, 2.8), 
                       "触角长": random.uniform(1.0, 1.8),
                       '类别':'库蚊'
                    })

# 生成伊蚊数据 
yiwen_data = []  
for j in range(50):
    yiwen_data.append({
                       "翅长": random.uniform(4.0, 5.0), 
                       "触角长": random.uniform(2.0, 3.0),
                       "类别": "伊蚊", 
                    })

# 生成未知数据(其实是库蚊) 
unknown_data_kuwen = []  
for j in range(5):
    unknown_data_kuwen.append({
                       "翅长": random.uniform(2.2, 2.8), 
                       "触角长": random.uniform(1.0, 1.8),
                       "类别": "未知", 
                    })

# 生成未知数据(其实是伊蚊) 
unknown_data_yiwen = []  
for j in range(5):
    unknown_data_yiwen.append({
                       "翅长": random.uniform(4.0, 5.0), 
                       "触角长": random.uniform(2.0, 3.0),
                       "类别": "未知", 
                    })

# 合并数据  
wenzi_data = kuwen_data + yiwen_data +  unknown_data_kuwen + unknown_data_yiwen
  
# 创建DataFrame  
wenzi_df = pd.DataFrame(wenzi_data)    
# print(wenzi_df)

x = wenzi_df[['翅长', '触角长']].values
y = wenzi_df['类别'].values

# Step2 数据预处理
# 最后 10 个样本为未知样本,其余样本为已知样本
train_X = x[:-10]
train_Y = y[:-10]
pred_X = x[-10:]

# Step3 训练模型
# 在 K 近邻分类器中,K 值通过参数 n_neighbors 设置
model = KNeighborsClassifier(n_neighbors=3)
model.fit(train_X, train_Y)

# Step4 应用模型
# 应用训练出的模型预测未知蚊子的类别
pred_Y = model.predict(pred_X)
print(pred_Y)

# 设置中文字体
plt.rcParams['font.family'] = 'Microsoft YaHei'

# 散点图表示
sns.relplot(x='翅长', y='触角长', data=wenzi_df , hue='类别')
plt.show()

faker

from faker import Faker

f = Faker(locale="zh_CN")

print(dir(f))
print(f.address())

文章作者: 彭韦浩
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 彭韦浩 !
  目录