Pandas实战-DataFrame对象

本文将主要介绍以下内容:

1. DataFrame概述

2. Series和DataFrame的相似点

3. DataFrame排序

4. 按DataFrame索引排序

5. 设置新索引

6. 从DataFrame读取列

7. 从DataFrame读取行

8. 重命名列或行

9. 重置索引

 

DataFrame是Pandas的另外一个主要的数据结构,它是由行和列组成的二维数据结构,因此需要两个参考点来从数据集中提取给定值。

1. DataFrame概述

DataFrame可以描述为网格或数据表,类似于Excel之类的电子表格中的网格或数据表。

1.1 从字典创建DataFrame

和往常一样,让我们从导入pandas开始,还将使用NumPy库生成一些随机数据:

In [1]: import pandas as pd
        import numpy as np

在导入第一个数据集之前,让我们练习从一些Python内置对象实例化一个DataFrame。例如字典,其键将用作列名,而相应的值将用作该列的值。

下例使用三个长度相等的列表来存储城市,国家和人口。也可以使用其它可迭代对象(如元组或Series)代替列表。DataFrame类的第一个参数data代表数据源。

In  [2]: city_data = {
           "City": ["New York City", "Paris", "Barcelona", "Rome"],
           "Country": ["United States", "France", "Spain", "Italy"],
           "Population": [8600000, 2141000, 5515000, 2873000]
         }
         cities = pd.DataFrame(city_data)
         cities
Out [2]:               City          Country Population
         0    New York City    United States    8600000
         1            Paris           France    2141000
         2        Barcelona            Spain    5515000
         3             Rome            Italy    2873000

我们创建了第一个DataFrame,它与Series非常相似。再次提醒,当我们没有为构造函数提供一个明确的索引时,pandas会默认生成一个从0开始的顺序索引。

如果我们想翻转数据,以列标头作为索引标签,我们可以调用transpose方法或其T属性:

In  [3]: cities.transpose() # 此行代码和下面代码是一样的
         cities.T
Out [3]:                           0         1            2          3
               City    New York City     Paris    Barcelona       Rome
            Country    United States    France        Spain      Italy
         Population          8600000   2141000      5515000    2873000

另外还可以使用一个更方便的from_dict方法,此方法用于把字典转换为DataFrame。其参数orient用于控制索引标签的创建,如果想把字典的键保存为DataFrame的列,可以使用默认值columns;如果想把字典的键保存为行,则使用值index:

In  [4]: pd.DataFrame.from_dict(data = city_data, orient = "index")
Out [4]:                           0          1            2          3
               City    New York City      Paris    Barcelona       Rome
            Country    United States     France        Spain      Italy
         Population          8600000    2141000      5515000    2873000

1.2 从NumPy 数组创建DataFrame

DataFrame构造函数还接受NumPy ndarray对象。假设我们要创建一个3x5的DataFrame,其整数在1到100(含)之间,我们可以使用random模块的randint方法:

In  [5]: data = np.random.randint(1, 101, [3, 5])
         data
Out [5]: array([[25, 22, 80, 43, 42],
                [40, 89, 7, 21, 25],
                [89, 71, 32, 28, 39]])

接下来,我们将ndarray传到DataFrame构造函数中。与行一样,如果未提供自定义的列标头,Pandas将为每列分配一个数字索引:

In  [6]: pd.DataFrame(data = data)
Out [6]:      0    1    2    3    4
         0   25   22   80   43   42
         1   40   89    7   21   25
         2   89   71   32   28   39

我们可以使用可迭代序列,例如列表,元组或ndarray,以用作行标签。请注意,可迭代项的长度必须等于数据集中的行数。这是一个3x5的表格,因此我们必须为索引提供3个标签。

In  [7]: index = ["Morning", "Afternoon", "Evening"]
         temperatures = pd.DataFrame(data = data, index = index)
         temperatures
Out [7]:              0    1    2    3    4
           Morning   25   22   80   43   42
         Afternoon   40   89    7   21   25
           Evening   89   71   32   28   39

columns参数允许我们设置DataFrame的列名(也称为垂直标签)。因为我们总共有5列,所以我们的可迭代项的长度必须为5。下例通过将标头存储在元组中来设置列名:

In  [8]: index = ["Morning", "Afternoon", "Evening"]
         columns = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
         temperatures = pd.DataFrame(data = data,
                                     index = index,
                                     columns = columns)
         temperatures
Out [8]:            Monday   Tuesday   Wednesday   Thursday   Friday
           Morning      25        22          80         43       42
         Afternoon      40        89           7         21       25
           Evening      89        71          32         28       39

行索引和列索引都允许包含重复值:

In  [9]: index = ["Morning", "Afternoon", " Morning"]
         columns = ("Monday", "Tuesday", "Wednesday", "Tuesday", "Friday")
         temperatures = pd.DataFrame(data = data,
                                     index = index,
                                     columns = columns)
         temperatures
Out [9]:           Monday   Tuesday   Wednesday   Tuesday   Friday
           Morning     25        22          80        43       42
         Afternoon     40        89           7        21       25
           Morning     89        71          32        28       39

2. Series和DataFrame的相似点

在之前介绍的许多Series属性和方法在DataFrame上也适用。

2.1 导入CSV数据集

nba.csv文件是2019-2020 NBA运动员的数据集,包括每个球员的姓名,球队,位置,生日和工资:

In  [10]: pd.read_csv("nba.csv")
Out [10]:                 Name                 Team Position   Birthday     Salary
            0     Shake Milton   Philadelphia 76ers       SG    9/26/96    1445697
            1   Christian Wood      Detroit Pistons       PF    9/27/95    1645357
            2    PJ Washington    Charlotte Hornets       PF    8/23/98    3831840
            3     Derrick Rose      Detroit Pistons       PG    10/4/88    7317074
            4    Marial Shayok   Philadelphia 76ers        G    7/26/95      79568
            …                …                    …        …          …          …
          445    Austin Rivers      Houston Rockets       PG     8/1/92    2174310
          446      Harry Giles     Sacramento Kings       PF    4/22/98    2578800
          447      Robin Lopez      Milwaukee Bucks        C     4/1/88    4767000
          448    Collin Sexton  Cleveland Cavaliers       PG     1/4/99    4764960
          449      Ricky Rubio         Phoenix Suns       PG   10/21/90   16200000
          450 rows x 5 columns

注意,Birthday列中的值默认是作为字符串而不是datetime对象导入,之前介绍过可以使用parse_dates参数将值强制转换为datetime,一致以YYYY-MM-DD格式显示:

In  [11]: pd.read_csv("nba.csv", parse_dates = ["Birthday"])
Out [11]:                 Name                 Team Position     Birthday    Salary
            0     Shake Milton   Philadelphia 76ers       SG   1996-09-26   1445697
            1   Christian Wood      Detroit Pistons       PF   1995-09-27   1645357
            2    PJ Washington    Charlotte Hornets       PF   1998-08-23   3831840
            3     Derrick Rose      Detroit Pistons       PG   1988-10-04   7317074
            4    Marial Shayok   Philadelphia 76ers        G   1995-07-26     79568
            …                …                    …        …            …         …
          445    Austin Rivers      Houston Rockets       PG   1992-08-01   2174310
          446      Harry Giles     Sacramento Kings       PF   1998-04-22   2578800
          447      Robin Lopez      Milwaukee Bucks        C   1988-04-01   4767000
          448    Collin Sexton  Cleveland Cavaliers       PG   1999-01-04   4764960
          449      Ricky Rubio         Phoenix Suns       PG   1990-10-21  16200000
          450 rows x 5 columns

现在我们可以把DataFrame分配给一个变量nba:

In  [12]: nba = pd.read_csv("nba.csv", parse_dates = ["Birthday"])

2.2 共享和专用属性

Series的值必须是单一同质的数据类型,而DataFrame的列可以保存异构的数据。让我们使用dtypes属性查看各自的数据类型,它返回的是一个Series对象:

In  [13]: nba.dtypes
Out [13]: Name                object
          Team                object
          Position            object
          Birthday    datetime64[ns]
          Salary               int64
          dtype: object

然后调用value_counts方法可以计算每种数据类型的列数:

In  [14]: nba.dtypes.value_counts()
Out [14]: object            3
          datetime64[ns]    1
          int64             1
          dtype: int64

DataFrame基本上由两个对象组成:一个由行标签组成的索引和一个保存每一行值的数据容器。Pandas自带了几个索引对象,每个索引对象都经过优化以存储特定类型的值(numeric、string、datetime等)。index属性返回DataFrame的Index对象。下面让我们看一下nba数据集使用的索引类型:

In  [15]: nba.index
Out [15]: RangeIndex(start=0, stop=450, step=1)

RangeIndex是一个优化的索引,用于存储顺序的整数值。与Python的range函数非常相似,RangeIndex包含三个参数:start,stop和step(每两个值之间的间隔)。上例的输出告诉我们索引从0开始,以1为增量(即0、1、2…449)直到450。

DataFrame还具有专用的columns属性,该属性返回包含标头的Index对象:

In  [16]: nba.columns
Out [16]: Index(['Name', 'Team', 'Position', 'Birthday', 'Salary'], dtype='object')

axes属性同时返回行和列索引:

In  [17]: nba.axes
Out [17]: [RangeIndex(start=0, stop=450, step=1),
           Index(['Name', 'Team', 'Position', 'Birthday', 'Salary'], dtype='object')]

shape属性返回DataFrame维度的元组,450行x 5列:

In  [18]: nba.shape
Out [18]: (450, 5)

ndim属性返回维数:

In  [19]: nba.ndim
Out [19]: 2

size属性返回数据集中值的总数,包括缺失值,它等于行数和列数的乘积:

In  [20]: nba.size
Out [20]: 2250

In  [21]: len(nba.index) * len(nba.columns)
Out [21]: 2250

如果要排除缺失值可以使用count方法,它将返回一个包含每个DataFrame列的非空值数量的Series。然后使用sum方法得出DataFrame中非空值的总数。因为此数据集不包含任何缺失值,所以size属性和count方法的结果将相同。

In  [22]: nba.count()
Out [22]: Name        450
          Team        450
          Position    450
          Birthday    450
          Salary      450
          dtype: int64

In  [23]: nba.count().sum()
Out [23]: 2250

2.3 共享方法

head和tail方法返回数据集的最前或最后的行:

In  [24]: nba.head(2)
Out [24]:               Name                 Team Position     Birthday    Salary
          0     Shake Milton   Philadelphia 76ers       SG   1996-09-26   1445697
          1   Christian Wood      Detroit Pistons       PF   1995-09-27   1645357

