《数据采集与分析》课程期中测试重要知识点复习

该篇博客主要复习《数据采集与分析》课程中Numpy和Pandas的重点内容,包括Numpy的数组创建、属性查看、转置与形状调整、索引切片和统计函数;Pandas的DataFrame创建、数据查看、增删改操作、合并及分组计算,特别强调了索引器iloc与loc的区别以及处理缺失值的方法。
摘要由CSDN通过智能技术生成

《数据采集与分析》课程期中测试重要知识点复习

文章目录

① Numpy部分应掌握的重要知识点

一、Numpy数组的创建

1、基于一维/二维列表创建

import numpy as np
a1_1=np.array([1,2,3,4])
a1_1
array([1, 2, 3, 4])
a1_2=np.array([[1,2,3],[4,5,6],[7,8,9]])
a1_2
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

2、基于可以产生有规律数据的函数创建一维数组

a2=np.arange(1,10,2)   #类似于Python的range函数
print("数组a2的元素:",a2)  #元素类型是int32
a3=np.linspace(0,100,6)   #注意:连同首尾共6个端点,5个区间
print("数组a3的元素:",a3)   #元素类型是float64
数组a2的元素: [1 3 5 7 9]
数组a3的元素: [   0.   20.   40.   60.   80.  100.]

3、基于特殊函数创建二维数组

