干货:4个小技巧助你搞定缺失、混乱的数据(附实例代码)

640?wx_fmt=gif

导读:数据工作者经常会遇到各种状况,比如你收集到的数据并不像你期待的那样完整、干净。此前我们讲解了用OpenRefine搞定数据清洗,本文进一步探讨用pandas和NumPy插补缺失数据并将数据规范化、标准化。

 

作者:托马兹·卓巴斯(Tomasz Drabas)

如需转载请联系大数据(ID:hzdashuju)

 

本文将使用一个数据集,包含985项真实的房产交易。这些交易是连续5天内在Sacramento发生的。数据下载自:

 

http://samplecsvs.s3.amazonaws.com/Sacramentorealestatetransactions.csv

 

数据已转成多种格式,放在GitHub代码库的Data/Chapter01文件夹中。

 

https://github.com/drabastomek/practicalDataAnalysisCookbook.git

 

 

01 插补缺失值

 

数据的收集工作很棘手。收集工具坏了,调查问卷上某些问题人们不想回答,或者文件被损坏了;这些还只是数据集可能不全的一小部分原因。如果想使用这个数据集,我们有两个选择:忽略缺失的数据,或者用一些值替代。

 

1. 准备

 

要实践本技巧,你要先装好pandas模块。

 

2. 怎么做

 

csv_read DataFrame可供使用。要插补缺失值,你只需要使用下面的代码(data_imput.py文件):

 

 

# 估算平均数以替代空值
csv_read['price_mean'] = csv_read['price'] \
.fillna(
csv_read.groupby('zip')['price'].transform('mean')
)

 

3. 原理

 

pandas的.fillna(...)方法帮我们处理了所有重活。这是DataFrame对象的一个方法,将要估算的值作为唯一必须传入的参数。

 

查阅pandas文档中.fillna(...)的部分,了解可传入的其他参数。文档位于:

 

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.fillna.html

 

在我们的处理过程中,我们假设每个邮编可能会有不同的均价。这就是我们用.groupby(...)方法对数据分组的原因。房产的价格重度依赖于房间的数目,这个推论也是成立的;如果我们的数据集更大,我们还能考虑beds这个变量。

 

.groupby(...)方法返回一个GroupBy对象。其.transform(...)方法高效地对邮编分组,在我们的例子中,分组的依据是各邮编价格数据的平均数。

 

现在,.fillna(...)方法简单地用这个平均数替代缺失的观测数据即可。

 

4. 更多

 

插补数据不是填补缺失值的唯一方法。数据对称分布且没有异常值时,才会返回一个合理的值;如果分布比较偏,平均值是有偏差的。衡量集中趋势更好的维度是中位数。我们前面的例子只需要改一个小地方:

 

 

# 估算中位数以替代空值
csv_read['price_median'] = csv_read['price'] \
.fillna(
csv_read.groupby('zip')['price'].transform('median')
)

 

 

02 将特征规范化、标准化

 

为了提高计算效率,我们将特征规范化(或标准化),这样不会超出计算机的限制。探索模型中变量之间的相互作用时也建议这么处理。

 

计算机是有限制的:整型值是有上限的(尽管目前在64位机器上这不是个问题),浮点型的精确度也有上限。

 

数据规范化是让所有的值落在0到1的范围内(闭区间)。数据标准化是移动其分布,使得数据的平均数是0、标准差是1。

 

1. 准备

 

要实践本技巧,你要先装好pandas模块。

 

其他没有什么要准备的了。

 

2. 怎么做

 

要实现规范化与标准化,我们定义了两个辅助函数(data_standardize.py文件):

 

 

def normalize(col):
'''
规范化
'''

return (col - col.min()) / (col.max() - col.min())
def standardize(col):
'''
标准化
'''

return (col - col.mean()) / col.std()

 

3. 原理

 

要规范化数据,即让每个值都落在0和1之间,我们减去数据的最小值,并除以样本的范围。统计学上的范围指的是最大值与最小值的差。normalize(...)方法就是做的前面描述的工作:对数据的集合,减去最小值,除以范围。

 

标准化的过程类似:减去平均数,除以样本的标准差。这样,处理后的数据,平均数为0而标准差为1。standardize(...)方法做了这些处理:

 

 

csv_read['n_price_mean'] = normalize(csv_read['price_mean'])
csv_read['s_price_mean'] = standardize(csv_read['price_mean'])

 

 

03 分级数据

 

当我们想查看数据分布的形状,或将数据转换为有序的形式时,数据分级就派上用场了。

 

1. 准备

 

要实践本技巧,你要先装好pandas和NumPy模块。

 

2. 怎么做

 

可以用下面的代码(data_binning.py文件)对数据分级(比如处理成直方图):

 

 

# 根据线性划分的价格的范围,创建价格的容器
bins = np.linspace(
csv_read['price_mean'].min(),
csv_read['price_mean'].max(),
6
)
# 将容器应用到数据上
csv_read['b_price'] = np.digitize(
csv_read['price_mean'],
bins
)

 

3. 原理

 