In  [25]: nba.tail(n = 3)
Out [25]:                Name                  Team Position     Birthday    Salary
          447     Robin Lopez       Milwaukee Bucks        C   1988-04-01   4767000
          448   Collin Sexton   Cleveland Cavaliers       PG   1999-01-04   4764960
          449     Ricky Rubio          Phoenix Suns       PG   1990-10-21  16200000

sample方法返回DataFrame的随机行:

In  [26]: nba.sample(3)
Out [26]:                   Name                   Team Position    Birthday   Salary
          348  Patrick Patterson   Los Angeles Clippers       PF  1989-03-14  3068660
           14         Alec Burks  Golden State Warriors       SG  1991-07-20  2320044
          228   Ignas Brazdeikis        New York Knicks       SF  1999-01-08   898310

nunique方法返回一个包含每一列唯一值的数量的Series:

In  [27]: nba.nunique()
Out [27]: Name        450
          Team         30
          Position      9
          Birthday    430
          Salary      269
          dtype: int64

之前介绍过的max和min方法在DataFrame上也适用,它们返回包含每一列的最大值和最小值的Series。datetime列的最大值是按时间顺序排列的最新日期。

In  [28]: nba.max()
Out [28]: Team         Washington Wizards
          Position                     SG
          Birthday    2000-12-23 00:00:00
          Salary                 40231758
          dtype: object

In  [29]: nba.min()
Out [29]: Team              Atlanta Hawks
          Position                      C
          Birthday    1977-01-26 00:00:00
          Salary                    79568
          dtype: object

nlargest方法返回按照指定列最大值排序的前n行。因为一个DataFrame可以包含多个可排序的列,所以我们必须使用columns参数指定要用作排序的列。参数值可以是单个列名,也可以是多个列名的列表。下例是返回NBA中收入最高的前4名球员:

In  [30]: nba.nlargest(n = 4, columns = "Salary")
Out [30]:                   Name                   Team Position    Birthday    Salary
          205      Stephen Curry  Golden State Warriors       PG  1988-03-14  40231758
           38         Chris Paul  Oklahoma City Thunder       PG  1985-05-06  38506482
          219  Russell West*        Houston Rockets       PG  1988-11-12  38506482
          251          John Wall     Washington Wizards       PG  1990-09-06  38199000

nsmallest方法返回按照指定列最小值排序的前n行。下例是返回NBA中最老的前3名球员:

In  [31]: nba.nsmallest(3, columns = ["Birthday"])
Out [31]:         is     Name              Team Position     Birthday    Salary
           98    Vince Carter     Atlanta Hawks       PF   1977-01-26   2564753
          196   Udonis Haslem        Miami Heat        C   1980-06-09   2564753
          262     Kyle Korver   Milwaukee Bucks       PF   1981-03-17   6004753

如果要计算所有NBA工资的总和,可以直接使用sum方法,但必须把numeric_only参数设为True,用于只计算数值类型的列。

In  [32]: nba.sum(numeric_only = True)
Out [32]: Salary    3444112694
          dtype: int64

mean方法可以计算平均工资:

In  [33]: nba.mean()
Out [33]: Salary    7.653584e+06
          dtype: float64

median方法可以计算工资的中位数,std方法统计偏差:

In  [34]: nba.median()
Out [34]: Salary    3303074.5
          dtype: float64

In  [35]: nba.std()
Out [35]: Salary    9.288810e+06
          dtype: float64

3. 按DataFrame值排序

我们可以使用sort_values方法按一列或多列对DataFrame进行排序。默认情况下,该方法返回一个新的DataFrame。

3.1 按单列排序

首先让我们按名字对球员进行排序,by参数用于指定排序的列:

In  [36]: nba.sort_values("Name") # 和下面代码是一样的
          nba.sort_values(by = "Name")
Out [36]:                   Name                   Team Position    Birthday    Salary
           52       Aaron Gordon          Orlando Magic       PF  1995-09-16  19863636
          101      Aaron Holiday         Indiana Pacers       PG  1996-09-30   2239200
          437        Abdel Nader  Oklahoma City Thunder       SF  1993-09-25   1618520
           81        Adam Mokoka          Chicago Bulls        G  1998-07-18     79568
          399  Admiral Schofield     Washington Wizards       SF  1997-03-30   1000000
            …                  …                      …        …           …         …
          159        Zach LaVine          Chicago Bulls       PG  1995-03-10  19500000
          302       Zach Norvell     Los Angeles Lakers       SG  1997-12-09     79568
          312       Zhaire Smith     Philadelphia 76ers       SG  1999-06-04   3058800
          137    Zion Williamson   New Orleans Pelicans        F  2000-07-06   9757440
          248     Zylan Cheatham   New Orleans Pelicans       SF  1995-11-17     79568
          450 rows × 5 columns

ascending参数可以指定升序或降序排序,我们可以使用它来找出NBA中最年轻的五个球员,只需对Birthday列进行降序排序,head方法默认返回前5行:

In  [37]: nba.sort_values("Birthday", ascending = False).head()
Out [37]:                     Name                  Team Position    Birthday   Salary
          136      Sekou Doumbouya       Detroit Pistons       SF  2000-12-23  3285120
          432  Talen Horton-Tucker    Los Angeles Lakers       GF  2000-11-25   898310
          137      Zion Williamson  New Orleans Pelicans        F  2000-07-06  9757440
          313           RJ Barrett       New York Knicks       SG  2000-06-14  7839960
          392         Jalen Lecque          Phoenix Suns        G  2000-06-13   898310

3.2 按多列排序

sort_values方法的by参数还支持按多个列排序,默认情况下,所有排序将按升序排列,也就是ascending参数默认值为True。下例按字母顺序对球队进行排序,然后再对每个球队中的球员进行排序:

In  [38]: nba.sort_values(by = ["Team", "Name"])
Out [38]:                 Name                Team Position    Birthday    Salary
          359         Alex Len       Atlanta Hawks        C  1993-06-16   4160000
          167     Allen Crabbe       Atlanta Hawks       SG  1992-04-09  18500000
          276  Brandon Goodwin       Atlanta Hawks       PG  1995-10-02     79568
          438   Bruno Fernando       Atlanta Hawks        C  1998-08-15   1400000
          194      Cam Reddish       Atlanta Hawks       SF  1999-09-01   4245720
            …                …                   …        …           …         …
          418     Jordan McRae  Washington Wizards       PG  1991-03-28   1645357
          273  Justin Robinson  Washington Wizards       PG  1997-10-12    898310
          428    Moritz Wagner  Washington Wizards        C  1997-04-26   2063520
           21    Rui Hachimura  Washington Wizards       PF  1998-02-08   4469160
           36    Thomas Bryant  Washington Wizards        C  1997-07-31    800000
          450 rows × 5 columns

我们可以使用ascending参数对每个列按相同的顺序排序:

In  [39]: nba.sort_values(["Team", "Name"], ascending = False)
Out [39]:                 Name                Team Position  Birthday      Salary
           36    Thomas Bryant  Washington Wizards        C  1997-07-31   8000000
           21    Rui Hachimura  Washington Wizards       PF  1998-02-08   4469160
          428    Moritz Wagner  Washington Wizards        C  1997-04-26   2063520
          273  Justin Robinson  Washington Wizards       PG  1997-10-12    898310
          418     Jordan McRae  Washington Wizards       PG  1991-03-28   1645357
            …                …                   …        …           …         …
          194      Cam Reddish       Atlanta Hawks       SF  1999-09-01   4245720
          438   Bruno Fernando       Atlanta Hawks        C  1998-08-15   1400000
          276  Brandon Goodwin       Atlanta Hawks       PG  1995-10-02     79568
          167     Allen Crabbe       Atlanta Hawks       SG  1992-04-09  18500000
          359         Alex Len       Atlanta Hawks        C  1993-06-16   4160000
          450 rows × 5 columns

如果我们想对每个列按照不同的排序顺序,例如,对球队按升序进行排序,然后再对工资按降序进行排序。为此,ascending参数也支持列表值,每个布尔值会与by参数的每个值对应,也就是by和ascending参数的列表的长度必须相等。

In  [40]: nba.sort_values(by = ["Team", "Salary"],
                          ascending = [True, False])
Out [40]:                   Name                Team Position    Birthday    Salary
          111   Chandler Parsons       Atlanta Hawks       SF  1988-10-25  25102512
           28        Evan Turner       Atlanta Hawks       PG  1988-10-27  18606556
          167       Allen Crabbe       Atlanta Hawks       SG  1992-04-09  18500000
          213    De'Andre Hunter       Atlanta Hawks       SF  1997-12-02   7068360
          339      Jabari Parker       Atlanta Hawks       PF  1995-03-15   6500000
            …                  …                   …        …           …         …
           80        Isaac Bonga  Washington Wizards       PG  1999-11-08   1416852
          399  Admiral Schofield  Washington Wizards       SF  1997-03-30   1000000
          273    Justin Robinson  Washington Wizards       PG  1997-10-12    898310
          283   Garrison Mathews  Washington Wizards       SG  1996-10-24     79568
          353      Chris Chiozza  Washington Wizards       PG  1995-11-21     79568
          450 rows × 5 columns

与Series一样,inplace参数会修改原始DataFrame而不是返回一个新的DataFrame。Jupyter Notebook中将不会产生任何输出:

In  [41]: nba.sort_values(by = ["Team", "Salary"],
                          ascending = [True, False],
                          inplace = True)

4. 按DataFrame索引排序

使用inplace参数更改了原始的DataFrame,但我们也有方法将其恢复为原始形式。

4.1 按行索引排序

sort_index方法按索引值对DataFrame进行排序:

In  [42]: nba.sort_index().head() # 与下行代码是一样的
          nba.sort_index(ascending = True).head()
Out [42]:               Name                 Team Position     Birthday    Salary
          0     Shake Milton   Philadelphia 76ers       SG   1996-09-26   1445697
          1   Christian Wood      Detroit Pistons       PF   1995-09-27   1645357
          2    PJ Washington    Charlotte Hornets       PF   1998-08-23   3831840
          3     Derrick Rose      Detroit Pistons       PG   1988-10-04   7317074
          4    Marial Shayok   Philadelphia 76ers        G   1995-07-26     79568

使用inplace参数使更改永久生效:

In  [43]: nba.sort_index(inplace = True)

4.2 按列索引排序

