返回介绍

第32单元 数据重塑

发布于 2024-01-28 22:01:16 字数 7855 浏览 0 评论 0 收藏 0

数据标签是pandas对表格数据的主要贡献。所谓数据标签,是指与列和行相关联的数字或文本标签(例如与列对应的列名,以及与行对应的扁平化索引和分层索引)。这样的关联是非常灵活的:为了与其他frame相匹配,可以修改底层的numpy数组的形状(请参阅第22单元的reshape()函数),这种修改可能会使frame的某些行变为列,某些列变为行。例如,如果一个frame的分层索引具有两个级别(比如“Year”和“State”),而要匹配的另一个frame只具有“State”索引,则pandas会将“Year”标签自动转换为列名。在本单元中,你将了解扁平索引、分层索引和重建索引,以及其他重组数据标签的方式。

索引

frame的索引是一组分配给frame行的标签集合。(标签必须属于相同的数据类型,但标签的值不一定是唯一的。)通过可选参数index,可以给DataFrame()构造器提供索引。和series类似,可以通过属性index.values和columns.values访问和更改列名及索引。

   alco2009.columns.values

➾ array(['Beer', 'Wine', 'Spirits', 'Total'], dtype=object)

   alco2009.index.values

➾ array(['Alabama', 'Alaska', 'Arizona', «...»], dtype=object)

frame中的任意一列都可以作为一个索引——函数reset_index()和set_index(column)分别用于删除现有索引(如果存在的话)和建立一个新索引。这两个函数都返回一个新的frame,但是如果提供了可选参数inplace=True,则函数将直接修改frame对象本身:

   alco2009.reset_index().set_index("Beer").head()

➾            State  Wine  Spirits  TotalBeer1.20     Alabama  0.22     0.58      01.31      Alaska  0.54     1.16      01.19     Arizona  0.38     0.74      01.07    Arkansas  0.17     0.60      01.05  California  0.55     0.73      0

frame的索引是重要的行访问工具和相关的行标识符。无论使用哪个列作为索引,它必须是有意义的。在上面的例子中,使用的列就没有意义:啤酒消费量是州的属性,但不是标识符。

一旦有了索引,就可以通过行的索引属性ix来访问某一行,这就像是一个用索引标签作为键的行series的字典。frame的列作为每个series的索引:

   alco2009.ix["Nebraska"]

➾ Beer       1.46Wine       0.20Spirits    0.68Total      0.00Name: Nebraska, dtype: float64

Python运算符in可以检查具有某个标签的行是否存在于frame中:

   "Samoa" in alco2009.index

➾ False

函数drop()返回一个删除了一行或若干行(用列表表示)的frame的副本。如果要删除原始frame中的行,请传递可选参数inplace=True。

重建索引

重建索引从现有的frame或series中选择一定的行排列、列排列或者行和列排列,来创建新的frame或series。本质上,它等同于numpy的一个“智能”索引(参见第23单元),只不过如果pandas在原始frame中找不到请求的行或列标签,它将创建一个新的行或列,并用nan填充它(或它们)。

在下面的例子中,我们创建名称以“S”开头的州列表(该列表包含了不是州名的“Samoa”,当然它也不在alco2009 frame中)。然后,除了最后一列(即“Total”列,它没有被正确初始化)之外,再添加名为“Water”的列。最后,从原始的frame中提取所选的行和列。因为有一行和一列不在原始的frame alco 2009中,所以pandas会自动创建它们:

   s_states = [state for state in alco2009.index if state[0] == 'S'] + ["Samoa"]
   drinks = list(alco2009.columns) + ["Water"]
   nan_alco = alco2009.reindex(s_states, columns=drinks)

➾                Beer  Wine  Spirits  WaterStateSouth Carolina 1.36  0.24     0.77    NaNSouth Dakota   1.53  0.22     0.88    NaNSamoa           NaN  NaN       NaN    NaN

可选参数method的可能值为"ffill"(正向填充)和"bfill"(后向填充),可以用于填补缺失的值。(这仅适用于单调减或单调增的索引。)关于数据插值的更多信息,请参阅第33单元。

分层索引

pandas支持分层(多级)索引和分层(多级)列名。多级索引也称为多重索引。

多级索引由三个列表组成:

级别名称

每个级别可能存在的所有标签

frame或series中每一项的实际值的列表(列表的长度相同,并等于索引中的级别数)

下面的frame包含完整版本的NIAAA数据集,不只是2009年。它具有州名和年份的多级索引,并且按照两个索引进行排序:先按州名排序,后按年份排序。

   alco

