Python常用库——DataFrame的运算

由于DataFrame的运算内容较多,所以单独拆分一节进行介绍。在这一部分介绍的内容包括:

图片说明

1 DataFrame与Excel之间的交互 ★★★

前面介绍到DataFrame对应了Excel中的数据表,那首先来介绍下如何把DataFrame的数据实现与Excel之间的互通。在pandas中提供了读取Excel的csv文件和写入到本地csv文件的方法。

写入使用to_csv函数,将pandas中已经建立好的DataFrame输出到本地的csv文件,其主要参数包括:path_or_buf路径,表示将csv文件写入到本地的哪个位置,同时这个地方需要给csv文件进行命名;sep表示不同列之间的分隔符,在Excel部分讲读取csv时,需要指定相应的分隔符,在这里写入到csv文件时需要指定写出时的分隔符;na_rep,对空值替换为指定值;columns指定输出的列有哪些;header,取值True或False,表示是否输出列名;index取值True或False,表示是否输出行索引值。

a_d_i = pd.DataFrame(data=[
                            ['Chinese','001',79,8],
                            ['Math','001',96,8],
                            ['English','001',64,8],   
                            ['Chinese','002',81,7],
                            ['Math','002',72,7],
                            ['English','002',60,7],   
                            ['Chinese','003',90,7],
                            ['Math','003',71,7],
                            ["",'003',92,7],   
                            ['Chinese','004',83,8],
                            ['Math','004',90,8],
                            ['English','004',84,8],   
                            ['Chinese','005',67,6],
                            ['Math','005',75,6],
                            ['English','005',88,6],   
],columns=['subject','s_id','score','age'])
a_d_i.to_csv("a_d_i.csv",sep=",",header=True,index=False)

在不指定路径的情况下,csv文件会写入到与ipynb文件相同的目录下,由于jupyter的路径的默认设置,所以在这里直接写入到默认文件夹。可以发现已经存在这一文件夹,使用jupyter打开,则可以查看相应的内容,使用逗号分隔不同列,输出列名,不输出索引值。

图片说明

图片说明

有写出,自然也有读入,读取csv文件,使用read_csv,其参数包括:路径名,即读取的csv文件所在的位置;sep,用于z指定读取的csv文件的分隔符,除可以使用sep外,还可以使用delimiter设置,需要注意的时,在同时使用sep和delimiter时,sep不起作用;header参数表示csv文件中是否包含列名,如果包含列名,则使用默认值即可,如果不包含列名,将header设置为None。在这里读取下刚写出的csv文件。

a_d_i_2 = pd.read_csv("a_d_i.csv",sep=",")
print(a_d_i_2)

输出结果如下

     subject  s_id  score  age
0   Chinese     1     79    8
1      Math     1     96    8
2   English     1     64    8
3   Chinese     2     81    7
4      Math     2     72    7
5   English     2     60    7
6   Chinese     3     90    7
7      Math     3     71    7
8       NaN     3     92    7
9   Chinese     4     83    8
10     Math     4     90    8
11  English     4     84    8
12  Chinese     5     67    6
13     Math     5     75    6
14  English     5     88    6

csv文件和txt文件的写入写出是相同的函数,区别仅在于文件的后缀是txt还是csv。

2 DataFrame的简单运算

2.1 DataFrame的基本属性

对DataFrame的基本属性获取,包括:DataFrame的形状、列名和行索引名称。
首先建立一个DataFrame的样例:

a_d_i = pd.DataFrame(data=np.array([[1,2,3,4,5],
                                    [10,20,30,40,50],
                                    [100,200,300,400,500],
                                    [1000,2000,3000,4000,5000]]),index=['a','b','c','d'],columns=['A','B','C','D','E'])
print(a_d_i)
print(a_d_i.shape)
print(a_d_i.columns)
print(a_d_i.index)

使用shape函数获取DataFrame的行数、列数;使用columns获取列名;使用index获取行索引名称。上述代码的输出结果如下

      A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
(4, 5)
Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
Index(['a', 'b', 'c', 'd'], dtype='object')

需要说明的是shape输出的是一个元组,元组的第一个元素是行数,元组的第二个元素是列数,基于元组的索引规则即可获得DataFrame的行数(a_d_i.shape[0])或列数(a_d_i.shape[1])。

