原文:Manipulating and Visualizing Data
译者:飞龙
我们已经学习了加载文件的基础知识,现在是时候将加载的数据,从 NumPy 和 Pandas 重新组织为常用的数据结构了。 为了产生各种数据结构,我们将把它们提供给 matplotlib 进行可视化。 然后,本实验将全面介绍我们的通用数据科学规划模板中的第 2,3 和 5 步:
- 获取数据,这意味着找到合适的文件,或从 Web 收集数据并存储在文件中
- 从磁盘加载数据并放入组织成数据结构的内存
- 规范化,清理或以其他方式准备数据
- 处理数据,这可能意味着训练机器学习模型,计算摘要统计量或优化成本函数
- 输出结果,可以是简单地将答案保存到磁盘上,也可以生成奇特的可视化
您将在机器学习,时间序列分析等课程中了解第 4 步的更多信息。
让我们开始导入我们需要的所有软件包,并设置一些参数,使这个 Jupyter 笔记本看起来更好:
import pandas
import numpy as np
import matplotlib.pyplot as plt
pandas.options.display.max_rows = 7 # Don't display too much data (Pandas)
np.set_printoptions(threshold=4) # Don't display too much data (NumPy)
分析程序倾向于使用大量的一维和二维数组。2D 数组是矩阵和数据表。1D 数组是向量,例如欧几里德空间中的点。表的列或行也是一维数组。 Python 有列表和列表的列表,可以满足 1D 和 2D 数组,但 Pandas 和 NumPy 定义了类似但功能更强的数据结构。
让我们从 Pandas 数据帧开始,它们是非常像 Excel 表的强大表格。 我还认为 Pandas 的read_csv()
是加载组织成行和列的大多数数据的最简单方法。 这是一个示例数据文件,包含一段时间内的价格列表,每行一个数据点且没有标题行:
! wc data/prices.txt
! head data/prices.txt
'''
345 345 2067 data/prices.txt
0.605
0.600
0.594
0.592
0.600
0.616
0.623
0.628
0.630
0.629
'''
(wc
和head
是 bash 命令,你可能会发现它们将来很有用。)
以下是使用 Pandas 加载该文件的方法:
prices = pandas.read_csv('data/prices.txt', header=None)
prices # jupyter notebooks know how to display this nicely
0 | |
---|---|
0 | 0.605 |
1 | 0.600 |
2 | 0.594 |
... | ... |
342 | 1.939 |
343 | 1.898 |
344 | 1.891 |
345 rows × 1 columns
左栏中的数字只是索引,是 Pandas 会显示给您的信息;它们不作为数据结构的一部分存储在内存中。 我们来看看这个数据结构的类型和形状:
print "type is", type(prices)
print "shape is", prices.shape
'''
type is <class 'pandas.core.frame.DataFrame'>
shape is (345, 1)
'''
该输出表明,数据存储在DataFrame
对象中,并且有 344 行和 1 列。
虽然 Pandas 非常适合加载数据,而我们将在下面看到其他一些内容,但我更喜欢使用 NumPy 数组;实际的类型称为ndarray
。让我们将价格列表从数据帧转换为 NumPy 数组:
m = prices.as_matrix() # Convert data frame to numpy array
print "type is", type(m)
print "shape is", m.shape
print m
'''
type is <type 'numpy.ndarray'>
shape is (345, 1)
[[ 0.605]
[ 0.6 ]
[ 0.594]
...,
[ 1.939]
[ 1.898]
[ 1.891]]
'''
打印的数组看起来像列表的列表,但它是不同的数据类型。 仅仅因为两个数据结构以相同的方式打印出来,并不意味着它们是相同类型的对象。
我们可以使用数组索引表示法array[row, column]
访问 2D NumPy 数组:
print m[0] # Access the first row
print m[0,0] # Access the first column of the first row
print m[1] # Access the 2nd row
print m[1,0] # Access the first column of the 2nd row
'''
[ 0.605]
0.605
[ 0.6]
0.6
'''
虽然这有点奇怪。 我们将其视为一维数组或仅仅是一个列表,而不是具有单列的二维数组(形状为 345 x 1)。 为了让 NumPy 将其视为 1D,我们使用数组的shape
属性:
m.shape = (345,) # len(m)==345
m
# array([ 0.605, 0.6 , 0.594, ..., 1.939, 1.898, 1.891])
现在,我们可以像我们期望的那样使用单个索引访问元素:
print m[0]
print m[1]
print m[2]
'''
0.605
0.6
0.594
'''
第二个参数为空的形状表示 1D 数组,这是 NumPy 将常规 Python 列表转换为数组的方式:
sizes = [28, 32, 34, 36, 38, 39, 40, 41] # Plain old Python list
a = np.array(sizes) # Convert to NumPy array
print "shape is", a.shape
a
'''
shape is (8,)
array([28, 32, 34, ..., 39, 40, 41])
'''
虽然我们在这里,但这里是将列表的列表转换为 2D NumPy 数组的方式:
stuff = [
[ 18, 8, 307, 3504],
[ 15, 8, 350, 3693],
[ 18, 8, 318, 3436]
]
m = np.array(stuff)
print "shape is", m.shape
m
'''
shape is (3, 4)
array([[ 18, 8, 307, 3504],
[ 15, 8, 350, 3693],
[ 18, 8, 318, 3436]])
'''
现在多个索引是有意义的。 例如,要访问包含值 3436 的元素,我们使用m[2,3]
(第 3 行,第 4 列)。
TODO:展示x + y
可以是字符串,int
,float
,list
或 numpy 数组。 重载运算符。例如,如果x
是字符串且y
是int
,则x * y
可以是字符串
import numpy as np
def f(x):
"Scalar or vector math!"
return np.cos(3 * np.pi * x) / x
print f(3.4)
X = np.array([1.2,3.0]) # a numpy array is more flexible than list of numbers
print f(X) # returns array due to vector math in f()!
print [f(x) for x in X] # manually apply f() to X
'''
0.237946174816
[ 0.25751416 -0.33333333]
[0.25751416197912252, -0.33333333333333331]
'''
我们的价格列表表示时间序列数据,例如股票价格,温度或人口波动。Matplotlib 是一个很好的数据可视化库,在本节中我们将使用它的plot()
,将价格显示为时间序列。 该函数接受单独的数组X
和Y
坐标。
我发现 Matplotlib 有点神秘,但我学会了一遍又一遍地使用的模式,比如这个时间序列的绘图。
m = prices.as_matrix() # Let's convert pandas data frame to numpy array
time = np.arange(0, len(m), 1) # Time axis goes from 0 to len(m) by 1
#plt.figure(figsize=(5, 2)) # Prepare a plot 5x2 inches
plt.plot(time, m) # Plot time vs the prices data
plt.xlabel("Time") # Always set the axes labels
plt.ylabel("Price (dollars)")
plt.show() # Show the actual plot
绘制函数
有时我们有一个平滑的函数,比如我们想绘制的余弦。为此,我们需要定期采样函数,来收集Y
坐标列表(如之前的价格)。让我们首先定义将X
坐标映射到Y
值的函数,然后以 0.1 到 1.1 之间,步长 0.01 的固定间隔获取X
值的样本:
def f(x):
return np.cos(3 * np.pi * x) / x
X = np.arange(.1, 1.1, 0.01) # from .1 to 1.1 by step 0.01
有三种方法可以在X
中包含的坐标处,采样函数f()
,我在这里已经描述过了。 所有这三种方法都使用我们的映射模式:
# Get f(x) values for all x in three different ways
# Option 1: (non-Pythonic)
Y = []
for x in X:
Y.append(f(x))
# Option 2: Pythonic way (cool kids do this)
Y = [f(x) for x in X]
# Option 3: Data science way (the most popular kids do this)
Y = f(X) # a so-called broadcast; implied map
print X
print Y
'''
[ 0.1 0.11 0.12 ..., 1.07 1.08 1.09]
[ 5.87785252 4.62764923 3.54816076 ..., -0.73846263 -0.67497095
-0.60670813]
'''
给定X
和Y
坐标,我们可以绘制函数:
plt.figure(figsize=(5, 2))
plt.plot(X, Y)
plt.xlabel("x")
plt.ylabel("cos(3 * pi * x) / x")
plt.show()
让我们现在超越一维数组到二维数组并绘制一列与另一列。以下是一些样本汽车数据(带标题行),带有每加仑英里数,汽缸数,发动机马力和重量(磅)的列:
! head data/cars.csv
'''
MPG,CYL,ENG,WGT
18,8,307,3504
15,8,350,3693
18,8,318,3436
16,8,304,3433
17,8,302,3449
15,8,429,4341
14,8,454,4354
14,8,440,4312
14,8,455,4425
'''
我们可以再次使用 Pandas 将数据加载到数据帧中,然后转换为 NumPy 2D 数组(矩阵):
cars = pandas.read_csv('data/cars.csv')
print "shape is", cars.shape
cars
# shape is (392, 4)
MPG | CYL | ENG | WGT | |
---|---|---|---|---|
0 | 18.0 | 8 | 307.0 | 3504 |
1 | 15.0 | 8 | 350.0 | 3693 |
2 | 18.0 | 8 | 318.0 | 3436 |
... | ... | ... | ... | ... |
389 | 32.0 | 4 | 135.0 | 2295 |
390 | 28.0 | 4 | 120.0 | 2625 |
391 | 31.0 | 4 | 119.0 | 2720 |
392 rows × 4 columns
m = cars.as_matrix()
print "shape is", m.shape
m
'''
shape is (392, 4)
array([[ 18., 8., 307., 3504.],
[ 15., 8., 350., 3693.],
[ 18., 8., 318., 3436.],
...,
[ 32., 4., 135., 2295.],
[ 28., 4., 120., 2625.],
[ 31., 4., 119., 2720.]])
'''
假设我们对汽车重量和燃油效率之间的关系感兴趣。 我们可以通过使用散点图绘制重量与效率来直观地检查这种关系。
这就引出了如何从 numpy 数组中提取列的问题,其中每列代表与所有汽车的一个属性关联的数据。 想法是固定列号,但使用通配符(冒号字符)表示我们想要所有行:
# can do this:
print cars.MPG
print cars['MPG']
# but I like as numpy matrix
mpg = m[:,0]
wgt = m[:,3]
print "shape is", mpg.shape
mpg
'''
0 18.0
1 15.0
2 18.0
...
389 32.0
390 28.0
391 31.0
Name: MPG, dtype: float64
0 18.0
1 15.0
2 18.0
...
389 32.0
390 28.0
391 31.0
Name: MPG, dtype: float64
shape is (392,)
array([ 18., 15., 18., ..., 32., 28., 31.])
'''
一旦我们有了两列,我们就可以使用 matplotlib 的scatter()
函数:
plt.figure(figsize=(5, 2))
plt.scatter(wgt, mpg, alpha=0.5) # looks cooler with alpha (opacity) at 50%
plt.xlabel('Weight (pounds)')
plt.ylabel('Miles per gallon')
plt.show()
很棒!这显示了重量和效率之间的明确关系:汽车越重,效率越低。
了解发动机汽缸的数量与重量和效率有何关系也很有趣。 我们可以转到三维图形甚至多个图形,但在这种情况下最好将另一个属性添加到单个图形中。我们可以根据气缸数改变颜色,但更好的可视化会改变所绘制点的大小。
我们可以像以前一样用m[:,1]
获取气缸的数量,但我们现在需要单独绘制每个点,因为我们必须指定不同的尺寸。 这意味着我们需要一个循环在scatter()
周围,来传递单独的X
和Y
坐标而不是列表。 scatter()
的s
参数实际上与我们想要的圆的面积成正比(参见 pyplot 散点图的标记大小)。 为了突出引擎尺寸之间的差异,我按比例 .7 缩放。以下是用于说明三个变量之间关系的代码:
plt.figure(figsize=(5, 2))
hp = m[:,2]
plt.scatter(wgt, mpg, s=hp*.5, alpha=0.1)
plt.xlabel('Weight (pounds)')
plt.ylabel('Miles per gallon')
plt.show()
在探索数据时,了解唯一值的集合通常很有用。例如,如果想知道气缸数的集合,我们可以使用set(mylist)
:
m = cars.as_matrix()
cyl = m[:,1]
print set(cyl)
有趣。 我不知道有 3 个汽缸的汽车。
练习:使用映射模式将cyl
转换为整数集合(不是浮点值)。 提示:int(3.0)
为 3。
我们可以计算每个唯一值中有多少出现在数据集中,而不仅仅是属性值的唯一集合。 Python 的Counter
对象,一种dict
,知道如何计算元素。 例如,以下是我们如何获得类似字典的对象,将气缸数映射到具有多个气缸的汽车数量:
from collections import Counter
m = cars.as_matrix()
cyl = m[:,1]
Counter(cyl)
# Counter({3.0: 4, 4.0: 199, 5.0: 3, 6.0: 83, 8.0: 103})
这对于类别变量非常有用,类别变量的种类数是这样,但是“计数器”不适合数值。 此外,观察气缸计数,很难快速了解相关的总体。 用直方图可视化数据是一个更好的想法,也适用于数值。 以下是为气缸属性制作直方图的代码:
plt.figure(figsize=(5, 2))
plt.hist(cyl, alpha=0.5)
plt.xlabel('Number of cylinders')
plt.ylabel('Number of cars')
plt.show()
相同的模式也为我们提供了数值数据的直方图:
m = cars.as_matrix()
hp = m[:,2]
plt.figure(figsize=(5, 2))
plt.hist(hp, alpha=0.5)
plt.xlabel('Horsepower')
plt.ylabel('Number of cars')
plt.show()
直方图实际上是变量密度函数的粗略估计,因此将直方图标准化来使区域积分(总和)为 1,通常很有用。要获得标准化的直方图,请使用参数normed=True
:
plt.figure(figsize=(5, 2))
n, bins, patches = plt.hist(hp, normed=True, alpha=0.5)
plt.xlabel('Horsepower')
plt.ylabel('Probability')
plt.show()
请注意,桶的高度之和不等于 1;高度乘以宽度之和等于 1。
到目前为止,我们加载的所有数据都是数字的,但以字符串的形式加载分类或文本变量是很常见的。在这种情况下,Pandas 数据帧非常有用。 让我们加载一些示例销售数据,包含三个字符串列:
sales = pandas.read_csv('data/sales-small.csv')
sales
Date | Quantity | Unit Price | Shipping | Customer Name | Product Category | Product Name | |
---|---|---|---|---|---|---|---|
0 | 10/13/10 | 6 | 38.94 | 35.00 | Muhammed MacIntyre | Office Supplies | Eldon Base for stackable storage shelf, platinum |
1 | 10/1/12 | 49 | 208.16 | 68.02 | Barry French | Office Supplies | 1.7 Cubic Foot Compact "Cube" Office Refrigera... |
2 | 10/1/12 | 27 | 8.69 | 2.99 | Barry French | Office Supplies | Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl |
... | ... | ... | ... | ... | ... | ... | ... |
28 | 11/8/10 | 28 | 13.48 | 4.51 | Carlos Soltero | Office Supplies | Tenex Personal Project File with Scoop Front D... |
29 | 10/21/12 | 49 | 6.08 | 1.17 | Grant Carroll | Office Supplies | Col-Erase Pencils with Erasers |
30 | 1/1/11 | 10 | 5.98 | 4.38 | Don Miller | Technology | Imation 3.5" DS/HD IBM Formatted Diskettes, 10... |
31 rows × 7 columns
数据帧的好处是我们可以使用table.attribute
或数组索引表示法table[attribute ]
来按名称访问列。
sales.Date
'''
0 10/13/10
1 10/1/12
2 10/1/12
...
28 11/8/10
29 10/21/12
30 1/1/11
Name: Date, dtype: object
'''
sales['Date']
'''
0 10/13/10
1 10/1/12
2 10/1/12
...
28 11/8/10
29 10/21/12
30 1/1/11
Name: Date, dtype: object
'''
sales['Customer Name']
'''
0 Muhammed MacIntyre
1 Barry French
2 Barry French
...
28 Carlos Soltero
29 Grant Carroll
30 Don Miller
Name: Customer Name, dtype: object
'''
通过sales [0]
访问行不起作用,因为 Pandas 希望使用数组索引表示法来获取列。 相反,我们必须使用稍微麻烦的表示法:
sales.iloc[0] # get first row of data
'''
Date 10/13/10
Quantity 6
Unit Price 38.94
Shipping 35
Customer Name Muhammed MacIntyre
Product Category Office Supplies
Product Name Eldon Base for stackable storage shelf, platinum
Name: 0, dtype: object
'''
为了获得单个元素,我们可以在loc
之后使用常规的 Python 表示法,用于列表的列表:
print sales.iloc[0][0], sales.iloc[0][1], sales.iloc[0][2]
# 10/13/10 6 38.94
在软件的构建和调试过程中,我经常喜欢显式打印列名,如上所示。 另一方面,如果我们需要将元素转换为普通的 Python 列表,我们可以使用list()
来实现:
row = list(sales.iloc[0])
print row
# ['10/13/10', 6, 38.939999999999998, 35.0, 'Muhammed MacIntyre', 'Office Supplies', 'Eldon Base for stackable storage shelf, platinum']
练习:将sales
的所有行转换为列表的列表。 提示:使用映射模式和list()
。
这项工作的任务很普遍,Pandas 直接提供了一种转换机制:
m = sales.as_matrix()
print "Type is", type(m)
print m[0] # get first row
'''
Type is <type 'numpy.ndarray'>
['10/13/10' 6 38.94 ..., 'Muhammed MacIntyre' 'Office Supplies'
'Eldon Base for stackable storage shelf, platinum']
'''
我们仍然可以使用之前看到的切片表示,来单独获取列:
m[:,0] # get first column
'''
array(['10/13/10', '10/1/12', '10/1/12', ..., '11/8/10', '10/21/12',
'1/1/11'], dtype=object)
'''
m[:,4] # get fifth column
'''
array(['Muhammed MacIntyre', 'Barry French', 'Barry French', ...,
'Carlos Soltero', 'Grant Carroll', 'Don Miller'], dtype=object)
'''
对于机器学习,我们经常希望将其中一列作为因变量分开,将其他列保持为一组独立变量。 我们通常使用的符号是X - > Y
,意味着X
中的观察集将结果预测或分类为Y
.
例如,假设我们想要根据效率,汽缸数量和整车重量来预测发动机尺寸。我们需要将引擎大小分离为Y
并将其他列组合成X
。使用 Pandas,我们可以轻松地分离变量并保留变量名称:
cars = pandas.read_csv('data/cars.csv')
Y = cars['ENG']
X = cars[['MPG','CYL','WGT']]
print X
print
print Y
'''
MPG CYL WGT
0 18.0 8 3504
1 15.0 8 3693
2 18.0 8 3436
.. ... ... ...
389 32.0 4 2295
390 28.0 4 2625
391 31.0 4 2720
[392 rows x 3 columns]
0 307.0
1 350.0
2 318.0
...
389 135.0
390 120.0
391 119.0
Name: ENG, dtype: float64
'''
转换为 NumPy 数组会删除列名称,但让我们将其视为矩阵,这在很多情况下都很方便(例如,矩阵加法)。从 NumPy 数组中分离列有点麻烦,但是:
m = cars.as_matrix()
Y = m[:,2]
X = np.column_stack((m[:,0],m[:,1], m[:,3])) # note extra parens; it's a tuple of columns
print X
print
print Y
'''
[[ 18. 8. 3504.]
[ 15. 8. 3693.]
[ 18. 8. 3436.]
...,
[ 32. 4. 2295.]
[ 28. 4. 2625.]
[ 31. 4. 2720.]]
[ 307. 350. 318. ..., 135. 120. 119.]
'''
虽然 NumPy 数组在拆分表时更麻烦,但不用loc
访问元素通常更方便:
print cars.iloc[0][1]
print m[0,1]
'''
8.0
8.0
'''
使用来自 Jeremy Howard 的提示,有关真实世界的数据清理。
import pandas
df = pandas.read_csv("data/mixed.csv", parse_dates=['Date'])
df
Date | Description | Size | Price | Topic | |
---|---|---|---|---|---|
0 | 2017-06-20 | NaN | 92.0 | 1.50 | News |
1 | 2017-06-21 | run forest | 42.0 | 2.34 | Sports |
2 | 2017-06-21 | not your droids | 19.0 | 0.88 | Sports |
3 | 2017-06-22 | hi mom | NaN | 9.30 | Politics |
4 | 2017-06-23 | foo&bar | 1.0 | 10.00 | NaN |
5 | 2017-06-24 | get off my lawn | 99.0 | 8.90 | Sci |
如果您需要将日期转换为已用时间,则可以将日期时间戳转换为 UNIX 时间,即自 1970 年以来的秒数:
d = df['Date']
delta = d - pandas.datetime(1970,1,1)
delta
'''
0 17337 days
1 17338 days
2 17338 days
3 17339 days
4 17340 days
5 17341 days
Name: Date, dtype: timedelta64[ns]
'''
df3 = df.copy()
df3['Date'] = delta.dt.total_seconds()
df3
Date | Description | Size | Price | Topic | Size_na | |
---|---|---|---|---|---|---|
0 | 1.497917e+09 | NaN | 92.0 | 1.50 | 2 | False |
1 | 1.498003e+09 | run forest | 42.0 | 2.34 | 5 | False |
2 | 1.498003e+09 | not your droids | 19.0 | 0.88 | 5 | False |
3 | 1.498090e+09 | hi mom | 42.0 | 9.30 | 3 | True |
4 | 1.498176e+09 | foo&bar | 1.0 | 10.00 | 1 | False |
5 | 1.498262e+09 | get off my lawn | 99.0 | 8.90 | 4 | False |
或者,您可以将时间戳转换为自 1970 年以来的天数:
delta.dt.days
'''
0 17337
1 17338
2 17338
3 17339
4 17340
5 17341
Name: Date, dtype: int64
'''
以下是我们将列转换为类别变量的方法:
df['Topic'] = df['Topic'].astype('category')
df
Date | Description | Size | Price | Topic | |
---|---|---|---|---|---|
0 | 2017-06-20 | NaN | 92.0 | 1.50 | News |
1 | 2017-06-21 | run forest | 42.0 | 2.34 | Sports |
2 | 2017-06-21 | not your droids | 19.0 | 0.88 | Sports |
3 | 2017-06-22 | hi mom | NaN | 9.30 | Politics |
4 | 2017-06-23 | foo&bar | 1.0 | 10.00 | NaN |
5 | 2017-06-24 | get off my lawn | 99.0 | 8.90 | Sci |
print df['Topic'].cat.categories # .cat field gives us access to categories stuff
# Index([u'News', u'Politics', u'Sci', u'Sports'], dtype='object')
print df['Topic'].cat.codes
'''
0 0
1 3
2 3
3 1
4 -1
5 2
dtype: int8
'''
print df['Topic'].cat.as_ordered()
'''
0 News
1 Sports
2 Sports
3 Politics
4 NaN
5 Sci
dtype: category
Categories (4, object): [News < Politics < Sci < Sports]
'''
如果我们愿意,我们可以将该类别转换为整数:
# make sure you convert to categorical first
df['Topic'] = df['Topic'].astype('category')
df['Topic'] = df['Topic'].cat.codes+1 # add one so NA (-1) becomes 0
df
Date | Description | Size | Price | Topic | Size_na | |
---|---|---|---|---|---|---|
0 | 2017-06-20 | NaN | 92.0 | 1.50 | 2 | False |
1 | 2017-06-21 | run forest | 42.0 | 2.34 | 5 | False |
2 | 2017-06-21 | not your droids | 19.0 | 0.88 | 5 | False |
3 | 2017-06-22 | hi mom | 42.0 | 9.30 | 3 | True |
4 | 2017-06-23 | foo&bar | 1.0 | 10.00 | 1 | False |
5 | 2017-06-24 | get off my lawn | 99.0 | 8.90 | 4 | False |
我们的数据缺少描述,我们可以忽略,但也缺少大小(数值)和主题(类别)条目。
*如果元素是数字,我们用列中位数替换缺失值,并添加一列 0 或 1 来表示是否缺少值。
*如果元素是分类的,当我们在get_dummies()
上使用参数dummy_na = True
时,Pandas 可以自动处理缺失值(参见下一节)。
让我们转换丢失的数值数据:
pandas.isnull(df['Size'])
'''
0 False
1 False
2 False
3 True
4 False
5 False
Name: Size, dtype: bool
'''
df['Size_na'] = pandas.isnull(df['Size'])
df
Date | Description | Size | Price | Topic | Size_na | |
---|---|---|---|---|---|---|
0 | 2017-06-20 | NaN | 92.0 | 1.50 | 1 | False |
1 | 2017-06-21 | run forest | 42.0 | 2.34 | 4 | False |
2 | 2017-06-21 | not your droids | 19.0 | 0.88 | 4 | False |
3 | 2017-06-22 | hi mom | NaN | 9.30 | 2 | True |
4 | 2017-06-23 | foo&bar | 1.0 | 10.00 | 0 | False |
5 | 2017-06-24 | get off my lawn | 99.0 | 8.90 | 3 | False |
szcol = df['Size']
df['Size'] = szcol.fillna(szcol.median())
df
Date | Description | Size | Price | Topic | Size_na | |
---|---|---|---|---|---|---|
0 | 2017-06-20 | NaN | 92.0 | 1.50 | 1 | False |
1 | 2017-06-21 | run forest | 42.0 | 2.34 | 4 | False |
2 | 2017-06-21 | not your droids | 19.0 | 0.88 | 4 | False |
3 | 2017-06-22 | hi mom | 42.0 | 9.30 | 2 | True |
4 | 2017-06-23 | foo&bar | 1.0 | 10.00 | 0 | False |
5 | 2017-06-24 | get off my lawn | 99.0 | 8.90 | 3 | False |
相反,我们可以将类别变量转换为虚拟变量,也称为“独热编码”。
如果我们懒惰,我们可以将所有内容转换为虚拟对象,但是Description
字段不是我们需要转换的内容,因为它主要是我们所携带的信息。
pandas.get_dummies(df) # convert all categorical to dummies
Date | Size | Price | Topic | Size_na | Description_foo&bar | Description_get off my lawn | Description_hi mom | Description_not your droids | Description_run forest | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 2017-06-20 | 92.0 | 1.50 | 1 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1 | 2017-06-21 | 42.0 | 2.34 | 4 | False | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
2 | 2017-06-21 | 19.0 | 0.88 | 4 | False | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
3 | 2017-06-22 | 42.0 | 9.30 | 2 | True | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
4 | 2017-06-23 | 1.0 | 10.00 | 0 | False | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 | 2017-06-24 | 99.0 | 8.90 | 3 | False | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
pandas.get_dummies(df['Topic']) # One column's dummies
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
1 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
2 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
3 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
4 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
pandas.get_dummies(df['Topic'], dummy_na=True) # Add an "na" column
0.0 | 1.0 | 2.0 | 3.0 | 4.0 | nan | |
---|---|---|---|---|---|---|
0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
2 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
3 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
4 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
我们可以手动将这些新列打包到旧数据帧中并删除旧列:
df2 = pandas.concat([df,pandas.get_dummies(df['Topic'], dummy_na=True)], axis=1)
df2.drop('Topic', axis=1, inplace=True) # Considered better than del df2['Topic'] I think
df2
Date | Description | Size | Price | Size_na | 1.0 | 2.0 | 3.0 | 4.0 | 5.0 | nan | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2017-06-20 | NaN | 92.0 | 1.50 | False | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1 | 2017-06-21 | run forest | 42.0 | 2.34 | False | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
2 | 2017-06-21 | not your droids | 19.0 | 0.88 | False | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
3 | 2017-06-22 | hi mom | 42.0 | 9.30 | True | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
4 | 2017-06-23 | foo&bar | 1.0 | 10.00 | False | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 | 2017-06-24 | get off my lawn | 99.0 | 8.90 | False | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
或者,我们可以通过指定要转换的列来轻松实现:
pandas.get_dummies(df, columns=['Topic'], dummy_na=True) # The easy way
Date | Description | Size | Price | Size_na | Topic_0.0 | Topic_1.0 | Topic_2.0 | Topic_3.0 | Topic_4.0 | Topic_nan | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2017-06-20 | NaN | 92.0 | 1.50 | False | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1 | 2017-06-21 | run forest | 42.0 | 2.34 | False | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
2 | 2017-06-21 | not your droids | 19.0 | 0.88 | False | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
3 | 2017-06-22 | hi mom | 42.0 | 9.30 | True | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
4 | 2017-06-23 | foo&bar | 1.0 | 10.00 | False | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 | 2017-06-24 | get off my lawn | 99.0 | 8.90 | False | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
如果您需要遍历数据帧中的列,则可以使用for
循环执行此操作:
# walk columns; col is the actual series
for name,col in df.iteritems():
print name
'''
Date
Description
Size
Price
Topic
Size_na
'''
df.describe() # useful stats about columns
Size | Price | Topic | |
---|---|---|---|
count | 6.000000 | 6.000000 | 6.000000 |
mean | 49.166667 | 5.486667 | 3.333333 |
std | 39.117345 | 4.326175 | 1.632993 |
... | ... | ... | ... |
50% | 42.000000 | 5.620000 | 3.500000 |
75% | 79.500000 | 9.200000 | 4.750000 |
max | 99.000000 | 10.000000 | 5.000000 |
8 rows × 3 columns
在本讲座中,您已经学习了加载和操作数据的基础知识:
- 使用
read_csv()
将数据加载到 Pandas 数据帧中 - 使用
as_matrix()
将数据帧转换为 NumPy 数组 - 使用
dataframe.columnname
或matrix[:, columnindex]
提取列 - 使用
dataframe.iloc[rowindex][columnindex]
或matrix[rowindex, columnindex]
访问元素 - 使用
set(mylist)
获取唯一元素
而且,您已经学会了如何可视化:
- 时间序列数据
- 超出给定范围的函数
- 使用散点图绘制变量之间的关系
- 近似密度函数的直方图