➾              Beer Wine SpiritsState   YearAlabama 1977 0.99 0.13    0.841978 0.98 0.12    0.881979 0.98 0.12    0.841980 0.96 0.16    0.741981 1.00 0.19    0.73«...»Wyoming 2005 1.21 0.23    0.972006 1.47 0.23    1.052007 1.49 0.23    1.102008 1.54 0.23    1.122009 1.45 0.22    1.10

数据转换操作通常会产生分层索引,但你也可以专门构建它们。函数MultiIndex.from_ tuples()使用带有标签的元组和可选的级别名称列表生成多级索引。可以将多级索引附加到现有的frame或series中,或将其作为参数传递给构造函数DataFrame():

   multi = pd.MultiIndex.from_tuples((
           ("Alabama", 1977), ("Alabama", 1978), ("Alabama", 1979), ...,
           ("Wyoming", 2009)),
           names=["State", "Year"])

➾ MultiIndex(levels=[['Alabama', 'Alaska', «...», 'Wyoming'],[1977, 1978, 1979, 1980, «...», 2009]],labels=[[0, 0, 0, 0, 0, 0, 0, 0, «...», 50],[0, 1, 2, 3, 4, 5, 6, 7, «...», 32]],names=['State', 'Year'])

   alco.index = multi

可以使用与扁平化索引相同的多级索引。部分索引(使用几个标签中的某一个)产生一个frame;完整的索引产生一个series。

   alco.ix['Wyoming'].head()

➾      Beer Wine SpiritsYear1977 1.79 0.21    1.321978 1.82 0.22    1.361979 1.86 0.22    1.301980 1.85 0.24    1.321981 1.91 0.24    1.27

   alco.ix['Wyoming', 1999]

➾ Beer       1.41Wine       0.18Spirits    0.84Name: (Wyoming, 1999), dtype: float64

pandas使用相同的方式处理多级索引和列,这使得索引级别可能会变成列级别,反之亦然。

堆叠和旋转

使用多级的列名可以将多级索引完全或部分扁平化,同样,使用多级索引则可以将多级列名完全或部分扁平化。

stack()函数会增加索引的级别数,同时减少列名的级别数。它使得frame更高更窄,如下图所示。如果列名已经扁平化了,则函数返回一个series。函数unstack()的作用相反:它减少索引的级别数,同时增加列名的级别数。它使得frame更短更宽。如果索引已经扁平化了,则函数返回一个series。

   tall_alco = alco.stack()
   tall_alco.index.names += ["Drink"]
   tall_alco.head(10)

➾ State    Year  DrinkAlabama  1977  Beer      0.99Wine      0.13Spirits   0.841978  Beer      0.98Wine      0.12Spirits   0.881979  Beer      0.98Wine      0.12Spirits   0.841980  Beer      0.96dtype: float64

上述操作的结果是一个具有三级索引的series(在这里我不得不提供缺少的第三级的名称—— “Drink”)。

   wide_alco = alco.unstack()
   wide_alco.head()

➾            Beer                                                       ...Year       1977  1978  1979  1980  1981  1982  1983  1984  1985  1986 ...State                                                        ...Alabama    0.99  0.98  0.98  0.96  1.00  1.00  1.01  1.02  1.06  1.09 ...Alaska     1.19  1.39  1.50  1.55  1.71  1.75  1.76  1.73  1.68  1.68 ...Arizona    1.70  1.77  1.86  1.69  1.78  1.74  1.62  1.57  1.67  1.77 ...Arkansas   0.92  0.97  0.93  1.00  1.06  1.03  1.03  1.02  1.03  1.06 ...California 1.31  1.36  1.42  1.42  1.43  1.37  1.37  1.38  1.32  1.36 ...[5 rows x 99 columns]

上述操作的结果是具有扁平索引和两级分层列名的frame。你经常会在CSV和其他表格文件中看到这些类型的frame。为了使数据更加“方正”,更加易于管理,你可能需要将它们堆叠起来。

堆叠和拆分是更一般的绕轴旋转(pivoting)操作的特殊情况。函数pivot(index, columns,values)将frame转换为另一个frame,新的frame使用列索引作为新的索引,columns作为新的列名列表,values作为数据。

在下面的例子中,alco被重新组织成一个“方正”的frame,按年份(新的扁平索引)和州(列名)描述葡萄酒的消费情况:

   alco.pivot("Year", "State", "Wine")

➾ State Alabama Alaska Arizona Arkansas California Colorado ConnecticutYear1977     0.13   0.42    0.34     0.10       0.67     0.36        0.351978     0.12   0.45    0.37     0.11       0.68     0.47        0.381979     0.12   0.47    0.39     0.10       0.70     0.47        0.401980     0.16   0.50    0.36     0.12       0.71     0.47        0.43«...»[33 rows x 51 columns]

如果index为None,则pandas会重新使用原始frame的索引。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文