2.2 基于行或列的汇总统计

除对DataFrame进行整体的认知外,还可以使用类似Series中的函数对DataFrame进行统计,最为常用就是describe。

a_d_i.describe()

使用describe实现对DataFrame的描述性统计,统计指标包括计数(count)、平均值(mean)、方差(std)、最小值(min)、最大值(max)、上四分位数点、中位数、下四分位数点。需要注意的是,describe是按照每列进行汇总的数据。

          A              B              C             D            E
count     4.000000     4.000000      4.000000      4.000000      4.000000
mean     277.750000    555.500000    833.250000    1111.000000    1388.750000
std      483.570315    967.140631    1450.710946    1934.281262    2417.851577
min      1.000000     2.000000      3.000000        4.000000         5.000000
25%      7.750000     15.500000     23.250000       31.000000     38.750000
50%      55.000000    110.000000    165.000000    220.000000    275.000000
75%      325.000000    650.000000    975.000000    1300.000000    1625.000000
max     1000.000000    2000.000000    3000.000000    4000.000000    5000.000000

describe是存在相应参数的,最常用的参数就是percentiles,用于指定计算的分位数点的位置,默认输出上四分位数、中位数和下四分位数。在这里可以修改为各个十分位数点。

a_d_i.describe(percentiles=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9])

输出结果如下

            A              B            C            D            E
count      4.000000       4.000000      4.000000      4.000000       4.000000
mean       277.750000     555.500000    833.250000    1111.000000    1388.750000
std        483.570315     967.140631    1450.710946   1934.281262    2417.851577
min        1.000000       2.000000      3.000000      4.000000       5.000000
10%        3.700000       7.400000      11.100000     14.800000      18.500000
20%        6.400000       12.800000     19.200000     25.600000      32.000000
30%        9.100000       18.200000     27.300000     36.400000      45.500000
40%        28.000000      56.000000     84.000000     112.000000     140.000000
50%        55.000000      110.000000    165.000000    220.000000     275.000000
60%        82.000000      164.000000    246.000000    328.000000     410.000000
70%        190.000000     380.000000    570.000000    760.000000     950.000000
80%        460.000000     920.000000    1380.000000   1840.000000    2300.000000
90%        730.000000     1460.000000   2190.000000   2920.000000    3650.000000
max        1000.000000    2000.000000   3000.000000   4000.000000    5000.000000

除使用describe进行比较完整的统计外,还可以分别使用相应的函数进行单独的统计。

print(a_d_i.max())
print(a_d_i.min())
print(a_d_i.mean())
print(a_d_i.count())
print(a_d_i.sum())

输出结果如下

A    1000
B    2000
C    3000
D    4000
E    5000
dtype: int32
A    1
B    2
C    3
D    4
E    5
dtype: int32
A     277.75
B     555.50
C     833.25
D    1111.00
E    1388.75
dtype: float64
A    4
B    4
C    4
D    4
E    4
dtype: int64
A    1111
B    2222
C    3333
D    4444
E    5555
dtype: int64

上面介绍的是对所有列执行相应的函数,若相对某列执行函数,则可以使用索引将某列选择出来再进行汇总统计。DataFrame可以看做是各列的集合,每一列是Series,把DataFrame中的某一列取出后,按照Series的统计函数进行计算即可。

print(a_d_i['A'].max())
print(a_d_i['A'].min())
print(a_d_i['A'].mean())
print(a_d_i['A'].count())
print(a_d_i['A'].sum())

输出结果如下

1000
1
277.75
4
1111

在这里需要强调的一点是,使用索引获取出的列的数据类型可能不是Series,而是DataFrame。

print(type(a_d_i['A']))
print(type(a_d_i[['A']]))

输出结果如下

<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>

两者的区别在于使用a_d_i['A']获取的是列名为A的一列;a_d_i[['A']]获取的是a_d_i的子集,如之前讲解的字符串、数组等,DataFrame的子集仍然是一个DataFrame。两者是不同的数据类型,所以在部分函数的使用存在差异,在使用时需要注意。

2.3 基于已有列生成新的列 ★★★