按列进行排序可以使用axis参数,只需把值设为1或columns:

In  [44]: nba.sort_index(axis = 1).head() # 这三行代码是一样的
          nba.sort_index(axis = "columns").head()
          nba.sort_index(axis = "columns", ascending = True).head()
Out [44]:       Birthday             Name Position    Salary                 Team
          0   1996-09-26     Shake Milton       SG   1445697   Philadelphia 76ers
          1   1995-09-27   Christian Wood       PF   1645357      Detroit Pistons
          2   1998-08-23    PJ Washington       PF   3831840    Charlotte Hornets
          3   1988-10-04     Derrick Rose       PG   7317074      Detroit Pistons
          4   1995-07-26    Marial Shayok        G     79568   Philadelphia 76ers

5. 设置新索引

设置新索引可以使用set_index方法,它返回一个以给定列作为索引的新DataFrame:

In  [45]: nba.set_index(keys = "Name") # is the same as
          nba.set_index("Name")
Out [45]:                                Team Position     Birthday     Salary
                    Name
            Shake Milton   Philadelphia 76ers       SG   1996-09-26    1445697
          Christian Wood      Detroit Pistons       PF   1995-09-27    1645357
           PJ Washington    Charlotte Hornets       PF   1998-08-23    3831840
            Derrick Rose      Detroit Pistons       PG   1988-10-04    7317074
           Marial Shayok   Philadelphia 76ers        G   1995-07-26      79568
                       …                    …        …            …          …
           Austin Rivers      Houston Rockets       PG   1992-08-01    2174310
             Harry Giles     Sacramento Kings       PF   1998-04-22    2578800
             Robin Lopez      Milwaukee Bucks        C   1988-04-01    4767000
           Collin Sexton  Cleveland Cavaliers       PG   1999-01-04    4764960
             Ricky Rubio         Phoenix Suns       PG   1990-10-21   16200000
          450 rows × 4 columns

使用inplace参数使更改永久生效:

In  [46]: nba.set_index(keys = "Name", inplace = True)

如果我们知道要在导入数据集时用作索引的列,我们还可以使用read_csv方法的index_col参数:

In  [47]: nba = pd.read_csv("nba.csv",
                            parse_dates = ["Birthday"],
                            index_col = "Name")

6. 从DataFrame读取列

DataFrame是共用相同索引的Series对象的集合,我们可以轻松地从DataFrame中读取一个或多个这些列。

6.1 从DataFrame读取单列

每个Series的列都可以使用DataFrame的属性读取。例如,我们可以使用nba.Salary读取Salary列:

In  [48]: nba.Salary
Out [48]: Name
          Shake Milton     1445697
          Christian Wood   1645357
          PJ Washington    3831840
          Derrick Rose     7317074
          Marial Shayo       79568
                               ...
          Austin Rivers    2174310
          Harry Giles      2578800
          Robin Lopez      4767000
          Collin Sexton    4764960
          Ricky Rubio     16200000
          Name: Salary, Length: 450, dtype: int64

如果您希望始终使用二维数据结构,可以使用to_frame方法将Series转换为DataFrame:

In  [49]: nba.Salary.to_frame()
Out [49]:                     Salary
                    Name
            Shake Milton     1445697
          Christian Wood     1645357
           PJ Washington     3831840
            Derrick Rose     7317074
           Marial Shayok       79568
                       …           …
           Austin Rivers     2174310
             Harry Giles     2578800
             Robin Lopez     4767000
           Collin Sexton     4764960
             Ricky Rubio    16200000
          450 rows × 1 columns

也可以通过名称来读取列,这种方法的优点是它支持名称中带有空格的列。

In  [50]: nba["Position"]
Out [50]: Name
          Shake Milton      SG
          Christian Wood    PF
          PJ Washington     PF
          Derrick Rose      PG
          Marial Shayok      G
                            ..
          Austin Rivers     PG
          Harry Giles       PF
          Robin Lopez        C
          Collin Sexton     PG
          Ricky Rubio       PG
          Name: Position, Length: 450, dtype: object

6.2 从DataFrame读取多列

要读取多个列,只需要在列表中指定多个列名,返回的是一个新的DataFrame。它的列的排列顺序和列表中的一样,这是重新排列DataFrame列的有效方式:

In  [51]: nba[["Salary", "Birthday"]]
Out [51]:                    Salary      Birthday
                    Name
            Shake Milton    1445697    1996-09-26
          Christian Wood    1645357    1995-09-27
           PJ Washington    3831840    1998-08-23
            Derrick Rose    7317074    1988-10-04
           Marial Shayok      79568    1995-07-26
                       …          …             …
           Austin Rivers    2174310    1992-08-01
             Harry Giles    2578800    1998-04-22
             Robin Lopez    4767000    1988-04-01
           Collin Sexton    4764960    1999-01-04
             Ricky Rubio   16200000    1990-10-21
          450 rows × 2 columns

如果我们想根据列的数据类型来选择列,可以使用select_dtypes方法,其include和exclude这两个参数可以指定单个数据类型或多个数据类型的列表。提醒一下,您可以使用dtypes属性查看数据集中的数据类型。

