Introduction

在上一篇教程中,我们学习了如何从 DataFrame 或 Series 中筛选出相关数据。正如我们在练习中所演示的那样,从数据表示中提取正确的数据对于完成工作至关重要。

然而,数据并非总是以我们想要的格式从内存中直接输出。有时,我们需要自行进行一些工作来重新格式化数据以适应当前任务。本教程将介绍我们可以对数据应用的不同操作,以使输入“恰到好处”。

要开始本主题的练习,请点击此处

我们将使用《葡萄酒杂志》的数据进行演示。

import pandas as pd
pd.set_option('display.max_rows', 5)
import numpy as np
reviews = pd.read_csv("../input/wine-reviews/winemag-data-130k-v2.csv", index_col=0)
reviews

Out[2]:

country description designation points price province region_1 region_2 taster_name taster_twitter_handle title variety winery
0 Italy Aromas include tropical fruit, broom, brimston… Vulkà Bianco 87 NaN Sicily & Sardinia Etna NaN Kerin O’Keefe @kerinokeefe Nicosia 2013 Vulkà Bianco (Etna) White Blend Nicosia
1 Portugal This is ripe and fruity, a wine that is smooth… Avidagos 87 15.0 Douro NaN NaN Roger Voss @vossroger Quinta dos Avidagos 2011 Avidagos Red (Douro) Portuguese Red Quinta dos Avidagos
129969 France A dry style of Pinot Gris, this is crisp with … NaN 90 32.0 Alsace Alsace NaN Roger Voss @vossroger Domaine Marcel Deiss 2012 Pinot Gris (Alsace) Pinot Gris Domaine Marcel Deiss
129970 France Big, rich and off-dry, this is powered by inte… Lieu-dit Harth Cuvée Caroline 90 21.0 Alsace Alsace NaN Roger Voss @vossroger Domaine Schoffit 2012 Lieu-dit Harth Cuvée Car… Gewürztraminer Domaine Schoffit

129971 行 × 13 列

Summary functions

Pandas 提供了许多简单的“摘要函数”(非官方名称),它们可以以某种有用的方式重构数据。例如,考虑 describe() 方法:

In [3]:

reviews.points.describe()

Out[3]:

count    129971.000000
mean 88.447138
...
75% 91.000000
max 100.000000
Name: points, Length: 8, dtype: float64

此方法生成给定列属性的高级摘要。它具有类型感知功能,这意味着其输出会根据输入的数据类型而变化。上面的输出仅适用于数值数据;对于字符串数据,我们得到的结果如下:

In [4]:

reviews.taster_name.describe()

Out[4]:

count         103727
unique 19
top Roger Voss
freq 25514
Name: taster_name, dtype: object

如果您想获取 DataFrame 或 Series 中某一列的某些简单的摘要统计信息,通常可以使用 pandas 函数来实现。

例如,要查看所分配分数的平均值(例如,一款平均评分的葡萄酒的评价如何),我们可以使用 mean() 函数:

In [5]:

reviews.points.mean()

Out[5]:

88.44713820775404

要查看唯一值列表,我们可以使用“unique()”函数:

In [6]:

reviews.taster_name.unique()

Out[6]:

array(['Kerin O’Keefe', 'Roger Voss', 'Paul Gregutt',
'Alexander Peartree', 'Michael Schachner', 'Anna Lee C. Iijima',
'Virginie Boone', 'Matt Kettmann', nan, 'Sean P. Sullivan',
'Jim Gordon', 'Joe Czerwinski', 'Anne Krebiehl\xa0MW',
'Lauren Buzzeo', 'Mike DeSimone', 'Jeff Jenssen',
'Susan Kostrzewa', 'Carrie Dykes', 'Fiona Adams',
'Christina Pickard'], dtype=object)

要查看唯一值列表以及它们在数据集中出现的频率,我们可以使用“value_counts()”方法:

In [7]:

reviews.taster_name.value_counts()

Out[7]:

Roger Voss           25514
Michael Schachner 15134
...
Fiona Adams 27
Christina Pickard 6
Name: taster_name, Length: 19, dtype: int64

Maps

map 是一个源自数学的术语,指将一组值“映射”到另一组值的函数。在数据科学中,我们经常需要根据现有数据创建新的表示,或者将数据从当前格式转换为我们期望的格式。map 就是处理这项工作的工具,因此它们对于完成工作至关重要!

