文章目录
- 1 入门:Numpy和Pandas
- 2 Numpy
- 入门
- 创建数组
- 数组索引
- 数组切片
- 数组连接
- 3 Pandas
- 分析数据
- 排序
- 删除重复行
- 基于特定列删除重复值
- 分类/新增数据行
- 缺失值处理
- 重命名行列名
- 连续变量分类
- 连续变量分类
- 分组与透视表
- 切片操作
- 布尔索引和条件筛选操作
- 数据透视表的基础操作例子
- 4 机器学习数据处理实例
- 5 总结
在数据科学和机器学习领域,NumPy和Pandas以其高效的数据操作能力和直观的语法设计,为数据计算和分析提供了极大的便利。无论是快速的数组计算,还是灵活的数据表操作,NumPy和Pandas都已成为数据处理工作的必备利器。在学习机器学习前,我们先来看一下这两个知识点。
1 入门:Numpy和Pandas
- Pandas依赖于NumPy
Pandas的强大数据操作能力是建立在NumPy库之上的,可以说NumPy是Pandas的基础。 - Pandas擅长处理表格型数据
Pandas在处理不同变量类型(如整数、浮点数、时间序列数据等)时表现出色,尤其适合进行数据加载、特征工程和时间序列分析等任务。 - NumPy专注于数值计算
NumPy非常适合执行基本的数值运算,例如均值、中位数、范围等。同时,它还支持创建多维数组,为复杂数据结构的操作提供了支持。 - 与其他语言的兼容性
NumPy能够与C/C++和Fortran代码无缝集成,进一步拓展了其在高性能计算领域的应用场景。
2 Numpy
入门
1.检查版本号
import numpy as np
np.__version__
'1.26.4'
2.创建一个从0到9的list
L = list(range(10))
L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
3.转化list为string
[str(c) for c in L]
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
4.获取每个元素的数据类型
[type(item) for item in L]
[int, int, int, int, int, int, int, int, int, int]
创建数组
NumPy数组具有同质性(homogeneous)的特性,也就是说,它们的所有元素必须是相同的数据类型(如整数、浮点数、双精度等),而不像Python的list那样可以包含不同的数据类型。
1.创建全零数组
np.zeros(10, dtype='int')
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
2.创建3×5的矩阵
# 值为1
np.ones((3,5), dtype=float)
array([[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]])
# 自定义值
np.full((3,5),1.23)
array([[ 1.23, 1.23, 1.23, 1.23, 1.23],
[ 1.23, 1.23, 1.23, 1.23, 1.23],
[ 1.23, 1.23, 1.23, 1.23, 1.23]])
3.根据步长创建数组
从 0 开始,每次递增 2,一直到(但不包括)20 的一个一维数组。
np.arange(0, 20, 2)
array([0, 2, 4, 6, 8,10,12,14,16,18])
4.根据元素个数生成数组
从 0 到 1(包含两端点)生成 5 个等间距的数值
np.linspace(0, 1, 5)
array([ 0., 0.25, 0.5 , 0.75, 1.])
5.生成服从正态分布的随机数组
生成一个形状为 3x3 的数组,其元素均从均值为 0、标准差为 1 的正态分布中随机抽取。
np.random.normal(0, 1, (3,3))
array([[ 0.72432142, -0.90024075, 0.27363808],
[ 0.88426129, 1.45096856, -1.03547109],
[-0.42930994, -1.02284441, -1.59753603]])
6.生成单位矩阵
生成一个 3x3 的单位矩阵,其对角线元素为 1,其余元素为 0。
np.eye(3)
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
7.随机数
# 设置随机数种子,使每次运行代码时生成的随机数一致(参数一样随机数就一样)
np.random.seed(0)
# 生成一个一维数组,包含6个随机整数,范围是0到9
x1 = np.random.randint(10, size=6) # 一维数组
# 生成一个二维数组,形状为3x4,每个元素是0到9之间的随机整数
x2 = np.random.randint(10, size=(3, 4)) # 二维数组
# 生成一个三维数组,形状为3x4x5,每个元素是0到9之间的随机整数
x3 = np.random.randint(10, size=(3, 4, 5)) # 三维数组
print("x3 ndim:", x3.ndim) # ndim表示数组的维度数
print("x3 shape:", x3.shape) # shape表示数组每个维度的大小
print("x3 size: ", x3.size) # size表示数组中所有元素的总个数
x3 ndim: 3
x3 shape: (3, 4, 5)
x3 size: 60
数组索引
python中的数组索引也是从0开始的:
x1 = np.array([4, 3, 4, 4, 8, 4])
x1
array([4, 3, 4, 4, 8, 4])
#assess value to index zero
x1[0]
4
#assess fifth value
x1[4]
8
#get the last value
x1[-1]
4
#get the second last value
x1[-2]
8
访问多维数组应该指定行和列索引:
#in a multidimensional array, we need to specify row and column index
x2
array([[3, 7, 5, 5],
[0, 1, 5, 9],
[3, 0, 5, 0]])
#1st row and 2nd column value
x2[2,3]
0
#3rd row and last value from the 3rd column
x2[2,-1]
0
替换数组中的值:
#replace value at 0,0 index
x2[0,0] = 12
x2
array([[12, 7, 5, 5],
[ 0, 1, 5, 9],
[ 3, 0, 5, 0]])
数组切片
数组切片即访问数组中的一部分元素:
x = np.arange(10)
x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
第0到第4个元素
#from start to 4th position
x[:5]
array([0, 1, 2, 3, 4])
第4个元素到末尾
#from 4th position to end
x[4:]
array([4, 5, 6, 7, 8, 9])
第4到第6个元素
#from 4th to 6th position
x[4:7]
array([4, 5, 6])
偶数索引元素
#return elements at even place
x[ : : 2]
array([0, 2, 4, 6, 8])
起点为索引1,步长为2
#return elements from first position step by two
x[1::2]
array([1, 3, 5, 7, 9])
反向访问数组
#reverse the array
x[::-1]
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
数组连接
连接多个一维数组
#You can concatenate two or more arrays at once.
x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
z = [21,21,21]
np.concatenate([x, y,z])
array([ 1, 2, 3, 3, 2, 1, 21, 21, 21])
连接两个二维数组
#You can also use this function to create 2-dimensional arrays.
grid = np.array([[1,2,3],[4,5,6]])
np.concatenate([grid,grid])
array([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
定义数组连接的方向
axis=1表示水平拼接,axis=0表示垂直拼接。
#Using its axis parameter, you can define row-wise or column-wise matrix
np.concatenate([grid,grid],axis=1)
array([[1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6]])
不同维度数组拼接
当需要结合不同维度的数组时,比如一个 1D 数组和一个 2D 数组,np.concatenate
并不是最方便的选择,因为它要求手动调整维度以确保形状兼容。为了更简洁地处理这种需求,可以使用更高层次的工具,比如:
-
np.vstack
:沿垂直方向(row-wise)堆叠数组。 -
np.hstack
:沿水平方向(column-wise)堆叠数组。x = np.array([3,4,5])
grid = np.array([[1,2,3],[17,18,19]])np.vstack([x,grid])
array([[ 3, 4, 5],
[ 1, 2, 3],
[17, 18, 19]])#Similarly, you can add an array using np.hstack
z = np.array([[9],[9]])
np.hstack([grid,z])
array([[ 1, 2, 3, 9],
[17, 18, 19, 9]])
分割数组
np.split
可以将数组按指定的索引位置拆分成多个子数组:
np.split(array, indices_or_sections, axis=0)
-
indices_or_sections
:可以是一个整数或一个数组-
如果是整数
n
,表示将数组平分为n
部分(必须能整除数组长度)。 -
如果是一个数组(如
[3, 6]
),表示在指定的索引位置进行拆分。
-
-
axis
:- 指定在哪个轴上进行拆分,
axis=0
表示沿行方向(垂直拆分),axis=1
表示沿列方向(水平拆分),不指定默认为0。
- 指定在哪个轴上进行拆分,
例子:
x = np.arange(10)
x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x1,x2,x3 = np.split(x,[3,6])
print x1,x2,x3
[0 1 2] [3 4 5] [6 7 8 9]
np.vsplit
是 NumPy 提供的一个高效工具,用于 沿垂直方向(行) 拆分数组。它是 np.split
的一个简化版本,专门用于垂直拆分。以下代码将一个4×4的数组拆分为上下两个部分。
grid = np.arange(16).reshape((4,4))
upper,lower = np.vsplit(grid,[2]) # 在第2行之后进行拆分
print (upper, lower)
(array([[0, 1, 2, 3],
[4, 5, 6, 7]]), array([[ 8, 9, 10, 11],
[12, 13, 14, 15]]))
除了我们上面学习的函数外,NumPy 库中还有许多其他的数学函数,例如 sum
(求和)、divide
(除法)、multiply
(乘法)、abs
(绝对值)、power
(幂运算)、mod
(取模)、sin
(正弦)、cos
(余弦)、tan
(正切)、log
(对数)、var
(方差)、min
(最小值)、mean
(均值)、max
(最大值)等等。你可以使用这些函数来完成基本的算术计算。想了解更多关于这些函数的信息,可以参考 NumPy 的官方文档。
3 Pandas
创建一个数据框(Data Frame
):这里使用字典,其中键转换为列名,值转换为行值。
import pandas as pd
data = pd.DataFrame({'Country': ['Russia','Colombia','Chile','Equador','Nigeria'],
'Rank':[121,40,100,130,11]})
data
Country | Rank | |
---|---|---|
0 | Russia | 121 |
1 | Colombia | 40 |
2 | Chile | 100 |
3 | Equador | 130 |
4 | Nigeria | 11 |
分析数据
我先可以使用describe
和info
快速地分析以下这个数据:
describe()
方法:用于计算整数或浮点型变量的统计摘要。info()
方法:显示数据集的完整信息,包括行数、列数、列名、数据类型和内存使用情况。
data.describe()
Rank | |
---|---|
count | 5.000000 |
mean | 80.400000 |
std | 52.300096 |
min | 11.000000 |
25% | 40.000000 |
50% | 100.000000 |
75% | 121.000000 |
max | 130.000000 |
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 2 columns):
Country 5 non-null object
Rank 5 non-null int64
dtypes: int64(1), object(1)
memory usage: 152.0+ bytes
排序
现在创建新的数据框:
data = pd.DataFrame({'group': ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c'],
'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]})
group | ounces | |
---|---|---|
0 | a | 4.0 |
1 | a | 3.0 |
2 | a | 12.0 |
3 | b | 6.0 |
4 | b | 7.5 |
5 | b | 8.0 |
6 | c | 3.0 |
7 | c | 5.0 |
8 | c | 6.0 |
按照 ounces 列排序
data.sort_values(by=['ounces'], ascending=True, inplace=False)
完整排序后数据表:
group | ounces | |
---|---|---|
1 | a | 3.0 |
6 | c | 3.0 |
0 | a | 4.0 |
7 | c | 5.0 |
3 | b | 6.0 |
8 | c | 6.0 |
4 | b | 7.5 |
5 | b | 8.0 |
2 | a | 12.0 |
按照多列排序
data.sort_values(by=['group', 'ounces'], ascending=[True, False], inplace=False)
完整排序后数据表:
group | ounces | |
---|---|---|
2 | a | 12.0 |
0 | a | 4.0 |
1 | a | 3.0 |
5 | b | 8.0 |
4 | b | 7.5 |
3 | b | 6.0 |
8 | c | 6.0 |
7 | c | 5.0 |
6 | c | 3.0 |
删除重复行
data = pd.DataFrame({'k1': ['one']*3 + ['two']*4, 'k2': [3, 2, 1, 3, 3, 4, 4]})
k1 | k2 | |
---|---|---|
0 | one | 3 |
1 | one | 2 |
2 | one | 1 |
3 | two | 3 |
4 | two | 3 |
5 | two | 4 |
6 | two | 4 |
数据排序
data.sort_values(by='k2')
k1 | k2 | |
---|---|---|
2 | one | 1 |
1 | one | 2 |
0 | one | 3 |
3 | two | 3 |
4 | two | 3 |
5 | two | 4 |
6 | two | 4 |
删除重复行
data.drop_duplicates()
完整去重后数据表:
k1 | k2 | |
---|---|---|
0 | one | 3 |
1 | one | 2 |
2 | one | 1 |
3 | two | 3 |
5 | two | 4 |
基于特定列删除重复值
data.drop_duplicates(subset='k1')
k1 | k2 | |
---|---|---|
0 | one | 3 |
3 | two | 3 |
分类/新增数据行
在数据处理中,我们需要根据特定条件对变量进行分类。例如,基于食物名称创建对应的动物来源。
创建一个数据框:
data = pd.DataFrame({'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami',
'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'],
'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]})
food | ounces | |
---|---|---|
0 | bacon | 4.0 |
1 | pulled pork | 3.0 |
2 | bacon | 12.0 |
3 | Pastrami | 6.0 |
4 | corned beef | 7.5 |
5 | Bacon | 8.0 |
6 | pastrami | 3.0 |
7 | honey ham | 5.0 |
8 | nova lox | 6.0 |
创建一个映射字典:
meat_to_animal = {
'bacon': 'pig',
'pulled pork': 'pig',
'pastrami': 'cow',
'corned beef': 'cow',
'honey ham': 'pig',
'nova lox': 'salmon'
}
使用 map
函数:
data['animal'] = data['food'].map(str.lower).map(meat_to_animal)
完整数据表:
food | ounces | animal | |
---|---|---|---|
0 | bacon | 4.0 | pig |
1 | pulled pork | 3.0 | pig |
2 | bacon | 12.0 | pig |
3 | Pastrami | 6.0 | cow |
4 | corned beef | 7.5 | cow |
5 | Bacon | 8.0 | pig |
6 | pastrami | 3.0 | cow |
7 | honey ham | 5.0 | pig |
8 | nova lox | 6.0 | salmon |
另一种方式是可以用apply
函数映射:
def meat_2_animal(series):
if series['food'] == 'bacon':
return 'pig'
elif series['food'] == 'pulled pork':
return 'pig'
elif series['food'] == 'pastrami':
return 'cow'
elif series['food'] == 'corned beef':
return 'cow'
elif series['food'] == 'honey ham':
return 'pig'
else:
return 'salmon'
#another way of doing it is: convert the food values to the lower case and apply the function
lower = lambda x: x.lower()
data['food'] = data['food'].apply(lower)
data['animal2'] = data.apply(meat_2_animal, axis='columns')
data
food | ounces | animal | animal2 | |
---|---|---|---|---|
0 | bacon | 4.0 | pig | pig |
1 | pulled pork | 3.0 | pig | pig |
2 | bacon | 12.0 | pig | pig |
3 | pastrami | 6.0 | cow | cow |
4 | corned beef | 7.5 | cow | cow |
5 | bacon | 8.0 | pig | pig |
6 | pastrami | 3.0 | cow | cow |
7 | honey ham | 5.0 | pig | pig |
8 | nova lox | 6.0 | salmon | salmon |
用assign
函数还可以有更多操作来增加一个新的列:
data.assign(new_variable = data\['ounces'\]\*10)
food | ounces | animal | animal2 | new_variable | |
---|---|---|---|---|---|
0 | bacon | 4.0 | pig | pig | 40.0 |
1 | pulled pork | 3.0 | pig | pig | 30.0 |
2 | bacon | 12.0 | pig | pig | 120.0 |
3 | pastrami | 6.0 | cow | cow | 60.0 |
4 | corned beef | 7.5 | cow | cow | 75.0 |
5 | bacon | 8.0 | pig | pig | 80.0 |
6 | pastrami | 3.0 | cow | cow | 30.0 |
7 | honey ham | 5.0 | pig | pig | 50.0 |
8 | nova lox | 6.0 | salmon | salmon | 60.0 |
缺失值处理
首先我们删除animal2
这一列的内容
data.drop('animal2',axis='columns',inplace=True)
food | ounces | animal | |
---|---|---|---|
0 | bacon | 4.0 | pig |
1 | pulled pork | 3.0 | pig |
2 | bacon | 12.0 | pig |
3 | Pastrami | 6.0 | cow |
4 | corned beef | 7.5 | cow |
5 | Bacon | 8.0 | pig |
6 | pastrami | 3.0 | cow |
7 | honey ham | 5.0 | pig |
8 | nova lox | 6.0 | salmon |
我们经常在数据集中发现缺失值。一种快速填补缺失值的方法是用任意随机数填充缺失值。下述代码中,np.nan
表示缺失值。
#Series function from pandas are used to create arrays
data = pd.Series([1., -999., 2., -999., -1000., 3.])
data
0 1.0
1 -999.0
2 2.0
3 -999.0
4 -1000.0
5 3.0
dtype: float64
#replace -999 with NaN values
data.replace(-999, np.nan,inplace=True)
data
0 1.0
1 NaN
2 2.0
3 NaN
4 -1000.0
5 3.0
dtype: float64
#We can also replace multiple values at once.
data = pd.Series([1., -999., 2., -999., -1000., 3.])
data.replace([-999,-1000],np.nan,inplace=True)
data
0 1.0
1 NaN
2 2.0
3 NaN
4 NaN
5 3.0
dtype: float64
重命名行列名
首先创建一个3×4的数组:
data = pd.DataFrame(np.arange(12).reshape((3, 4)),index=['Ohio', 'Colorado', 'New York'],columns=['one', 'two', 'three', 'four'])
data
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
New York | 8 | 9 | 10 | 11 |
现在我们重命名一下行列名:
#Using rename function
data.rename(index = {'Ohio':'SanF'}, columns={'one':'one_p','two':'two_p'},inplace=True)
data
one_p | two_p | three | four | |
---|---|---|---|---|
SanF | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
New York | 8 | 9 | 10 | 11 |
可以使用字符串函数
#You can also use string functions
data.rename(index = str.upper, columns=str.title,inplace=True)
data
One_p | Two_p | Three | Four | |
---|---|---|---|---|
SANF | 0 | 1 | 2 | 3 |
COLORADO | 4 | 5 | 6 | 7 |
NEW YORK | 8 | 9 | 10 | 11 |
连续变量分类
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
我们将年龄划分为几个区间:18-25, 26-35, 36-60,以及60及以上。
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
# '(' 表示区间包含左端点,'[' 表示区间包含右端点
[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
Length: 12
Categories (4, object): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]
修改区间包含规则
要包含右端点,可以设置 right=False
:
pd.cut(ages, bins, right=False)
[[18, 25), [18, 25), [25, 35), [25, 35), [18, 25), ..., [25, 35), [60, 100), [35, 60), [35, 60), [25, 35)]
Length: 12
Categories (4, object): [[18, 25) < [25, 35) < [35, 60) < [60, 100)]
为分类变量自动分配编码
Pandas 库会为分类变量自动分配编码:
cats.labels
array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
统计每个区间的观察值
pd.value_counts(cats)
(18, 25] 5
(35, 60] 3
(25, 35] 3
(60, 100] 1
dtype: int64
为每个区间分配独特名称
bin_names = ['Youth', 'YoungAdult', 'MiddleAge', 'Senior']
new_cats = pd.cut(ages, bins, labels=bin_names)
pd.value_counts(new_cats)
Youth | 5 |
MiddleAge | 3 |
YoungAdult | 3 |
Senior | 1 |
计算累计和
pd.value_counts(new_cats).cumsum()
Youth | 5 |
MiddleAge | 3 |
YoungAdult | 3 |
Senior | 1 |
连续变量分类
接下来,我们将学习如何对连续变量进行分类(分箱)。
python
复制代码
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
我们将年龄划分为几个区间:18-25, 26-35, 36-60,以及60及以上。
python复制代码# 理解输出 - '(' 表示区间包含左端点,'[' 表示区间包含右端点
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
输出:
less复制代码[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
Length: 12
Categories (4, object): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]
修改区间包含规则
要包含右端点,可以设置 right=False
:
python
复制代码
pd.cut(ages, bins, right=False)
输出:
less复制代码[[18, 25), [18, 25), [25, 35), [25, 35), [18, 25), ..., [25, 35), [60, 100), [35, 60), [35, 60), [25, 35)]
Length: 12
Categories (4, object): [[18, 25) < [25, 35) < [35, 60) < [60, 100)]
为分类变量自动分配编码
Pandas 库会为分类变量自动分配编码:
python
复制代码
cats.labels
输出:
scss
复制代码
array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
统计每个区间的观察值
python
复制代码
pd.value_counts(cats)
输出:
go复制代码(18, 25] 5
(35, 60] 3
(25, 35] 3
(60, 100] 1
dtype: int64
为每个区间分配独特名称
python复制代码bin_names = ['Youth', 'YoungAdult', 'MiddleAge', 'Senior']
new_cats = pd.cut(ages, bins, labels=bin_names)
pd.value_counts(new_cats)
输出:
Youth | 5 |
MiddleAge | 3 |
YoungAdult | 3 |
Senior | 1 |
dtype: int64 |
计算累计和
python
复制代码
pd.value_counts(new_cats).cumsum()
输出:
Youth | 5 |
MiddleAge | 3 |
YoungAdult | 3 |
Senior | 1 |
dtype: int64 |
分组与透视表
接下来,我们学习如何在 Pandas 中对数据进行分组和创建透视表。这是数据分析中非常重要的方法,几乎每个数据集都会用到。
示例数据集:
df = pd.DataFrame({
'key1': ['a', 'a', 'b', 'b', 'a'],
'key2': ['one', 'two', 'one', 'two', 'one'],
'data1': np.random.randn(5),
'data2': np.random.randn(5)
})
key1 | key2 | data1 | data2 |
---|---|---|---|
a | one | -0.254348 | 0.853759 |
a | two | 0.130805 | 1.634567 |
b | one | -1.196749 | -0.655586 |
b | two | 0.444007 | -0.711560 |
a | one | -0.537325 | 0.678978 |
按 key1
分组并计算 data1
列的均值:
grouped = df['data1'].groupby(df['key1'])
grouped.mean()
key1
a -0.220289
b -0.376371
Name: data1, dtype: float64
切片操作
先随机创建一个数据集
dates = pd.date_range('20130101', periods=6)
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))
df
A | B | C | D | |
---|---|---|---|---|
2013-01-01 | 1.030816 | -1.276989 | 0.837720 | -1.490111 |
2013-01-02 | -1.070215 | -0.209129 | 0.604572 | -1.743058 |
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 |
2013-01-04 | 0.918203 | -0.158800 | -0.964063 | -1.990779 |
2013-01-05 | 0.089731 | 0.114854 | -0.585815 | 0.298772 |
2013-01-06 | 0.222260 | 0.435183 | -0.045748 | 0.049898 |
获取数据框的前n行
df[:3]
A | B | C | D | |
---|---|---|---|---|
2013-01-01 | 1.030816 | -1.276989 | 0.837720 | -1.490111 |
2013-01-02 | -1.070215 | -0.209129 | 0.604572 | -1.743058 |
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 |
基于日期范围切片
df['20130101':'20130104']
A | B | C | D | |
---|---|---|---|---|
2013-01-01 | 1.030816 | -1.276989 | 0.837720 | -1.490111 |
2013-01-02 | -1.070215 | -0.209129 | 0.604572 | -1.743058 |
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 |
2013-01-04 | 0.918203 | -0.158800 | -0.964063 | -1.990779 |
基于列名切片
df.loc[:, ['A', 'B']]
A | B | |
---|---|---|
2013-01-01 | 1.030816 | -1.276989 |
2013-01-02 | -1.070215 | -0.209129 |
2013-01-03 | 1.524227 | 1.863575 |
2013-01-04 | 0.918203 | -0.158800 |
2013-01-05 | 0.089731 | 0.114854 |
2013-01-06 | 0.222260 | 0.435183 |
基于行标签和列名切片
df.loc['20130102':'20130103', ['A', 'B']]
A | B | |
---|---|---|
2013-01-02 | -1.070215 | -0.209129 |
2013-01-03 | 1.524227 | 1.863575 |
基于列索引切片
返回第4行(索引为3的行):
df.iloc[3]
A 0.918203
B -0.158800
C -0.964063
D -1.990779
Name: 2013-01-04 00:00:00, dtype: float64
返回指定范围的行和列
df.iloc[2:4, 0:2]
A | B | |
---|---|---|
2013-01-03 | 1.524227 | 1.863575 |
2013-01-04 | 0.918203 | -0.158800 |
使用行和列索引列表返回特定行列
df.iloc[[1, 5], [0, 2]]
A | C | |
---|---|---|
2013-01-02 | -1.070215 | 0.604572 |
2013-01-06 | 0.222260 | -0.045748 |
布尔索引和条件筛选操作
我们也可以基于列值进行布尔索引操作,这有助于根据预定义条件筛选数据集。
df[df.A > 1]
A | B | C | D | |
---|---|---|---|---|
2013-01-01 | 1.030816 | -1.276989 | 0.837720 | -1.490111 |
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 |
数据复制和添加新列
我们可以复制数据集并添加新列。
df2 = df.copy()
df2['E'] = ['one', 'one', 'two', 'three', 'four', 'three']
df2
A | B | C | D | E | |
---|---|---|---|---|---|
2013-01-01 | 1.030816 | -1.276989 | 0.837720 | -1.490111 | one |
2013-01-02 | -1.070215 | -0.209129 | 0.604572 | -1.743058 | one |
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 | two |
2013-01-04 | 0.918203 | -0.158800 | -0.964063 | -1.990779 | three |
2013-01-05 | 0.089731 | 0.114854 | -0.585815 | 0.298772 | four |
2013-01-06 | 0.222260 | 0.435183 | -0.045748 | 0.049898 | three |
基于列值选择行
df2[df2['E'].isin(['two', 'four'])]
A | B | C | D | E | |
---|---|---|---|---|---|
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 | two |
2013-01-05 | 0.089731 | 0.114854 | -0.585815 | 0.298772 | four |
选择除特定值外的所有行
df2[~df2['E'].isin(['two', 'four'])]
A | B | C | D | E | |
---|---|---|---|---|---|
2013-01-01 | 1.030816 | -1.276989 | 0.837720 | -1.490111 | one |
2013-01-02 | -1.070215 | -0.209129 | 0.604572 | -1.743058 | one |
2013-01-04 | 0.918203 | -0.158800 | -0.964063 | -1.990779 | three |
2013-01-06 | 0.222260 | 0.435183 | -0.045748 | 0.049898 | three |
使用 query
方法基于条件选择列
列出所有 A 大于 C 的行:
df.query('A > C')
A | B | C | D | |
---|---|---|---|---|
2013-01-01 | 1.030816 | -1.276989 | 0.837720 | -1.490111 |
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 |
2013-01-04 | 0.918203 | -0.158800 | -0.964063 | -1.990779 |
2013-01-05 | 0.089731 | 0.114854 | -0.585815 | 0.298772 |
2013-01-06 | 0.222260 | 0.435183 | -0.045748 | 0.049898 |
使用 OR 条件筛选:
df.query('A < B | C > A')
A | B | C | D | |
---|---|---|---|---|
2013-01-02 | -1.070215 | -0.209129 | 0.604572 | -1.743058 |
2013-01-03 | 1.524227 | 1.863575 | 1.291378 | 1.300696 |
2013-01-05 | 0.089731 | 0.114854 | -0.585815 | 0.298772 |
2013-01-06 | 0.222260 | 0.435183 | -0.045748 | 0.049898 |
数据透视表的基础操作例子
数据透视表(pivot table
)在以自定义表格格式分析数据时非常有用。在 Excel 等工具中,数据透视表的功能使其备受欢迎,因为它提供了快速分析数据的方法。
创建数据框
data = pd.DataFrame({
'group': ['a', 'a', 'a', 'b','b', 'b', 'c', 'c','c'],
'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]
})
data
group | ounces | |
---|---|---|
0 | a | 4.0 |
1 | a | 3.0 |
2 | a | 12.0 |
3 | b | 6.0 |
4 | b | 7.5 |
5 | b | 8.0 |
6 | c | 3.0 |
7 | c | 5.0 |
8 | c | 6.0 |
计算每组的平均值
data.pivot_table(values='ounces', index='group', aggfunc=np.mean)
group | ounces |
---|---|
a | 6.333333 |
b | 7.166667 |
c | 4.666667 |
计算每组的计数
data.pivot_table(values='ounces', index='group', aggfunc='count')
group | ounces |
---|---|
a | 3 |
b | 3 |
c | 3 |
4 机器学习数据处理实例
我们将使用著名的 adult
数据集,来源于 UCI 机器学习库。您可以从 这里下载数据集。 在此数据集中,目标变量是 “target”。这是一个二分类问题,我们需要预测某人的工资是低于还是高于 50K。
加载数据集
train = pd.read_csv("~/Adult/train.csv")
test = pd.read_csv("~/Adult/test.csv")
数据集基本信息
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 32561 entries, 0 to 32560
Data columns (total 15 columns):
age 32561 non-null int64
workclass 30725 non-null object
fnlwgt 32561 non-null int64
education 32561 non-null object
education.num 32561 non-null int64
marital.status 32561 non-null object
occupation 30718 non-null object
relationship 32561 non-null object
race 32561 non-null object
sex 32561 non-null object
capital.gain 32561 non-null int64
capital.loss 32561 non-null int64
hours.per.week 32561 non-null int64
native.country 31978 non-null object
target 32561 non-null object
dtypes: int64(6), object(9)
memory usage: 3.7+ MB
训练集包含 32561 行和 15 列,其中 6 列为整数类型,其余为字符串(或字符)类型。
快速检查行和列数量:
print ("The train data has", train.shape)
print ("The test data has", test.shape)
The train data has (32561, 15)
The test data has (16281, 15)
查看前几行数据
train.head()
age | workclass | fnlwgt | education | education.num | marital.status | occupation | relationship | race | sex | capital.gain | capital.loss | hours.per.week | native.country | target | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 39 | State-gov | 77516 | Bachelors | 13 | Never-married | Adm-clerical | Not-in-family | White | Male | 2174 | 0 | 40 | United-States | <=50K |
1 | 50 | Self-emp-not-inc | 83311 | Bachelors | 13 | Married-civ-spouse | Exec-managerial | Husband | White | Male | 0 | 0 | 13 | United-States | <=50K |
2 | 38 | Private | 215646 | HS-grad | 9 | Divorced | Handlers-cleaners | Not-in-family | White | Male | 0 | 0 | 40 | United-States | <=50K |
3 | 53 | Private | 234721 | 11th | 7 | Married-civ-spouse | Handlers-cleaners | Husband | Black | Male | 0 | 0 | 40 | United-States | <=50K |
4 | 28 | Private | 338409 | Bachelors | 13 | Married-civ-spouse | Prof-specialty | Wife | Black | Female | 0 | 0 | 40 | Cuba | <=50K |
缺失值检查
train.isnull().sum()
缺失值数量 | |
---|---|
age | 0 |
workclass | 1836 |
occupation | 1843 |
native.country | 583 |
填充缺失值:
train['workclass'].fillna('Private', inplace=True)
train['occupation'].fillna('Prof-specialty', inplace=True)
train['native.country'].fillna('United-States', inplace=True)
数据转换
我们将字符型变量转化为数值型以便用于机器学习模型,同样的字符串用同一个数字表示:
from sklearn import preprocessing
for col in train.columns:
if train[col].dtype == 'object':
lbl = preprocessing.LabelEncoder()
train[col] = lbl.fit_transform(train[col])
随机森林模型
训练随机森林模型并评估其性能:
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
y = train['target']
X = train.drop(['target'], axis=1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y, random_state=1)
clf = RandomForestClassifier(n_estimators=500, max_depth=6, random_state=1)
clf.fit(X_train, y_train)
prediction = clf.predict(X_test)
acc = accuracy_score(y_test, prediction)
print(f'The accuracy of Random Forest is {acc}')
模型的准确率为 85.2%。
5 总结
NumPy 是用于高效数值计算的基础工具,擅长处理多维数组和矩阵运算,为数据科学提供了强大的支持。Pandas 提供了灵活的数据操作和分析功能,尤其擅长处理结构化数据,是数据清洗和分析的利器。
希望大家对这两个工具有了初步认识,未来可以结合实际场景深入学习和应用。