b2=np.zeros((3,4))         #创建3行4列的全0数组,参数(3,4)用于指定数组形状,当于b1=np.zeros(shape=(3,4))
print("全0数组b2的元素:\n",b2)           
b3=np.ones((3,4))           #创建3行4列的全1数组
print("全1数组b3的元素:\n",b3)
b4=np.full((3,4),5)    #3行4列元素全为5的数组,第2个参数给出了元素值,该函数等价于5*np.ones((2,4))
print("全为5的数组b4的元素:\n",b4)            
b5=np.identity(3)           #3阶主对角线元素都为1的数组
print("对角线都为1的数组b5的元素:\n",b5)
b6=np.diag([5,6,7],k=0)     #创建n阶对角形数组,第一个参数允许指定对角线元素,第2个参数k=0表示主对角线
print("对角形数组b6的元素:\n",b6)0数组b2的元素:
 [[ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]]1数组b3的元素:
 [[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
全为5的数组b4的元素:
 [[5 5 5 5]
 [5 5 5 5]
 [5 5 5 5]]
对角线都为1的数组b5的元素:
 [[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
对角形数组b6的元素:
 [[5 0 0]
 [0 6 0]
 [0 0 7]]

4、基于随机数创建数组

#设定随机数种子,这样每次运行的数据都相同
np.random.seed(666)
#产生[0,1)范围内的5个随机小数构成的一维数组
c1=np.random.random(3)
print("[0,1)范围内的随机一维小数数组:",c1)
#产生[0,1)范围内的随机小数构成的二维数组
c2=np.random.random((2,3))   #此处要用元组做参数,与下面的rand函数不同
print("[0,1)范围内的随机二维小数数组:\n",c2)
#产生[1,100)范围内的6个随机整数构成的一维数组
c3=np.random.randint(1,100,6)
print("[1,100)范围内的随机一维整数数组:",c3)
#产生[1,100)范围内的随机整数构成的二维数组
c4=np.random.randint(1,100,(2,3))
print("[1,100)范围内的随机二维整数数组:\n",c4)
[0,1)范围内的随机一维小数数组: [ 0.70043712  0.84418664  0.67651434]
[0,1)范围内的随机二维小数数组:
 [[ 0.72785806  0.95145796  0.0127032 ]
 [ 0.4135877   0.04881279  0.09992856]]
[1,100)范围内的随机一维整数数组: [64 17 47 40 70 83]
[1,100)范围内的随机二维整数数组:
 [[77 80 14]
 [70 21 12]]
#产生[a,b)范围内的均匀分布数组
c7=np.random.uniform(1,11,(2,3))  #此处数组形状需要使用元组
print("服从[1,11)区间均匀分布的二维随机小数数组:\n",c7)
#产生更一般的正态分布(均值为a,标准差为b)数组
c8=np.random.normal(5,2,(2,3))    #此处数组形状需要使用元组
print("服从均值为5、标准差为2的正态分布的二维随机小数数组:\n",c8)
服从[1,11)区间均匀分布的二维随机小数数组:
 [[ 1.05108839  2.12857654  2.10953672]
 [ 3.47668229  1.23236299  8.27321154]]
服从均值为5、标准差为2的正态分布的二维随机小数数组:
 [[ 2.82241403  3.84845851  1.63419846]
 [ 5.4583705   1.48674955  6.68926524]]

二、查看数组的属性和相关帮助信息

1、查看数组的维数、形状等属性

lst=[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
b1=np.array(lst)
print("数组b1的元素:\n",b1)
print("数组b1的维数:",b1.ndim)   
print("数组b1的形状:",b1.shape)  
print("数组b1的元素个数:",b1.size)  
数组b1的元素:
 [[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
数组b1的维数: 2
数组b1的形状: (4, 3)
数组b1的元素个数: 12

2、查看联机帮助的两种常见方法(help和?)

np.diag?
#也可以使用help(np.random.randint)查看帮助:
#help(np.random.randint)
Help on built-in function randint:

randint(...) method of numpy.random.mtrand.RandomState instance
    randint(low, high=None, size=None, dtype=int)
    
    Return random integers from `low` (inclusive) to `high` (exclusive).
    
    Return random integers from the "discrete uniform" distribution of
    the specified dtype in the "half-open" interval [`low`, `high`). If
    `high` is None (the default), then results are from [0, `low`).
    
    .. note::
        New code should use the ``integers`` method of a ``default_rng()``
        instance instead; please see the :ref:`random-quick-start`.
    
    Parameters
    ----------
    low : int or array-like of ints
        Lowest (signed) integers to be drawn from the distribution (unless
        ``high=None``, in which case this parameter is one above the
        *highest* such integer).
    high : int or array-like of ints, optional
        If provided, one above the largest (signed) integer to be drawn
        from the distribution (see above for behavior if ``high=None``).
        If array-like, must contain integer values
    size : int or tuple of ints, optional
        Output shape.  If the given shape is, e.g., ``(m, n, k)``, then
        ``m * n * k`` samples are drawn.  Default is None, in which case a
        single value is returned.
    dtype : dtype, optional
        Desired dtype of the result. Byteorder must be native.
        The default value is int.
    
        .. versionadded:: 1.11.0
    
    Returns
    -------
    out : int or ndarray of ints
        `size`-shaped array of random integers from the appropriate
        distribution, or a single such random int if `size` not provided.
    
    See Also
    --------
    random_integers : similar to `randint`, only for the closed
        interval [`low`, `high`], and 1 is the lowest value if `high` is
        omitted.
    random.Generator.integers: which should be used for new code.
    
    Examples
    --------
    >>> np.random.randint(2, size=10)
    array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # random
    >>> np.random.randint(1, size=10)
    array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    
    Generate a 2 x 4 array of ints between 0 and 4, inclusive:
    
    >>> np.random.randint(5, size=(2, 4))
    array([[4, 0, 2, 1], # random
           [3, 2, 2, 0]])
    
    Generate a 1 x 3 array with 3 different upper bounds
    
    >>> np.random.randint(1, [3, 5, 10])
    array([2, 2, 9]) # random
    
    Generate a 1 by 3 array with 3 different lower bounds
    
    >>> np.random.randint([1, 5, 7], 10)
    array([9, 8, 7]) # random
    
    Generate a 2 by 4 array using broadcasting with dtype of uint8
    
    >>> np.random.randint([1, 3, 5, 7], [[10], [20]], dtype=np.uint8)
    array([[ 8,  6,  9,  7], # random
           [ 1, 16,  9, 12]], dtype=uint8)

三、数组转置、改变形状和升维

1、数组转置需要使用.T属性

#对b1数组进行转置
print("转置前b1数组:",b1)
b1=b1.T
print("转置后b1数组:",b1)
转置前b1数组: [[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
转置后b1数组: [[ 1  4  7 10]
 [ 2  5  8 11]
 [ 3  6  9 12]]

2、修改数组的形状

#(1)使用reshape函数,注意:它不会改变原数组的形状
b1_2=b1.reshape(2,6)
b1_2
array([[ 1,  4,  7, 10,  2,  5],
       [ 8, 11,  3,  6,  9, 12]])
#(2)使用ravel函数把数组拉伸成一维,注意:它不会改变原数组的形状
b1_3=b1_2.ravel()
print("ravel拉伸后数组b1_2没有变化:",b1_2)
print("拉伸后的结果数组b1_3:",b1_3)
拉伸后数组b1_2没有变化: [[ 1  4  7 10  2  5]
 [ 8 11  3  6  9 12]]
拉伸后的结果数组b1_3: [ 1  4  7 10  2  5  8 11  3  6  9 12]
#(3)如果想在拉伸成一维的同时使原数组改变,应使用flatten函数
print("flatten拉伸后数组b1_2发生变化:",b1_2.flatten())
flatten拉伸后数组b1_2发生变化: [ 1  4  7 10  2  5  8 11  3  6  9 12]

3、提升数组的维度

#通过newaxis属性或expand_dims函数可以给既存的数组添加维度
a = np.array([1, 2, 3, 4, 5, 6])
print("一维数组a的形状:",a.shape)
b=a[np.newaxis,:]     #在行的方向上增加维度,等价于b=np.expand_dims(a,axis=0)
print("二维数组b的形状:",b.shape)
c=a[:,np.newaxis]                 #在列的方向上增加维度,等价于c=np.expand_dims(a,axis=1)
print("二维数组c的形状:",c.shape)
一维数组a的形状: (6,)
二维数组b的形状: (1, 6)
二维数组c的形状: (6, 1)

四、数组索引和切片

#(1)切片访问:二维数组允许在每个维度上使用切片,相互间用逗号分隔
n=np.array([[1,2,3,],[11,22,33],[111,222,333],[1111,2222,3333]])
print("n =",n)
print("n[1:,2:4] =",n[1:,2:4])  #行:第2行到最后一行,列:第3、4列
print("n[::,-3::2] =",n[::,-3::2]) #行:所有行,列:第1列开始、每隔1列
print("n[1,:]用于取第2行:",n[1,:])  #单个冒号:出现在列的位置上,表示所有列 
print("n[:,-1]用于取最后一列:",n[:,-1])  #单个冒号:出现在行的位置上,表示所有行
n = [[   1    2    3]
 [  11   22   33]
 [ 111  222  333]
 [1111 2222 3333]]
n[1:,2:4] = [[  33]
 [ 333]
 [3333]]
n[::,-3::2] = [[   1    3]
 [  11   33]
 [ 111  333]
 [1111 3333]]
n[1,:]用于取第2行: [11 22 33]
n[:,-1]用于取最后一列: [   3   33  333 3333]
#(2)切片赋值
#与Python列表的切片不同,数组切片不是复制,它返回的是数组数据的视图而非副本
p=n[:,:]
print("使用切片操作,数组p和数组n指向相同的数组对象:",p)
#因此通过切片赋值给p,会改变原来的数组n
p[1:2,:]=555
print("切片赋值后数组p=",p)
print("切片赋值后数组n=",n)
使用切片操作,数组p和数组n指向相同的数组对象: [[   1    2    3]
 [  11   22   33]
 [ 111  222  333]
 [1111 2222 3333]]
切片赋值后数组p= [[   1    2    3]
 [ 555  555  555]
 [ 111  222  333]
 [1111 2222 3333]]
切片赋值后数组n= [[   1    2    3]
 [ 555  555  555]
 [ 111  222  333]
 [1111 2222 3333]]
#(3)布尔数组:通过数组做关系运算产生,例如下面第2行的x%3==0就会产生布尔数组
x=np.arange(15).reshape((3,5))
print(x)
print(x%3==0)

#布尔数组用于索引,可以筛选满足条件的元素,其形式是:数组[数组通过关系运算产生的布尔数组],例如下面的x[x%3==0]
y=x[x%3==0]     #等价于y=np.extract(x%3==0,x)
print("数组x中3的倍数构成的新数组y=",y)   #注意布尔数组用于索引,筛选的结果是一维数组
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
[[ True False False  True False]
 [False  True False False  True]
 [False False  True False False]]
数组x中3的倍数构成的新数组y= [ 0  3  6  9 12]
#(4)花式索引(fancy indexing),允许用一个索引数组作为另一个数组的索引以获取后者的子集
#设定随机数种子,这样每次运行的数据都相同
np.random.seed(666)
z=np.random.randint(1,100,12).reshape((3,4))
print("二维随机整数数组z=:",z)

#下面的idx就是一个二维的索引数组,其第1维表示行,第2维表示列
#注意:索引数组主要用于检索不连续/无规律的多行(或多列)时;而切片技术用于检索连续/有规律的多行(或多列)
idx=[2,[1,3]]   #2表示要获取第3行,[1,3]表示要获取第2、4列
print("索引数组idx=",idx)

#下面的z[idx]就是花式索引的用法,因为它用数组idx作为另一个数组z的索引以获取z的子集,所以idx才称为索引数组
#注意:花式索引的结果子集的形状与索引数组idx的形状一致
print("用idx做索引数组,检索数组z得到的子集z[idx]=",z[idx])
二维随机整数数组z=[[ 3 46 31 63]
 [71 74 31 37]
 [62 92 95 52]]
索引数组idx= [2, [1, 3]]
用idx做索引数组,检索数组z得到的子集z[idx]= [92 52]

五、应用统计与排序函数

np.random.seed(666)
z=np.random.randint(1,100,12).reshape((3,4))
print("二维随机整数数组z =",z)
#计算元素的和
print("z的全部元素之和:",z.sum())      # z.sum()等价于np.sum(z)
print("z的列元素之和:",z.sum(axis=0))  # z.sum(axis=0)等价于np.sum(z,axis=0)
print("z的行元素之和:",z.sum(axis=1))  # z.sum(axis=1)等价于np.sum(z,axis=1)
#计算元素的均值
print("z的全部元素均值:",np.mean(z))
print("z的列元素均值:",z.mean(axis=0))
print("z的行元素均值:",z.mean(axis=1))
#找出数组的最大值和它们各自所在的索引
print("z的最大值:",z.max())
print("z的最大值所在的索引:",z.argmax())
print("z的每行最大值:",z.max(axis=1))
print("z的每行最大值所在的索引:",z.argmax(axis=1))
#统计满足条件的元素个数
print("z大于90的元素个数:",np.sum((z>90)))   #统计大于90的元素个数
print("z介于60到80之间的元素个数:",np.sum((z>=60) & (z<=80)))  #统计介于60到80之间的元素个数
二维随机整数数组z = [[ 3 46 31 63]
 [71 74 31 37]
 [62 92 95 52]]
z的全部元素之和: 657
z的列元素之和: [136 212 157 152]
z的行元素之和: [143 213 301]
z的全部元素均值: 54.75
z的列元素均值: [45.33333333 70.66666667 52.33333333 50.66666667]
z的行元素均值: [35.75 53.25 75.25]
z的最大值: 95
z的最大值所在的索引: 10
z的每行最大值: [63 74 95]
z的每行最大值所在的索引: [3 1 2]
z大于90的元素个数: 2
z介于6080之间的元素个数: 4
#数组排序,默认按升序
print("排序前数组z =",z)
#默认按行排序,相当于axis=1
print("按行排序的结果:",np.sort(z))   
print("按行排序结果的原索引:",np.argsort(z))
#按列排序
print("按列排序的结果:",np.sort(z,axis=0))   
print("按列排序结果的原索引:",np.argsort(z,axis=0))
#二维数组拉成一维后再排序,默认按行拉伸
r=z.flatten()
print("z按行拉成的一维数组r =",r)
print("拉伸后的数组r的排序结果:",np.sort(r))
#逆序
print("通过切片实现降序排列:",np.sort(r)[::-1])   #注意:不能写成np.sort(-r),没有这种操作!
print("通过argsort函数实现降序排列:",r[np.argsort(-r)]) #注意此用法很常见:argsort()返回的索引数组用于花式索引
#注意np.sort(r)与r.sort()排序的区别:前者会产生新数组存放排序结果,而原数组不变 ;后者会直接改变原数组的元素顺序
print("*************************")
print("排序前的数组r=",r)
print("用np.sort(r)排序后的结果:",np.sort(r))
print("排序后的数组r=",r)
print("用r.sort()排序后的结果:",r.sort())
print("排序后的数组r=",r)
排序前数组z = [[ 3 46 31 63]
 [71 74 31 37]
 [62 92 95 52]]
按行排序的结果: [[ 3 31 46 63]
 [31 37 71 74]
 [52 62 92 95]]
按行排序结果的原索引: [[0 2 1 3]
 [2 3 0 1]
 [3 0 1 2]]
按列排序的结果: [[ 3 46 31 37]
 [62 74 31 52]
 [71 92 95 63]]
按列排序结果的原索引: [[0 0 0 1]
 [2 1 1 2]
 [1 2 2 0]]
z按行拉成的一维数组r = [ 3 46 31 63 71 74 31 37 62 92 95 52]
拉伸后的数组r的排序结果: [ 3 31 31 37 46 52 62 63 71 74 92 95]
通过切片实现降序排列: [95 92 74 71 63 62 52 46 37 31 31  3]
通过argsort函数实现降序排列: [95 92 74 71 63 62 52 46 37 31 31  3]
*************************
排序前的数组r= [ 3 46 31 63 71 74 31 37 62 92 95 52]
用np.sort(r)排序后的结果: [ 3 31 31 37 46 52 62 63 71 74 92 95]
排序后的数组r= [ 3 46 31 63 71 74 31 37 62 92 95 52]
用r.sort()排序后的结果: None
排序后的数组r= [ 3 31 31 37 46 52 62 63 71 74 92 95]
#axis=0表示行,因此:如果是单行操作,就指的是某一行;如果是聚合操作 ,则表示跨行
#axis=1表示列,因此:如果是单列操作,就指的是某一列;如果是聚合操作 ,则表示跨列

② Pandas部分应掌握的重要知识点

六、DataFrame数据框的创建

1、直接基于二维数据创建(同时使用index和columns参数)

import numpy as np
import pandas as pd
scores=np.array([[97,93,86],
                [95,97,88]])
pd.DataFrame(scores,index=['s01','s02'],columns=['数学','英语','语文'])
数学英语语文
s01979386
s02959788

2、基于excel文件中的数据来创建

team=pd.read_excel('team.xlsx')
team.head()
nameteamQ1Q2Q3Q4
0LiverE89212464
1ArryC36373757
2AckA57601884
3EorgeC93967178
4OahD65496186

七、查看数据框中的数据和联机帮助信息

1、查看特殊行的数据

#查看前n行:head(n),不指定n时默认前5行
team.head(3)
nameteamQ1Q2Q3Q4
0LiverE89212464
1ArryC36373757
2AckA57601884
#查看后n行:tail(n),不指定n时默认后5行
team.tail()
nameteamQ1Q2Q3Q4
95GabrielC48598774
96Austin7C21313043
97Lincoln4C9893120
98EliE11745891
99BenE21434174
#随机抽样查看n行:sample(n),不指定n时默认抽样1行数据
team.sample(2)
nameteamQ1Q2Q3Q4
73ElliotC15177622
26TeddyE71912148

2、查看联机帮助的两种常见方法(help和?)

# team.sample?
#也可以使用help(team.sample)查看帮助:
help(team.sample)

3、查看总体统计情况

team.describe()   #技巧:输入des后按键盘的tab键可以实现命令补全
Q1Q2Q3Q4
count100.000000100.000000100.000000100.000000
mean49.20000052.55000052.67000052.780000
std29.96260329.84518126.54367727.818524
min1.0000001.0000001.0000002.000000
25%19.50000026.75000029.50000029.500000
50%51.50000049.50000055.00000053.000000
75%74.25000077.75000076.25000075.250000
max98.00000099.00000099.00000099.000000

4、根据指定行号或列号查看数据

#(1)通用写法:因为行号/列号是整数,所以需要使用.iloc位置索引器
#索引器中括号内行列下标的位置上都允许使用切片和花式索引,下例中行使用切片,列使用花式索引
#注意:下面的3:5表示下标为3和4的两行,[0,2]表示下标为0和2的两列
team.iloc[3:5,[0,2]]
nameQ1
3Eorge93
4Oah65
#(2)当只按行下标查看多个连续的行数据时,可以采用以下简化写法(不使用索引器):
team[10:13]
#注意:(1)该简化方法等价于team.iloc[10:13,:],但更推荐.iloc的写法,因为后者更通用
#(2)该简化写法下,即使查看一行数据,也要使用切片的形式,例如:team[10:11]可以查看下标为10的行
nameteamQ1Q2Q3Q4
10LeoB1743379
11LoganB9893565
12ArchieC83895968

5、根据行标签或列标签查看数据

#(1)通用方法:因为行标签或列标签通常是字符串,所以需要使用.loc标签索引器
#索引器中括号内行列下标的位置上都允许使用切片和花式索引,下例中行使用切片,列使用花式索引
#注意:下面的3:4表示行标签为3和4的两行,["name","Q1"]表示列标签为"name"和"Q1"的两列
team.loc[3:4,["name","Q1"]]
nameQ1
3Eorge93
4Oah65

特别提醒,虽然上述两种通用写法的输出相同,但原理不同:

(1)iloc索引器的切片不包含终值,所以team.iloc[3:5,[0,2]]中不包含下标为5的行

(2) loc索引器的切片却包含终值,所以team.loc[3:4,[0,2]]中却包含行标签为4的行

(3)同样是整数,在iloc索引器中将被解读为行/列下标,而在loc索引器中将被解读为行/列标签

#(2)当只涉及到按列标签查看数据时,可以使用下列简化方法(不使用索引器):
print(team['team'].unique())   #按列标签选择一列
team[['name','Q1']].head(3)    #按列标签选择多列,使用花式索引的形式
['E' 'C' 'A' 'D' 'B']
nameQ1
0Liver89
1Arry36
2Ack57

补充说明:使用.iloc或loc索引器的通用写法适用性更广泛,因此掌握通用写法是基本要求,在此基础上最好能掌握基于列标签的简化写法,因为这种写法也比较常见

6、根据给定条件查询数据

#(1)因为多数条件都会涉及列标签,因此都要使用loc索引器(而非iloc索引器)
#(2)因为通常是寻找满足条件的行,所以索引器内部需要在行的维度上表达查询条件

#以下是查询第一季度销售额大于90的人员姓名:
team.loc[team['Q1']>90,'name']
3         Eorge
17        Henry
19          Max
32    Alexander
38       Elijah
80         Ryan
88        Aaron
97     Lincoln4
Name: name, dtype: object
#查询姓名以字母'M'开头的人前两个季度的销售情况:
team.loc[team['name'].str.startswith('M'),['name','Q1','Q2']]
nameQ1Q2
19Max9775
23Mason8096
62Matthew4433
77Michael8921
#通过set_index函数可以把name列作为新的行标签
if team.index.name!='name':
    team.set_index("name",inplace=True)
#再次查询姓名以字母'M'开头的人四个季度的销售情况:
team.loc[team.index.str.startswith('M'),'Q1':'Q4']
Q1Q2Q3Q4
name
Max9775413
Mason80962649
Matthew44334198
Michael89215992

八、对数据框进行增删改操作

1、在数据框的尾部增加一列

df = pd.DataFrame({'employee': ['Bob', 'Jake', 'Lisa', 'Sue'],
                    'group': ['Accounting', 'Engineering', 'Engineering', 'HR']})
print("增加性别列之前:\n",df)
sex_value=pd.Series(['M','M','F','F'])
salary_value=[6000,5000,4000,3000]
#在尾部增加一列:采用赋值法
df['sex']=sex_value
df['salary']=salary_value
print("增加性别和工资列之后:")
df
增加性别列之前:
   employee        group
0      Bob   Accounting
1     Jake  Engineering
2     Lisa  Engineering
3      Sue           HR

增加性别和工资列之后:

employeegroupsexsalary
0BobAccountingM6000
1JakeEngineeringM5000
2LisaEngineeringF4000
3SueHRF3000

2、在尾部增加一行

#注意:此处只能使用loc索引器(使用iloc会出现索引越界的提示)
#索引器中的len(df)是想把当前数据框的长度作为新增加行的行标签
df.loc[len(df),:]=['Mike','Guarding','M',2000]
print("在尾部增加一行之后:")
df
在尾部增加一行之后:
employeegroupsexsalary
0BobAccountingM6000.0
1JakeEngineeringM5000.0
2LisaEngineeringF4000.0
3SueHRF3000.0
4MikeGuardingM2000.0

3、修改一列数据

#修改一列数据仍采用对列进行赋值操作的形式
#下面把性别列的值都设置为"Unknown"
new_sex=len(df)*["Unknown"]
print(new_sex)
df['sex']=new_sex
print("修改性别列之后:")
df
['Unknown', 'Unknown', 'Unknown', 'Unknown', 'Unknown']

修改性别列之后:

employeegroupsexsalary
0BobAccountingUnknown6000.0
1JakeEngineeringUnknown5000.0
2LisaEngineeringUnknown4000.0
3SueHRUnknown3000.0
4MikeGuardingUnknown2000.0

4、修改一行数据

#可以使用loc索引器结合赋值操作来修改:
#下面把标签为2的那行数据修改为["Rose","Sales","Female"]
df.loc[2,:]=["Rose","Sales","Female",3500]
print("修改标签为2的行之后:")
df
修改标签为2的行之后:
employeegroupsexsalary
0BobAccountingUnknown6000.0
1JakeEngineeringUnknown5000.0
2RoseSalesFemale3500.0
3SueHRUnknown3000.0
4MikeGuardingUnknown2000.0

5、删除一列或多列数据

#使用drop函数,并且指定axis=1才能删除列
#如果要删除多列,则要结合标签的花式索引形式:
df.drop(['sex','salary'],axis=1,inplace=True)   #inplace=True表示原地修改,即修改的结果直接作用于当前对象
print("删除性别和工资列之后:")
df
删除性别和工资列之后:
employeegroup
0BobAccounting
1JakeEngineering
2RoseSales
3SueHR
4MikeGuarding

6、删除一行数据

#使用drop函数,默认是删除行(axis=0是默认值):
#以下是删除标签为4的行
df.drop(4,inplace=True)
print("删除标签为4的行之后:")
df
删除标签为4的行之后:
employeegroup
0BobAccounting
1JakeEngineering
2RoseSales
3SueHR

说明:可以通过?或help来查看以上操作函数的参数,例如df.drop?可以查看drop函数的相关帮助信息

九、数据框的合并

问题:有两个数据框,如下图所示,现在期望将它们合并成如下图所示的效果,该如何做?

数据框df2:
在这里插入图片描述
数据框df3:

在这里插入图片描述

df2 = pd.DataFrame({'employee': ['Lisa', 'Bob', 'Jake', 'Sue'],
                    'hire_date': [2004, 2008, 2012, 2014]})
df2
employeehire_date
0Lisa2004
1Bob2008
2Jake2012
3Sue2014
df3 = pd.DataFrame({'employee': ['Bob', 'Jake', 'Lisa', 'Sue','Tom'],
                    'group': ['Accounting', 'Engineering', 'Engineering', 'HR',np.NaN]})
df3   #注意Tom目前没有所属部门
employeegroup
0BobAccounting
1JakeEngineering
2LisaEngineering
3SueHR
4TomNaN

1、merge合并

merge主要基于列值匹配而进行列合并,类似于SQL中的连接操作。合并时四种不同的连接规则:

df4_1=pd.merge(df3,df2)             #效果等价于how='right'
df4_1
employeegrouphire_date
0BobAccounting2008
1JakeEngineering2012
2LisaEngineering2004
3SueHR2014
df4_2=pd.merge(df3,df2,how='outer')    #效果等价于how='left'
df4_2
employeegrouphire_date
0BobAccounting2008.0
1JakeEngineering2012.0
2LisaEngineering2004.0
3SueHR2014.0
4TomNaNNaN

2、concat合并

df5=pd.concat([df3,df2])
df5
employeegrouphire_date
0BobAccountingNaN
1JakeEngineeringNaN
2LisaEngineeringNaN
3SueHRNaN
4TomNaNNaN
0LisaNaN2004.0
1BobNaN2008.0
2JakeNaN2012.0
3SueNaN2014.0

3、join合并

df6=df3.join(df2,lsuffix='_l', rsuffix='_r')
df6
employee_lgroupemployee_rhire_date
0BobAccountingLisa2004.0
1JakeEngineeringBob2008.0
2LisaEngineeringJake2012.0
3SueHRSue2014.0
4TomNaNNaNNaN

小结: concat默认的合并方式是行拼接,取并集(axis=0,join=‘outer’)

merge默认的合并方式是基于列值进行列拼接,取交集(how=‘inner’)

join默认的合并方式是基于行索引进行列合并,并且默认为左连接

十、分组及相关计算

1、分组及统计

#针对team数据框,要求按'team'列统计各团队前两个季度的平均销售额:
#方法1:先分组再选择列最后计算,推荐此种写法
#注意本例中,选择两列时使用了花式索引()
team.groupby('team')[['Q1','Q2']].mean()

#如果如果只有一列,则无需使用花式索引,如下所示:
#team.groupby('team')['Q1'].mean()
Q1Q2
team
A62.70588237.588235
B44.31818255.363636
C48.00000054.272727
D45.26315862.684211
E48.15000050.650000
#方法2:先分组再计算最后选择列
#注意本例中,选择两列时使用了花式索引(如果只有一列,则无需使用花式索引)
team.groupby('team').mean()[['Q1','Q2']]

#如果如果只有一列,则无需使用花式索引,如下所示:
#team.groupby('team').mean()['Q1']
Q1Q2
team
A62.70588237.588235
B44.31818255.363636
C48.00000054.272727
D45.26315862.684211
E48.15000050.650000

2、找到满足条件的分组(过滤掉不满足条件的分组)

#现在要求找到前两个季度平均销售额都大于45的团队,显然这是一个对分组进行过滤的任务
#该任务可以分两步进行:
#(1)用filter函数得到满足所需条件的分组中的记录,它的结果是整个数据集的子集
flt_df=team.groupby('team').filter(lambda x: (x['Q1'].mean()>45) & (x['Q2'].mean()>45))
#(2)再对该子集重新进行一次分组汇总统计
flt_df.groupby('team')[['Q1','Q2']].mean()

#补充说明:
#(1)filter函数用于对分组进行过滤(类似于SQL中的having子句)
#(2)filter函数返回满足过滤条件的分组中的记录,而不是满足条件的分组
#(3)其参数必须是函数,本例中lambda函数的形参x代表每个分组
#(4)当组对象存在多列时,filter的过滤条件要求显式的指定某一列
Q1Q2
team
C48.00000054.272727
D45.26315862.684211
E48.15000050.650000

十一、处理缺失值

1、Pandas中缺失值的表示

#Pandas表示缺失值的一种方法是使用NaN(Not a Number),它是一个特殊的浮点数;另一种是使用Python中的None;
#Pandas会自动把None转变成NaN
data=pd.Series([1, np.nan, 'hello', None])
data
0        1
1      NaN
2    hello
3     None
dtype: object

2、 与缺失值判断和处理相关的方法

  • isnull(): 判断每个元素是否是缺失值,会返回一个与原对象尺寸相同的布尔性Pandas对象
  • notnull(): 与isnull()相反
  • dropna(): 返回一个删除缺失值后的数据对象
  • fillna(): 返回一个填充了缺失值之后的数据对象
#判断是否含有缺失值
data.isnull()
0    False
1     True
2    False
3     True
dtype: bool
#统计一维的data中缺失值的个数
data.isnull().sum()
2
df = pd.DataFrame([[1,      np.nan, 2],
                   [2,      3,      5],
                   [np.nan, 4,      6]])
 #统计二维的df中缺失值的个数
df.isnull().sum().sum()  
2
#dropna默认删除任何包含缺失值的整行数据
df.dropna()
012
12.03.05
#使用axis=1或axis='columns'删除任何包含缺失值的整列数据
df.dropna(axis=1)
2
02
15
26
##更精确的缩小删除范围,需要使用how或thresh(阈值)参数
#只有全为空值的列才会被删除
df.dropna(axis='columns', how='all')
012
01.0NaN2
12.03.05
2NaN4.06

3、 填充缺失值

#用单个值填充,下面的例子使用0来填充缺失值
df.fillna(0)
012
01.00.02
12.03.05
20.04.06
# 从前向后填充(forward-fill)
df.fillna(method='ffill')
012
01.0NaN2
12.03.05
22.04.06
# 从后向前填充(back-fill)
df.fillna(method='bfill')
012
01.03.02
12.03.05
2NaN4.06
#插值法填充
#下面的示例:线性插值、沿着水平方向从前向后填充
#填充的方向默认是axis=0,即垂直方向填充;
#如果希望水平方向填充,需要设置axis=1
df.interpolate(method='linear', limit_direction='forward', axis=1)
012
01.01.52.0
12.03.05.0
2NaN4.06.0
#上面的方法都不是原地修改原对象,如果需要原地修改,则需要设置inplace=True
print(df)
df.interpolate(method='linear', limit_direction='forward', axis=1,inplace=True)
df
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6
012
01.01.52.0
12.03.05.0
20.04.06
# 从前向后填充(forward-fill)
df.fillna(method='ffill')
012
01.0NaN2
12.03.05
22.04.06
# 从后向前填充(back-fill)
df.fillna(method='bfill')
012
01.03.02
12.03.05
2NaN4.06
#插值法填充
#下面的示例:线性插值、沿着水平方向从前向后填充
#填充的方向默认是axis=0,即垂直方向填充;
#如果希望水平方向填充,需要设置axis=1
df.interpolate(method='linear', limit_direction='forward', axis=1)
012
01.01.52.0
12.03.05.0
2NaN4.06.0
#上面的方法都不是原地修改原对象,如果需要原地修改,则需要设置inplace=True
print(df)
df.interpolate(method='linear', limit_direction='forward', axis=1,inplace=True)
df
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6
012
01.01.52.0
12.03.05.0
2NaN4.06.0
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-北天-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值