2.3.1 基于索引生成新列

常用Excel的同学可能会注意到,除使用Excel实现统计外,另外一项很重要的功能是基于现有的列生成新列,在pandas中也是比较容易实现的。

在前面介绍的是直接插入新的一列,这里介绍的是如何基于已有的列生成新列或更新已有列的值。

print(a_d_i)
a_d_i['F'] =  a_d_i['A'] + a_d_i['B'] + a_d_i['C']
print(a_d_i)

输出结果如下

      A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E     F
a     1     2     3     4     5     6
b    10    20    30    40    50    60
c   100   200   300   400   500   600
d  1000  2000  3000  4000  5000  6000

可以发现已经生成新列F,其数值是ABC三列的和。

在这里,如果不是新的列F,而是已有的列,则会直接更新已有列的数值。如更新D列是ABC三列的数值。

print(a_d_i)
a_d_i['D'] =  a_d_i['A'] + a_d_i['B'] + a_d_i['C']
print(a_d_i)

除使用列索引的方法直接更新列的数值外,还可以使用行索引的方法进行更新。

print(a_d_i)
a_d_i.loc[['a','c'],'F'] = 0
a_d_i.loc[['b'],'F'] = 1
print(a_d_i)

在这里按照行索引的方式进行赋值,对于a、c行的F列赋值为0,对于b行赋值为1,剩余的d行未赋值,所以显示为空。

     A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E    F
a     1     2     3     4     5  0.0
b    10    20    30    40    50  1.0
c   100   200   300   400   500  0.0
d  1000  2000  3000  4000  5000  NaN

除上述行索引和列索引外,还可以使用布尔索引的方法实现新列的生成。

print(a_d_i)
a_d_i.loc[a_d_i['A'] < 100,'F'] = 1
print(a_d_i)
a_d_i.loc[a_d_i['A'] >= 100,'F'] = 0
print(a_d_i)

输出结果如下

       A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E    F
a     1     2     3     4     5  1.0
b    10    20    30    40    50  1.0
c   100   200   300   400   500  NaN
d  1000  2000  3000  4000  5000  NaN
      A     B     C     D     E    F
a     1     2     3     4     5  1.0
b    10    20    30    40    50  1.0
c   100   200   300   400   500  0.0
d  1000  2000  3000  4000  5000  0.0

a_d_i['A'] >= 100是布尔索引的判断条件,不再使用单独的行索引值,而是通过是否满足相应的条件来判断该行应该赋值多少。

2.3.2 使用eval函数生成新列

上面的索引书写较为麻烦,可以借助eval函数实现上述函数的简化。

print(a_d_i)
a_d_i_1 = a_d_i.eval('F=A+B+C',inplace=False)
print(a_d_i)
print(a_d_i_1)
a_d_i.eval('F=A+B+C',inplace=True)
print(a_d_i)

eval函数有两个参数,前面的' '内是计算公式,即将ABC三列的值汇总到F列;inplace参数指定了是否替换原DataFrame,如果不进行替换,则可以函数返回的值赋予新的变量进行输出。

       A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E     F
a     1     2     3     4     5     6
b    10    20    30    40    50    60
c   100   200   300   400   500   600
d  1000  2000  3000  4000  5000  6000
      A     B     C     D     E     F
a     1     2     3     4     5     6
b    10    20    30    40    50    60
c   100   200   300   400   500   600
d  1000  2000  3000  4000  5000  6000

使用eval函数的好处在于简化了索引的使用,直接使用列名进行公式输入即可,方便快捷。

2.3.3 使用apply和where生成新列

除索引方法外,还可以使用pandas的函数实现新列的赋值,常用的方法包括apply和where。 在loc中如果对某列赋值,如果是基于不同的数值赋予不同的值,则需要通过多行代码实现,使用where和apply方法则可以通过一行代码实现多样赋值。

print(a_d_i)
a_d_i['F'] = np.where(a_d_i['A'] < 100,1,0)
print(a_d_i)

上述代码的输出结果如下

      A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E  F
a     1     2     3     4     5  1
b    10    20    30    40    50  1
c   100   200   300   400   500  0
d  1000  2000  3000  4000  5000  0