In  [52]: # 仅选择字符串类型的列
    `     nba.select_dtypes(include = "object")
Out [52]:                               Team Position
                    Name                      
            Shake Milton  Philadelphia 76ers 	   SG
          Christian Wood     Detroit Pistons       PF
           PJ Washington   Charlotte Hornets 	   PF
            Derrick Rose     Detroit Pistons 	   PG
           Marial Shayok  Philadelphia 76ers 	    G
                       … 			       … 	    …
           Austin Rivers     Houston Rockets 	   PG
    	     Harry Giles    Sacramento Kings 	   PF
             Robin Lopez     Milwaukee Bucks 	    C
           Collin Sexton  Cleveland Cavaliers 	   PG
             Ricky Rubio           Phoenix Suns    PG
          450 rows × 2 columns

In  [53]: # 排除字符串和整数类型的列
          nba.select_dtypes(exclude = ["object", "int"])
Out [53]:	                  Birthday
                    Name                      
            Shake Milton    1996-09-26
          Christian Wood    1995-09-27
           PJ Washington    1998-08-23
            Derrick Rose    1988-10-04
           Marial Shayok    1995-07-26
       		           … 	         …
           Austin Rivers    1992-08-01
             Harry Giles    1998-04-22
             Robin Lopez    1988-04-01
           Collin Sexton    1999-01-04
             Ricky Rubio    1990-10-21
          450 rows × 1 columns

7. 从DataFrame读取行

DataFrame中的行可以通过索引标签或索引位置读取。

7.1 通过索引标签读取行

loc属性返回具有给定索引标签行的Series,注意是区分大小写。下例是返回索引标签是"LeBron James"的行:

In  [54]: nba.loc["LeBron James"]
Out [54]: Team         Los Angeles Lakers
          Position                     PF
          Birthday    1984-12-30 00:00:00
          Salary                 37436858
          Name: LeBron James, dtype: object

还可以给定一个列表以读取多行,返回结果是一个DataFrame,顺序和给定的列表一样:

In  [55]: nba.loc[["Kawhi Leonard", "Paul George"]]
Out [55]:                                 Team Position     Birthday     Salary
                   Name
          Kawhi Leonard   Los Angeles Clippers       SF   1991-06-29   32742000
            Paul George   Los Angeles Clippers       SF   1990-05-02   33005556

Pandas还支持Python的列表切片语法。例如,我们可以对索引标签进行排序以按字母顺序获得球员的姓名,然后选择Otto Porter和Patrick Beverley之间的所有球员。注意,两个端点的球员也会被包括在内:

In  [56]: nba.sort_index().loc["Otto Porter":"Patrick Beverley"]
Out [56]:                                    Team Position     Birthday     Salary
                      Name
               Otto Porter          Chicago Bulls       SF   1993-06-03   27250576
                 PJ Dozier         Denver Nuggets       PG   1996-10-25      79568
             PJ Washington      Charlotte Hornets       PF   1998-08-23    3831840
             Pascal Siakam        Toronto Raptors       PF   1994-04-02    2351838
           Pat Connaughton        Milwaukee Bucks       SG   1993-01-06    1723050
          Patrick Beverley   Los Angeles Clippers       PG   1988-07-12   12345680

我们还可以读取DataFrame从某行开始到最后一行的数据,它与从Python列表中读取分片的语法相同,也就是在初始索引标签后加一个冒号:

In  [57]: nba.sort_index().loc["Zach Collins":]
Out [57]:                                    Team Position     Birthday      Salary
                     Name
             Zach Collins  Portland Trail Blazers        C   1997-11-19     4240200
              Zach LaVine           Chicago Bulls       PG   1995-03-10    19500000
             Zach Norvell      Los Angeles Lakers       SG   1997-12-09       79568
             Zhaire Smith      Philadelphia 76ers       SG   1999-06-04     3058800
          Zion Williamson    New Orleans Pelicans        F   2000-07-06     9757440
           Zylan Cheatham    New Orleans Pelicans       SF   1995-11-17       79568

同理可以读取DataFrame从开头到某行的数据,下例返回所从开头到"Al Horford"的行:

In  [58]: nba.sort_index().loc[:"Al Horford"]
Out [58]:                                     Team Position    Birthday    Salary
                       Name
               Aaron Gordon          Orlando Magic       PF  1995-09-16  19863636
              Aaron Holiday         Indiana Pacers       PG  1996-09-30   2239200
                Abdel Nader  Oklahoma City Thunder       SF  1993-09-25   1618520
                Adam Mokoka          Chicago Bulls        G  1998-07-1      79568
          Admiral Schofield     Washington Wizards       SF  1997-03-30   1000000
                 Al Horford     Philadelphia 76ers        C  1986-06-03  28000000

如果DataFrame中不存在指定的索引标签,则会抛出KeyError异常:

In  [59]: nba.loc["Bugs Bunny"]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
KeyError: 'Bugs Bunny'

7.2 通过索引位置读取行

iloc(索引位置index location)属性返回具有给定索引位置的一行或多行,参数可以是单个整数或整数的列表:

In  [60]: nba.iloc[300]
Out [60]: Team            Denver Nuggets
          Position                    PF
          Birthday   1999-04-03 00:00:00
          Salary                 1416852
          Name: Jarred Vanderbilt, dtype: object

In  [61]: nba.iloc[[100, 200, 300, 400]]
Out [61]:                                 Team Position    Birthday   Salary
                       Name
                Brian Bowen     Indiana Pacers       SG  1998-10-02    79568
            Marco Belinelli  San Antonio Spurs       SF  1986-03-25  5846154
          Jarred Vanderbilt     Denver Nuggets       PF  1999-04-03  1416852
               Louis King      Detroit Pistons        F  1999-04-06    79568

列表切片的语法在这里也是使用的,需要注意冒号后面指定端点的行是不包括的。下例返回索引位置400、401、402和403的行:

In  [62]: nba.iloc[400:404]
Out [62]:                                     Team Position    Birthday     Salary
                          Name
                    Louis King     Detroit Pistons        F  1999-04-06      79568
          Kostas Antetokounmpo  Los Angeles Lakers       PF  1997-11-20      79568
                Rodions Kurucs       *lyn Nets       PF  1998-02-05    1699236
             Spencer Dinwiddie       *lyn Nets       PG  1993-04-06   10605600

In  [63]: nba.iloc[:2] # 读取头两行
Out [63]:                                Team Position     Birthday    Salary
                    Name
            Shake Milton   Philadelphia 76ers       SG   1996-09-26   1445697
          Christian Wood      Detroit Pistons       PF   1995-09-27   1645357

In  [64]: nba.iloc[447:] # 读取从索引位置447到最后
Out [64]:                                Team Position     Birthday     Salary
                   Name
            Robin Lopez       Milwaukee Bucks        C   1988-04-01    4767000
          Collin Sexton   Cleveland Cavaliers       PG   1999-01-04    4764960
            Ricky Rubio          Phoenix Suns       PG   1990-10-21   16200000

索引位置也可以使用负数,也就是从倒数开始数。下例是从倒数第10行直到倒数第6行,但不包括倒数第6行:

In  [65]: nba.iloc[-10:-6]
Out [65]:                                      Team Position     Birthday    Salary
                       Name
               Jared Dudley      Los Angeles Lakers       PF   1985-07-10   2564753
                  Max Strus            ChicagoBulls       SG   1996-03-28     79568
               Kevon Looney   Golden State Warriors        C   1996-02-06   4464286
          Willy Hernangomez       Charlotte Hornets        C   1994-05-27   1557250

除此以外还可以指定索引位置的步长序列。在下例中,我们从前十行中选择间隔为2的行。因此,返回结果的索引位置为0、2、4、6和8:

In  [66]: nba.iloc[0:10:2]
Out [66]:                               Team Position     Birthday     Salary
                  Name
           Shake Milton   Philadelphia 76ers       SG   1996-09-26    1445697
          PJ Washington    Charlotte Hornets       PF   1998-08-23    3831840
          Marial Shayok   Philadelphia 76ers        G   1995-07-26      79568
          Kendrick Nunn           Miami Heat       SG   1995-08-03    1416852
            * Lopez      Milwaukee Bucks        C   1988-04-01   12093024

7.3 从行的指定列中读取值

loc和iloc属性都支持第二个参数指定要读取的列。在下例中,我们读取索引标签为"Giannis Antetokounmpo" 所在行的Team列的值:

In  [67]: nba.loc["Giannis Antetokounmpo", "Team"]
Out [67]: 'Milwaukee Bucks'

两个参数都支持传递列表,下例第二个参数使用列表指定要读取Position和Birthday列的值:

In  [68]: nba.loc["James Harden", ["Position", "Birthday"]]
Out [68]: Position                    PG
          Birthday   1989-08-26 00:00:00
          Name: James Harden, dtype: object

下例第一、二个参数都使用了列表:

In  [69]: nba.loc[["Russell West*", "Anthony Davis"],
                  ["Team", "Salary"]]
Out [69]:                                   Team     Salary
                       Name
          Russell West*      Houston Rockets   38506482
              Anthony Davis   Los Angeles Lakers   27093019

列表切片语法也可以用于读取多个列,注意,这里两个端点都将包括在内:

In  [70]: nba.loc["Joel Embiid", "Position":"Salary"]
Out [70]: Position                     C
          Birthday   1994-03-16 00:00:00
          Salary                27504630
          Name: Joel Embiid, dtype: object

参数指定的列名必须和它们在DataFrame中出现的顺序一样。下例会返回空列表,因为Salary列位于Position列之后:

In  [71]: nba.loc["Joel Embiid", "Salary":"Position"]
Out [71]: Series([], Name: Joel Embiid, dtype: object)

每个DataFrame列都分配有一个索引位置,在我们当前的DataFrame中,Team的索引为0,Position的索引为1,依此类推。

In  [72]: nba.columns
Out [72]: Index(['Team', 'Position', 'Birthday', 'Salary'], dtype='object')

列的索引位置也可以作为第二个参数传给iloc:

In  [73]: nba.iloc[57, 3]
Out [73]: 796806

列表切片语法也可以在此处使用。下例返回索引位置100到104(不包括)所在行的从开始到索引位置3(不包括)的列:

In  [74]: nba.iloc[100:104, :3]
Out [74]:                                Team Position      Birthday
                   Name
            Brian Bowen        Indiana Pacers       SG    1998-10-02
          Aaron Holiday        Indiana Pacers       PG    1996-09-30
           Troy Daniels    Los Angeles Lakers       SG    1991-07-15
            Buddy Hield      Sacramento Kings       SG    1992-12-17

iloc和loc属性非常通用,参数可以是单个值、列表、列表切片等。这种灵活性的缺点是需要额外的开销,pandas必须检查iloc或loc的输入类型。

当我们要从DataFrame中读取单个值时,可以使用at和iat这两个替代属性: at属性的参数是行和列标签,而iat属性的参数是行和列索引位置:

In  [75]: nba.at["Austin Rivers", "Birthday"]
Out [75]: Timestamp('1992-08-01 00:00:00')

In  [76]: nba.iat[263, 1]
Out [76]: 'PF'

8. 重命名列或行

我们可以通过使用新名称列表覆盖columns属性来重命名DataFrame中的某些或所有列:

In  [77]: nba.columns
Out [77]: Index(['Team', 'Position', 'Birthday', 'Salary'], dtype='object')

In  [78]: nba.columns = ["Team", "Position", "Date of Birth", "Pay"]
          nba.head(1)
Out [78]:                              Team Position Date of Birth        Pay
                  Name
          Shake Milton   Philadelphia 76ers       SG    1996-09-26    1445697

我们也可以使用rename方法,其参数columns的值类型是一个字典,键是需要修改的原列名,值是新的列名。下例是把原列名"Date of Birth"重命名为"Birthday":

In  [79]: nba.rename(columns = { "Date of Birth": "Birthday" })
Out [79]:                                Team Position     Birthday        Pay
                    Name
            Shake Milton   Philadelphia 76ers       SG   1996-09-26    1445697
          Christian Woo       Detroit Pistons       PF   1995-09-27    1645357
           PJ Washington    Charlotte Hornets       PF   1998-08-23    3831840
            Derrick Rose      Detroit Pistons       PG   1988-10-04    7317074
           Marial Shayok   Philadelphia 76ers        G   1995-07-26      79568
                       …                    …        …            …          …
           Austin Rivers      Houston Rockets       PG   1992-08-01    2174310
             Harry Giles     Sacramento Kings       PF   1998-04-22    2578800
             Robin Lopez      Milwaukee Bucks        C   1988-04-01    4767000
           Collin Sexton  Cleveland Cavaliers       PG   1999-01-04    4764960
             Ricky Rubio         Phoenix Suns       PG   1990-10-21   16200000
          450 rows × 4 columns

一如既往地,使用 inplace 参数使修改永久生效:

In  [80]: nba.rename(
              columns = { "Date of Birth": "Birthday" },
              inplace = True
          )

rename方法也可以重命名索引标签。下例将 "Giannis Antetokounmpo" 重命名为他的昵称 "Greek Freak":

In  [81]: nba.loc["Giannis Antetokounmpo"]
Out [81]: Team            Milwaukee Bucks
          Position                     PF
          Birthday    1994-12-06 00:00:00
          Pay                    25842697
          Name: Giannis Antetokounmpo, dtype: object

In  [82]: nba.rename(
              index = { "Giannis Antetokounmpo": "Greek Freak" },
              inplace = True
          )

In  [83]: nba.loc["Greek Freak"]
Out [83]: Team           Milwaukee Bucks
          Position                    PF
          Birthday   1994-12-06 00:00:00
          Pay                   25842697
          Name: Greek Freak, dtype: object

9. 重置索引

如果我们想把另一列用作DataFrame的索引,可以使用set_index方法,但会造成当前索引Name的丢失:

In  [84]: nba.set_index("Team").head()
Out [84]:                     Position      Birthday        Pay
                        Team
          Philadelphia 76ers        SG    1996-09-26    1445697
             Detroit Pistons        PF    1995-09-27    1645357
           Charlotte Hornets        PF    1998-08-23    3831840
             Detroit Pistons        PG    1988-10-04    7317074
          Philadelphia 76ers         G    1995-07-26      79568

为了保留原来的索引列Name,我们首先要使用reset_index方法把现有索引重新整合为DataFrame中的常规列,并生成新的顺序索引:

In  [85]: nba.reset_index().head()
Out [85]:               Name                 Team Position     Birthday       Pay
          0     Shake Milton   Philadelphia 76ers       SG   1996-09-26   1445697
          1   Christian Wood      Detroit Pistons       PF   1995-09-27   1645357
          2    PJ Washington    Charlotte Hornets       PF   1998-08-23   3831840
          3     Derrick Rose      Detroit Pistons       PG   1988-10-04   7317074
          4    Marial Shayok   Philadelphia 76ers        G   1995-07-26     79568

现在我们可以放心使用set_index方法了:

In  [86]: nba.reset_index().set_index("Team").head()
Out [86]:                                Name Position     Birthday       Pay
                        Team
          Philadelphia 76ers     Shake Milton       SG   1996-09-26   1445697
             Detroit Pistons   Christian Wood       PF   1995-09-27   1645357
           Charlotte Hornets    PJ Washington       PF   1998-08-23   3831840
             Detroit Pistons     Derrick Rose       PG   1988-10-04   7317074
          Philadelphia 76ers    Marial Shayok        G   1995-07-26     79568

reset_index方法也支持inplace参数,但是要注意:如果参数设置为True,则该方法将不会返回新的DataFrame,因此不能直接链接调用set_index方法,必须依次分开单独调用:

In  [87]: nba.reset_index(inplace = True)
          nba.set_index("Name", inplace = True)

 

END O(∩_∩)O

上一篇:MongoDB入门详细教程


下一篇:基于Html+Css+javascript的网页制作(体育主题)