有两种映射方法你会经常使用。

map() 是第一种,也稍微简单一些。例如,假设我们想将葡萄酒的得分重新平均为 0。我们可以这样做:

In [8]:

review_points_mean = reviews.points.mean()
reviews.points.map(lambda p: p - review_points_mean)

Out[8]:

0        -1.447138
1 -1.447138
...
129969 1.552862
129970 1.552862
Name: points, Length: 129971, dtype: float64

传递给 map() 的函数应该从 Series 中获取一个值(在上例中是一个点值),并返回该值的转换版本。map() 返回一个新的 Series,其中所有值都已由你的函数转换。

如果我们想通过在每一行上调用自定义方法来转换整个 DataFrame,那么 apply() 是等效方法。

In [9]:

def remean_points(row):
row.points = row.points - review_points_mean
return row

reviews.apply(remean_points, axis='columns')

Out[9]:

country description designation points price province region_1 region_2 taster_name taster_twitter_handle title variety winery
0 Italy Aromas include tropical fruit, broom, brimston… Vulkà Bianco -1.447138 NaN Sicily & Sardinia Etna NaN Kerin O’Keefe @kerinokeefe Nicosia 2013 Vulkà Bianco (Etna) White Blend Nicosia
1 Portugal This is ripe and fruity, a wine that is smooth… Avidagos -1.447138 15.0 Douro NaN NaN Roger Voss @vossroger Quinta dos Avidagos 2011 Avidagos Red (Douro) Portuguese Red Quinta dos Avidagos
129969 France A dry style of Pinot Gris, this is crisp with … NaN 1.552862 32.0 Alsace Alsace NaN Roger Voss @vossroger Domaine Marcel Deiss 2012 Pinot Gris (Alsace) Pinot Gris Domaine Marcel Deiss
129970 France Big, rich and off-dry, this is powered by inte… Lieu-dit Harth Cuvée Caroline 1.552862 21.0 Alsace Alsace NaN Roger Voss @vossroger Domaine Schoffit 2012 Lieu-dit Harth Cuvée Car… Gewürztraminer Domaine Schoffit

129971 行 × 13 列

如果我们调用 reviews.apply() 时传入 `axis=’index’,那么我们就需要传入一个函数来转换每一行,而不是传入一个函数来转换每一列。

需要注意的是,map()apply() 分别返回转换后的新 Series 和 DataFrame。它们不会修改调用它们的原始数据。如果我们查看 reviews 的第一行,就会发现它仍然保留着原来的 points 值。

In [10]:

reviews.head(1)

Out[10]:

country description designation points price province region_1 region_2 taster_name taster_twitter_handle title variety winery
0 Italy Aromas include tropical fruit, broom, brimston… Vulkà Bianco 87 NaN Sicily & Sardinia Etna NaN Kerin O’Keefe @kerinokeefe Nicosia 2013 Vulkà Bianco (Etna) White Blend Nicosia

Pandas 内置了许多常见的映射操作。例如,下面是一种更快速地重新定义 points 列的方法:

In [11]:

review_points_mean = reviews.points.mean()
reviews.points - review_points_mean

Out[11]:

0        -1.447138
1 -1.447138
...
129969 1.552862
129970 1.552862
Name: points, Length: 129971, dtype: float64

在这段代码中,我们在左侧的多个值(Series 中的所有内容)和右侧的单个值(平均值)之间执行运算。Pandas 会查看这个表达式,并计算出我们的意思是从数据集中的每个值中减去该平均值。

如果我们在等长的 Series 之间执行这些运算,Pandas 也能理解该怎么做。例如,合并数据集中的国家和地区信息的一种简单方法是执行以下操作:

In [12]:

reviews.country + " - " + reviews.region_1

Out[12]:

0            Italy - Etna
1 NaN
...
129969 France - Alsace
129970 France - Alsace
Length: 129971, dtype: object

这些运算符比 map()apply() 更快,因为它们使用了 Pandas 内置的加速功能。所有标准 Python 运算符(><== 等)都以这种方式工作。

然而,它们不如 map()apply() 灵活,后者可以执行更高级的操作,例如应用条件逻辑,而这仅靠加法和减法是无法实现的。

Your turn

如果你还没有开始练习,你可以**从这里开始**。