除可以直接赋值新值外,还可以使用DataFrame中已有的数值。

print(a_d_i)
a_d_i['F'] = np.where(a_d_i['A'] < 100,1,a_d_i['E'])
print(a_d_i)

上述代码的意思是,对于a_d_i的F列,如果A列的数值小于100,则赋值为1,如果大于等于100,则F列的数值等于E列的数值,所以输出结果如下

     A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E     F
a     1     2     3     4     5     1
b    10    20    30    40    50     1
c   100   200   300   400   500   500
d  1000  2000  3000  4000  5000  5000

apply是比where更灵活的操作方法,where一般只能实现是否的两种判断结果的输出,而apply则可以实现更多判断结果的输出。apply的优势在于能够跟函数匹配使用实现更复杂的输出,一般来说使用的是lambda的匿名函数,可以将匿名函数理解为是一个临时的函数。

print(a_d_i)
a_d_i['F'] = a_d_i.apply(lambda x: 1 if x['A'] < 100 else 0,axis=1)
print(a_d_i)

先看计算结果,输出如下

      A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E  F
a     1     2     3     4     5  1
b    10    20    30    40    50  1
c   100   200   300   400   500  0
d  1000  2000  3000  4000  5000  0

其实现的功能还是根据A列来生成F列的值,如果A列的值小于100,则赋值为1,如果A列的值大于等于100,则赋值为0。来具体讲解下apply的使用,lambda表示声明匿名函数,其等同于def func_name(),后跟的x表示输入参数,在这里表示相应的DataFrame,后跟冒号:,表示后续为函数的表达式,与常用的if判断的区别在于是在这里先说明执行的语句再说明判断条件,赋值为1在满足x['A'] < 100的条件下,不然(else)则赋值为0。axis=1参数表示是对列进行操作。由于是匿名函数,即用即删,用完后该函数就不存在了,不能在其他地方进行调用。同样的由于是匿名函数,所以操作可以更灵活。

print(a_d_i)
a_d_i['F'] = a_d_i.apply(lambda x: 1 if x['A'] < 100 else 2 if x['A'] < 1000 else 0,axis=1)
print(a_d_i)

使用多层if函数即可实现判断,仍然需要注意,赋值在前,判断条件在后(除最后的else),将函数语句翻译过来即为,如果A列数值小于100,则赋值1,如果大于等于100且小于1000,则赋值2,如果大于等于1000则赋值0。所以输出结果如下:

     A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
      A     B     C     D     E  F
a     1     2     3     4     5  1
b    10    20    30    40    50  1
c   100   200   300   400   500  2
d  1000  2000  3000  4000  5000  0

3 对DataFrame进行排序、筛选、分类汇总

3.1 实现数据排序功能 ★★

在pandas中使用sort_values函数实现对DataFrame实现排序,sort_values参数包括三个:排序列名、升序或降序排序、是否替代原DataFrame。

a_d_i_1 = a_d_i
print("a_d_i_1排序前\n",a_d_i_1)
a_d_i_2 = a_d_i_1.sort_values(by='A',ascending=False,inplace=False)
print("a_d_i_2排序后\n",a_d_i_2)
print("a_d_i_1排序后\n",a_d_i_1)

首先介绍按照单列对DataFrame实现排序,在这里使用的是A列,ascending参数表示是否升序排序,在这里选择False,即为降序排序;inplace参数表示是否要将排序的结果覆盖原DataFrame(a_d_i_1),在这里设置为False,即不替换原DataFrame,输出结果如下:

a_d_i_1排序前
       A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000
a_d_i_2排序后
       A     B     C     D     E
d  1000  2000  3000  4000  5000
c   100   200   300   400   500
b    10    20    30    40    50
a     1     2     3     4     5
a_d_i_1排序后
       A     B     C     D     E
a     1     2     3     4     5
b    10    20    30    40    50
c   100   200   300   400   500
d  1000  2000  3000  4000  5000

如果将参数inplace选择为True,则输出结果如下

a_d_i_1排序前
       A     B     C     D     E
a     1     2     

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

数据分析入门技术篇

全部评论

相关推荐

深夜书店vv:腾讯是这样的,去年很多走廊都加桌子当工区
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务