第一步是创建容器。对于价格数据(缺失值用估算的平均数填补),我们创建了六个容器,在最小值和最大值之间均匀分配。.linspace(...)方法做了这点工作:创建长度为6的NumPy数组,其中每个元素比前一个大固定的差值。比如,.linspace(0, 6, 6)生成数组[0., 1.2, 2.4, 3.6, 4.8, 6.]。

 

NumPy对线性代数来说是个强大的数字处理库。可轻松处理大型数组和矩阵,还提供了极其丰富的函数操作数据。想了解更多,可访问:

 

http://www.numpy.org

 

.digitize(...)方法对指定列中的每个值,都返回所属的容器索引。第一个参数是要分级的列,第二个参数是容器的数组。

 

使用DataFrame的.value_counts()得到每个容器中的记录计数,counts_b = csv_read['b_price'].value_counts()。

 

4. 更多

 

有时候我们不会用均匀间隔的值,我们会让每个桶中拥有相同的数目。要达成这个目标,我们可以使用分位数。

 

分位数与百分位数有紧密的联系。区别在于百分位数返回的是给定百分数的值,而分位数返回的是给定分位点的值。想了解更多,可访问:

 

https://www.stat.auckland.ac.nz/~ihaka/787/lectures-quantiles-handouts.pdf

 

我们想把列拆成十分位数,即10个(差不多)相等的容器。要做到这点,我们可以使用下面的代码(你可以一眼看出其和之前方法的相似之处):

 

 

# 根据十分位数创建容器
decile = csv_read['price_mean'].quantile(np.linspace(0111))
# 将容器应用到数据上
csv_read['p_price'] = np.digitize(
csv_read['price_mean'],
decile
)

 

.quantile(...)方法可以传一个(0到1之间的)数字,来表明要返回的分位数(例如,0.5是中位数,0.25和0.75是上下四分位数)。它也可以传入一个分位的列表,返回相应的值的数组。.linspace(0, 1, 11)方法会生成这个数组:

 

 

0.0.10.20.30.40.50.60.70.80.91.]

 

所以,.quantile(...)方法会以price_mean列的最小值开始,直到最大值,返回十分位数的列表。

 

 

04 编码分类变量

 

为数据的探索阶段准备的最后一步就是分类变量了。有些软件包在背后做了这个工作,但最好还是理解这步处理的时机与做法。

 

统计模型只能接受有序的数据。分类变量(有时根据上下文可表示为数字)不能直接在模型中使用。要使用它们,我们要先进行编码,也就是给它们一个唯一的数字编号。这解释了什么时候做。至于如何做—应用下述技巧即可。

 

1. 准备

 

要实践本技巧,你要先装好pandas模块。

 

其他没有什么要准备的了。

 

2. 怎么做

 

pandas又提供了一个方法,帮我们做完所有事(data_dummy_code.py文件):

 

 

# 根据房产类型处理的简单代码
csv_read = pd.get_dummies(
csv_read,
prefix='d',
columns=['type']
)

 

3. 原理

 

.get_dummies(...)方法将分类变量转换为简单的变量。比如,考虑一个变量,以三种水平中的某一种作为值:

 

 

1 One
2 Two
3 Three

 

需要用三列进行编码:

 

 

1 One 1 0 0
2 Two 0 1 0
3 Three 0 0 1

 

有时可用两列。如果有一个水平等效于null的话,我们可以这样做:

 

 

1 One 1 0 
2 Two 0 1 
3 Three 0 0 

 

.get_dummies(...)方法的第一个参数是DataFrame对象。columns参数指定了代码要处理的DataFrame的列(或某些列,因为可以传入列表)。通过指定前缀,我们告诉方法生成的列名以d打头;本例中生成的列会叫d_Condo。下划线是默认的,可以通过指定prefix_sep参数更改。

 

.get_dummies(...)方法的完整参数列表,参见:

 

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.get_dummies.html

 

关于作者:托马兹·卓巴斯(Tomasz Drabas),微软数据科学家,致力于解决高维特征空间的问题。他有超过13年的数据分析和数据科学经验:在欧洲、澳大利亚和北美洲三大洲期间,工作领域遍及高新技术、航空、电信、金融和咨询。

本文摘编自《数据分析实战》,经出版方授权发布。

 

延伸阅读《数据分析实战

点击上图了解及购买

转载请联系微信:togo-maruko

 

推荐语:通过大量的现实案例,详细讲解数据分析相关的各种方法。

 

640?

 

据统计,99%的大咖都完成了这个神操作

 

640?wx_fmt=png

 

更多精彩

 

在公众号后台对话框输入以下关键词

查看更多优质内容!

 

PPT | 报告 | 读书 | 书单

大数据 | 揭秘 | 人工智能 | AI

Python | 机器学习 | 深度学习 | 神经网络

可视化 | 区块链 | 干货 | 数学

 

猜你想看

 

 

 

Q: 你都遇到过哪些不完整的数据?

欢迎留言与大家分享

觉得不错,请把这篇文章分享给你的朋友

转载 / 投稿请联系:baiyu@hzbook.com

更多精彩,请在后台点击“历史文章”查看

640?wx_fmt=jpeg

640?wx_fmt=gif点击阅读原文,了解更多

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

大数据v

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值