1、处理缺失值
欢迎来到Kaggle学习的数据清理课程!
数据清理是数据科学的一个关键部分,但它可能会非常令人沮丧。为什么你的一些文本字段是乱码?您应该如何处理这些丢失的值?为什么你的日期格式不正确?如何快速清理不一致的数据输入?在本课程中,您将了解为什么会遇到这些问题,更重要的是,如何解决这些问题!
在本课程中,您将学习如何解决一些最常见的数据清理问题,以便能够更快地实际分析数据。您将使用真实、混乱的数据完成五个实际操作练习,并回答一些最常见的数据清理问题。
在本笔记本中,我们将了解如何处理缺少的值。
先看一下数据
我们需要做的第一件事是加载我们将要使用的库和数据集。
为了演示,我们将使用美式足球比赛中发生的事件的数据集。在下面的练习中,你将把你的新技能应用到旧金山颁发的建筑许可数据集中。
# modules we'll use
import pandas as pd
import numpy as np
# read in all our data
nfl_data = pd.read_csv("../input/nflplaybyplay2009to2016/NFL Play by Play 2009-2017 (v4).csv")
# set seed for reproducibility
np.random.seed(0)
当您得到一个新的数据集时,首先要做的是查看其中的一些数据集。这可以让您看到所有的数据都被正确读入,并了解数据的情况。在本例中,让我们看看是否有任何缺少的值,这些值将用NaN或None表示。
我们有多少缺失的数据点?
好的,现在我们知道我们确实缺少一些值。让我们看看每列有多少。
# 获取每列缺少的数据点数
missing_values_count = nfl_data.isnull().sum()
# look at the # of missing points in the first ten columns
missing_values_count[0:10]
好像很多!查看数据集中缺失值的百分比可能会有所帮助,以便更好地了解此问题的规模:
# how many total missing values do we have?
total_cells = np.product(nfl_data.shape)
total_missing = missing_values_count.sum()
# percent of data that is missing
percent_missing = (total_missing/total_cells) * 100
print(percent_missing)
哇,这个数据集中几乎四分之一的单元格都是空的!在下一步中,我们将更仔细地查看一些缺少值的列,并尝试找出它们可能发生的情况。
找出数据丢失的原因
在这一点上,我们进入了数据科学的一部分,我喜欢称之为“数据直觉”,我的意思是“真正地审视你的数据,并试图找出它为什么是这样,以及它将如何影响你的分析”。这可能是数据科学中令人沮丧的一部分,特别是如果你对这个领域比较新,没有很多经验的话。为了处理丢失的值,您需要使用直觉来找出丢失值的原因。你可以问自己的一个最重要的问题是:
这个值丢失是因为它没有被记录还是因为它不存在?
如果某个值因为不存在而丢失(比如没有孩子的人的最大孩子的身高),那么尝试猜测它可能是什么就没有意义了。这些值您可能确实希望保持为NaN。另一方面,如果某个值由于未记录而丢失,则可以尝试根据该列和该行中的其他值猜测该值可能是什么。这就是所谓的插补,接下来我们将学习如何做!:)
让我们看一个例子。查看nfl\ U数据帧中缺失值的数量,我注意到“TimesSec”列中有很多缺失值:
# 请看前十列中缺失的点
missing_values_count[0:10]
通过查看文档,我可以看到这个专栏有关于游戏中剩余秒数的信息。这意味着这些值可能丢失是因为它们没有被记录,而不是因为它们不存在。所以,我们应该试着猜测他们应该是什么样的人,而不是把他们当作NA。
另一方面,还有其他一些字段,比如“popultedteam”,也有很多缺少的字段。在这种情况下,虽然,该领域是失踪的,因为如果没有处罚,那么这是没有意义的,说哪支球队被处罚。对于这个列,将其保留为空或者添加第三个值(如“neither”)并使用它来替换NA的值更有意义。
提示:这是一个阅读数据集文档的好地方,如果你还没有!如果您使用的是从其他人那里获得的数据集,您也可以尝试联系他们以获取更多信息。
如果您正在进行非常仔细的数据分析,那么您可以在这一点上逐个查看每一列,以找出填充这些缺失值的最佳策略。在本笔记本的其余部分,我们将介绍一些“快速而肮脏”的技术,这些技术可以帮助您处理丢失的值,但也可能最终删除一些有用的信息或给数据添加一些噪声。
删除缺少的值
如果您很匆忙或者没有理由找出丢失值的原因,那么您可以选择删除包含丢失值的任何行或列(注意:对于重要的项目,我一般不推荐这种方法!花点时间浏览数据并逐个查看所有缺少值的列通常是值得的,这样才能真正了解数据集。)
如果您确定要删除缺少值的行,pandas确实有一个方便的函数dropna()来帮助您完成此操作。让我们在我们的NFL数据集上试试吧!
# 删除包含缺少值的所有行
nfl_data.dropna()
哦,天哪,看起来我们的数据都被删除了!😱 这是因为数据集中的每一行都至少缺少一个值。我们可能会更幸运地删除所有至少缺少一个值的列。
# 删除至少缺少一个值的所有列
columns_with_na_dropped = nfl_data.dropna(axis=1)
columns_with_na_dropped.head()
# 我们损失了多少数据?
print("Columns in original dataset: %d \n" % nfl_data.shape[1])
print("Columns with na's dropped: %d" % columns_with_na_dropped.shape[1])
我们丢失了很多数据,但现在我们已经成功地从数据中删除了所有的NaN。
自动填写缺失值
另一种选择是尝试填充缺少的值。接下来,我将得到NFL数据的一小部分,这样它就可以很好地打印出来。
# 获取NFL数据集的一小部分
subset_nfl_data = nfl_data.loc[:, 'EPA':'Season'].head()
subset_nfl_data
我们可以使用Panda的fillna()函数来填充数据帧中缺少的值。我们有一个选择,就是指定要用什么来替换NaN值。在这里,我想用0替换所有的NaN值。
# 将所有NA替换为0
subset_nfl_data.fillna(0)
我还可以更精明一点,用同一列中紧跟其后的值替换缺少的值(对于观测值具有某种逻辑顺序的数据集来说,这很有意义。)
# 替换同一列中紧跟其后的所有NA值,
# 然后用0替换所有剩余的na
subset_nfl_data.fillna(method='bfill', axis=0).fillna(0)
2、缩放和标准化
在本笔记本中,我们将研究如何缩放和规范化数据(以及两者之间的区别!)。
让我们开始吧!
建立我们的环境
我们需要做的第一件事是加载我们将要使用的库。
# 我们将使用的模块
import pandas as pd
import numpy as np
# 关于Box-Cox变换
from scipy import stats
# 用于最小最大缩放
from mlxtend.preprocessing import minmax_scaling
# 绘图模块
import seaborn as sns
import matplotlib.pyplot as plt
# 为再现性设定种子
np.random.seed(0)
缩放与标准化:有什么区别?
在缩放和规范化之间容易混淆的原因之一是,这些术语有时可以互换使用,更令人困惑的是,它们非常相似!在这两种情况下,您都在转换数值变量的值,以便转换后的数据点具有特定的有用属性。区别在于:
在缩放中,您正在更改数据的范围,而
在标准化中,您正在更改数据分布的形状。
让我们更深入地讨论一下这些选项中的每一个。
缩放比例
这意味着您正在转换数据,使其符合特定的比例,如0-100或0-1。当您使用基于数据点距离度量的方法时,如支持向量机(SVM)或k近邻(KNN),您希望缩放数据。使用这些算法,任何数字特征中“1”的变化都具有相同的重要性。
例如,您可能正在查看某些产品的日元和美元价格。一美元价值约100 Yen,但如果你不标价,像SVM或KNN的方法会考虑1日元的差价,和1美元的差价一样重要。这显然不符合我们对世界的直觉。使用“货币”,您可以在不同货币之间进行转换。但是如果你看的是身高和体重呢?现在还不完全清楚多少磅应该等于一英寸(或者多少公斤应该等于一米)。
通过缩放变量,您可以帮助在平等的基础上比较不同的变量。为了帮助巩固缩放效果,让我们看一个虚构的示例(别担心,我们将在下面的练习中使用真实数据!)
# 从指数分布中随机抽取1000个数据点
original_data = np.random.exponential(size=1000)
# 最大混合比例在0和1之间缩放数据
scaled_data = minmax_scaling(original_data, columns=[0])
# 将两者绘制在一起进行比较
fig, ax = plt.subplots(1,2)
sns.distplot(original_data, ax=ax[0])
ax[0].set_title("Original Data")
sns.distplot(scaled_data, ax=ax[1])
ax[1].set_title("Scaled data")
请注意,数据的形状没有改变,但它现在的范围不是从0到8ish,而是从0到1。
规范化
缩放只会更改数据的范围。规范化是一种更激进的转变。标准化的要点是改变你的观察值,使它们可以被描述为正态分布。
正态分布:也称为“钟形曲线”,这是一种特定的统计分布,其中大致相等的观测值位于平均值之上和之下,平均值和中位数相同,并且有更多的观测值更接近平均值。正态分布也称为高斯分布。
通常,如果要使用假设数据是正态分布的机器学习或统计技术,则需要对数据进行规范化。其中一些例子包括线性判别分析(LDA)和高斯朴素贝叶斯(专业提示:任何名称中带有“Gaussian”的方法都可能假定为正态。)
这里我们用来规范化的方法叫做Box-Cox变换。让我们快速了解一些数据的正常化:
# 使用boxcox规范化指数数据
normalized_data = stats.boxcox(original_data)
# 将两者绘制在一起进行比较
fig, ax=plt.subplots(1,2)
sns.distplot(original_data, ax=ax[0])
ax[0].set_title("Original Data")
sns.distplot(normalized_data[0], ax=ax[1])
ax[1].set_title("Normalized data")
请注意,数据的形状已更改。在正常化之前,它几乎是L形的。但在标准化后,它看起来更像钟形的轮廓(因此称为“钟形曲线”)。
3、解析日期
在本笔记本中,我们将讨论日期。
让我们开始吧!
建立我们的环境
我们需要做的第一件事是加载我们将要使用的库和数据集。我们将使用一个包含2007年至2016年间发生的滑坡信息的数据集。在下面的练习中,您将把新技能应用于全球地震数据集。
# 我们将使用的模块
import pandas as pd
import numpy as np
import seaborn as sns
import datetime
# 读入我们的数据
landslides = pd.read_csv("../input/landslide-events/catalog.csv")
# 为再现性设定种子
np.random.seed(0)
现在我们准备看一些日期!
检查日期列的数据类型
我们首先看一下数据的前五行。
landslides.head()
我们将使用数据框中的“日期”列。让我们确保它看起来确实包含日期。
# 打印日期列的前几行
print(landslides['date'].head())
是的,那些是日期!但仅仅因为我,一个人,能分辨出这些是日期并不意味着Python知道它们是日期。注意,在head()输出的底部,您可以看到该列的数据类型是“object”。
Pandas使用“object”数据类型来存储各种类型的数据类型,但大多数情况下,当您看到数据类型为“object”的列时,其中会包含字符串。
如果查看此处的pandas数据类型文档,您会注意到还有一个特定的datetime64数据类型。因为我们列的数据类型是object而不是datetime64,所以可以看出Python不知道该列包含日期。
我们也可以只查看列的数据类型,而不打印前几行:
# 检查日期列的数据类型
landslides['date'].dtype
您可能需要检查numpy文档,以便将字母代码与对象的数据类型相匹配。”“O”是“object”的代码,所以我们可以看到这两种方法提供了相同的信息。
将日期列转换为日期时间
现在我们知道我们的date列没有被识别为日期,是时候将其转换为日期了。这被称为“解析日期”,因为我们接收字符串并识别其组成部分。
我们可以通过一个名为“strftime指令”的指南了解日期的格式,您可以在这个链接上找到更多信息。基本的想法是,你需要指出日期的哪些部分在哪里,它们之间有什么标点。一个日期有很多可能的部分,但最常见的是%d表示日、%m表示月、%y表示两位数年、%y表示四位数年。
一些例子:
2007年1月17日的格式为“%m/%d/%y”
17-1-2007的格式为“%d-%m-%Y”
回顾滑坡数据集中“日期”列的开头,我们可以看到它的格式是“月/日/两位数年”,因此我们可以使用与第一个示例相同的语法来解析日期:
# 创建一个新列date_parsed,其中包含解析的日期
landslides['date_parsed'] = pd.to_datetime(landslides['date'], format="%m/%d/%y")
现在,当我检查新列的前几行时,我可以看到数据类型是datetime64。我还可以看到,我的日期已稍微重新排列,以便适合默认的order datetime对象(年-月-日)。
# 打印前几行
landslides['date_parsed'].head()
既然我们的日期被正确解析,我们就可以用有用的方式与之交互。
如果我遇到多个日期格式的错误怎么办?当我们在这里指定日期格式时,当一列中有多个日期格式时,有时会遇到错误。如果发生这种情况,您必须尝试推断正确的日期格式。您可以这样做:
landslides['date_parsed'] = pd.to_datetime(landslides['Date'], infer_datetime_format=True)
为什么不总是使用推断日期时间格式=真?有两大理由不总是让熊猫猜时间格式。首先,pandas并不总是能够找出正确的日期格式,特别是如果有人在数据输入方面有创意的话。第二,它比指定日期的确切格式慢得多。
选择月份的哪一天
现在我们有了一列解析的日期,我们可以提取滑坡发生的月份的日期之类的信息。
# 从date_parsed列获取月份的日期
day_of_month_landslides = landslides['date_parsed'].dt.day
day_of_month_landslides.head()
如果我们试图从原始的“date”列中获取相同的信息,我们将得到一个错误:AttributeError:只能使用带有datetimelike值的.dt访问器。这是因为dt.day不知道如何处理dtype为“object”的列。即使我们的数据框中有日期,我们也必须先解析它们,然后才能以有用的方式与它们交互。
绘制月份的日期以检查日期
解析日期的最大危险之一是将月份和日期混淆。to_datetime()函数确实有非常有用的错误消息,但仔细检查我们提取的月份天数是否有意义并没有什么坏处。
为此,让我们绘制一个月中天数的柱状图。我们预计它的值在1到31之间,因为没有理由假设滑坡在一个月的某些日子比其他日子更常见,所以分布相对均匀(因为不是所有月份都有31天。)让我们看看情况是否如此:
# 移除na's
day_of_month_landslides = day_of_month_landslides.dropna()
# 画一个月的哪一天
sns.distplot(day_of_month_landslides, kde=False, bins=31)
是的,看起来我们确实正确地解析了日期&这个图表对我来说很有意义。
4、字符编码
在本笔记本中,我们将使用不同的字符编码。
让我们开始吧!
建立我们的环境
我们需要做的第一件事是加载我们将要使用的库。但不是我们的数据集:我们稍后再讨论!
# 我们将使用的模块
import pandas as pd
import numpy as np
# 字符编码模块
import chardet
# 为再现性设定种子
np.random.seed(0)
什么是编码?
字符编码是一组特定的规则,用于将原始二进制字节字符串(看起来像:011010000011101001)映射到构成人类可读文本的字符(像“hi”)。有许多不同的编码,如果你试图用不同的编码来阅读文本,你最终会得到一个被称为“mojibake”(像mo gee bah kay这样说)的混乱文本。以下是mojibake的一个例子:
您也可能以“未知”字符结束。当用于读取字节字符串的编码中的特定字节和字符之间没有映射时,会打印出以下内容:
字符编码不匹配在今天已经不像以前那么普遍了,但这肯定仍然是一个问题。有很多不同的字符编码,但您需要知道的主要编码是UTF-8。
UTF-8是标准的文本编码。所有Python代码都是UTF-8格式,理想情况下,您的所有数据也应该是UTF-8格式。当事情不在UTF-8中时,你就会遇到麻烦。
在Python2中处理编码非常困难,但谢天谢地,在Python3中它要简单得多(Kaggle笔记本电脑仅使用Python 3。)在Python 3中处理文本时,您会遇到两种主要的数据类型。一种是字符串,默认情况下文本就是字符串。
# 从字符串开始
before = "This is the euro symbol: €"
# 查看它是什么数据类型
type(before)
str
另一个数据是bytes数据类型,它是一个整数序列。通过指定字符串的编码方式,可以将字符串转换为字节:
# 将其编码为不同的编码,替换引起错误的字符
after = before.encode("utf-8", errors="replace")
# 检查类型
type(after)
bytes
如果你看一个bytes对象,你会发现它前面有一个b,后面可能有一些文本。这是因为字节被打印出来,就好像它们是ASCII编码的字符一样(ASCII是一种较旧的字符编码,它实际上不适用于除英语以外的任何语言。)在这里,您可以看到,我们的欧元符号已被一些mojibake所取代,当它像ASCII字符串一样打印时,它看起来像“\xe2\x82\xac”。
# 看看字节是什么样子的
after
b'This is the euro symbol: \xe2\x82\xac'
当我们用正确的编码将字节转换回字符串时,我们可以看到我们的文本都是正确的,这很好!)
# 将其转换回utf-8
print(after.decode("utf-8"))
This is the euro symbol: €
但是,当我们尝试使用不同的编码将字节映射到字符串时,会出现错误。这是因为我们试图使用的编码不知道如何处理我们试图传递的字节。您需要告诉Python字节字符串实际应该使用的编码。
你可以把不同的编码看作是录制音乐的不同方式。您可以在CD、盒式磁带或8音轨上录制相同的音乐。虽然音乐听起来可能或多或少相同,但您需要使用正确的设备播放每种录制格式的音乐。正确的解码器类似于盒式磁带播放机或CD播放机。如果你试着用CD播放机播放一盘磁带,它就是不起作用。
#尝试用ascii编码解码我们的字节
print(after.decode("ascii"))
如果我们试图使用错误的编码从字符串映射到字节,我们也会遇到麻烦。正如我前面所说的,在Python3中,字符串默认为UTF-8,因此如果我们试图将它们像在另一种编码中一样对待,就会产生问题。
例如,如果我们尝试使用encode()将字符串转换为ASCII字节,我们可以要求字节与文本为ASCII时的字节相同。但是,由于文本不是ASCII格式,因此会有一些字符无法处理。我们可以自动替换ASCII无法处理的字符。然而,如果我们这样做,任何非ASCII字符将被替换为未知字符。然后,当我们将字节转换回字符串时,该字符将替换为未知字符。这件事的危险之处在于,没有办法判断它应该是哪个角色。这意味着我们可能刚刚使我们的数据无法使用!
# 从字符串开始
before = "This is the euro symbol: €"
# 将其编码为不同的编码,替换引起错误的字符
after = before.encode("ascii", errors = "replace")
# 将其转换回utf-8
print(after.decode("ascii"))
# 我们丢失了原始的底层字节字符串!一直都是这样
# 替换为未知字符的基础字节字符串:(
This is the euro symbol: ?
这很糟糕,我们希望避免这样做!最好尽快将所有文本转换为UTF-8,并保持这种编码方式。将非UTF-8输入转换为UTF-8的最佳时间是在读入文件时,我们将在下面讨论。
读取有编码问题的文件
您将遇到的大多数文件可能都是用UTF-8编码的。这是Python在默认情况下所期望的,所以大多数情况下您不会遇到问题。但是,有时会出现如下错误:
# 尝试读取非UTF-8格式的文件
kickstarter_2016 = pd.read_csv("../input/kickstarter-projects/ks-projects-201612.csv")
请注意,我们得到的UnicodeDecodeError与我们尝试将UTF-8字节解码为ASCII时得到的相同!这告诉我们这个文件实际上不是UTF-8,但我们不知道它实际上是什么编码。解决这个问题的一种方法是尝试并测试一系列不同的字符编码,看看它们是否有效。不过,更好的方法是使用chardet模块尝试并自动猜测正确的编码是什么。这并不是100%保证是正确的,但它通常比仅仅猜测要快。
我只看一下这个文件的前一万字节。这通常足以很好地猜测编码是什么,并且比查看整个文件要快得多(特别是对于大文件,这可能非常慢。)只查看文件的第一部分的另一个原因是,通过查看错误消息,我们可以看到第一个问题是第11个字符。因此,我们可能只需要查看文件的第一部分,就可以了解发生了什么。
# 查看前一万字节以猜测字符编码
with open("../input/kickstarter-projects/ks-projects-201801.csv", 'rb') as rawdata:
result = chardet.detect(rawdata.read(10000))
# 检查字符编码可能是什么
print(result)
{'encoding': 'Windows-1252', 'confidence': 0.73, 'language': ''}
因此,chardet有73%的信心认为正确的编码是“Windows-1252”。让我们看看这是否正确:
# 使用chardet检测到的编码读入文件
kickstarter_2016 = pd.read_csv("../input/kickstarter-projects/ks-projects-201612.csv", encoding='Windows-1252')
# 看前几行
kickstarter_2016.head()
是的,看起来chardet是对的!文件读入时没有问题(尽管我们确实收到了关于数据类型的警告),当我们查看前几行时,它看起来很好。
如果编码chardet猜测不正确怎么办?由于chardet基本上只是一个花哨的猜测者,有时它会猜测错误的编码。您可以尝试的一件事是查看文件的多多少少,看看是否得到不同的结果,然后再试一次。
使用UTF-8编码保存文件
最后,一旦您经历了将文件转换为UTF-8的所有麻烦,您可能会希望保持这种方式。最简单的方法是使用UTF-8编码保存文件。好消息是,由于UTF-8是Python中的标准编码,因此在保存文件时,默认情况下会将其保存为UTF-8:
# 保存我们的文件(默认情况下将保存为UTF-8!)
kickstarter_2016.to_csv("ks-projects-201801-utf8.csv")
5、不一致的数据输入
在本笔记本中,我们将学习如何清理不一致的文本条目。
让我们开始吧!
建立我们的环境
我们需要做的第一件事是加载我们将要使用的库和数据集。
# 我们将使用的模块
import pandas as pd
import numpy as np
# 有用模块
import fuzzywuzzy
from fuzzywuzzy import process
import chardet
# 读入我们所有的数据
professors = pd.read_csv("../input/pakistan-intellectual-capital/pakistan_intellectual_capital.csv")
# 为再现性设定种子
np.random.seed(0)
做一些初步的文本预处理
首先,我们将快速查看数据的前几行。
professors.head()
假设我们有兴趣清理“Country”列,以确保其中没有数据输入不一致。当然,我们可以手工检查每一行,并在发现不一致时手工更正。不过,有一种更有效的方法可以做到这一点!
# 获取“countries”列中的所有唯一值
countries = professors['Country'].unique()
# 按字母顺序排序,然后仔细查看
countries.sort()
countries
只要看看这一点,我就可以看到由于数据输入不一致而产生的一些问题:“德国”和“德国”,或者“新西兰”和“新西兰”。
我要做的第一件事是将所有内容都简化为小写(如果愿意,我可以在末尾将其改回),并删除单元格开头和结尾的所有空白。大写和尾随空格的不一致在文本数据中非常常见,通过这样做,您可以修复80%的文本数据输入不一致。
# 转换成小写
professors['Country'] = professors['Country'].str.lower()
# 删除尾随空格
professors['Country'] = professors['Country'].str.strip()
接下来,我们将处理更困难的不一致性。
使用模糊匹配纠正不一致的数据输入
好的,让我们再看一看“国家”栏,看看我们是否还需要进行更多的数据清理。
# 获取“countries”列中的所有唯一值
countries = professors['Country'].unique()
# 按字母顺序排序,然后仔细查看
countries.sort()
countries
看起来确实存在另一个不一致之处:“southkorea”和“south korea”应该是一样的。
我们将使用fuzzyfuzzy包来帮助识别哪些字符串彼此最接近。这个数据集足够小,我们可能可以手动更正错误,但这种方法不能很好地扩展(你想手工改正一千个错误吗?一万怎么样?尽早实现自动化通常是个好主意。另外,这很有趣!)
模糊匹配:自动查找与目标字符串非常相似的文本字符串的过程。一般来说,一个字符串被认为与另一个字符串“更接近”,即在将一个字符串转换为另一个字符串时需要更改的字符数越少。因此,“apple”和“snapple”是两个彼此不同的变化(添加“s”和“n”),而“in”和“on”则是一个变化(用“o”替换“i”)。你不可能总是100%依赖模糊匹配,但它通常会为你节省至少一点时间。
fuzzyfuzzy返回给定两个字符串的比率。比率越接近100,两个字符串之间的编辑距离越小。在这里,我们将从我们的城市列表中获得与“迪可汗”距离最近的十个字符串。
# 获取最接近的前10个匹配项"south korea"
matches = fuzzywuzzy.process.extract("south korea", countries, limit=10, scorer=fuzzywuzzy.fuzz.token_sort_ratio)
# 看看他们
matches
我们可以看到,城市中有两个项目与“south korea”非常接近:“south korea”和“southkorea国”。让我们将“国家”列中比率>47的所有行替换为“韩国”。
为此,我将编写一个函数(编写一个通用函数是一个好主意,如果您认为您可能需要多次执行特定任务,那么您可以重用该函数。这使您不必过于频繁地复制和粘贴代码,从而节省时间并有助于防止错误。)
# 函数替换所提供数据帧的所提供列中的行
# 将高于提供比率的提供字符串与提供的字符串匹配
def replace_matches_in_column(df, column, string_to_match, min_ratio = 47):
# 获取唯一字符串的列表
strings = df[column].unique()
# 获取与输入字符串最接近的前10个匹配项
matches = fuzzywuzzy.process.extract(string_to_match, strings,
limit=10, scorer=fuzzywuzzy.fuzz.token_sort_ratio)
# 仅获取比率>90的匹配项
close_matches = [matches[0] for matches in matches if matches[1] >= min_ratio]
# 获取数据帧中所有紧密匹配的行
rows_with_matches = df[column].isin(close_matches)
# 将所有行替换为输入匹配的紧密匹配
df.loc[rows_with_matches, column] = string_to_match
# 让我们知道功能已经完成
print("All done!")
现在我们有了一个函数,我们可以对它进行测试了!
# 使用我们刚刚编写的函数,将与“south korea”的匹配项替换为“with "south korea”
replace_matches_in_column(df=professors, column='Country', string_to_match="south korea")
现在让我们再次检查“国家”栏中的独特值,确保我们正确地整理了“south korea”。
# 获取“国家”列中的所有唯一值
countries = professors['Country'].unique()
# 按字母顺序排序,然后仔细查看
countries.sort()
countries
杰出的现在我们的数据框中只有“south korea”,我们不需要手动更改任何内容。