机器学习详解(1):Python基础之Numpy和Pandas

发布于:2024-12-08 ⋅ 阅读:(117) ⋅ 点赞:(0)


在数据科学和机器学习领域,NumPy和Pandas以其高效的数据操作能力和直观的语法设计,为数据计算和分析提供了极大的便利。无论是快速的数组计算,还是灵活的数据表操作,NumPy和Pandas都已成为数据处理工作的必备利器。在学习机器学习前,我们先来看一下这两个知识点。

1 入门:Numpy和Pandas

  1. Pandas依赖于NumPy
    Pandas的强大数据操作能力是建立在NumPy库之上的,可以说NumPy是Pandas的基础。
  2. Pandas擅长处理表格型数据
    Pandas在处理不同变量类型(如整数、浮点数、时间序列数据等)时表现出色,尤其适合进行数据加载、特征工程和时间序列分析等任务。
  3. NumPy专注于数值计算
    NumPy非常适合执行基本的数值运算,例如均值、中位数、范围等。同时,它还支持创建多维数组,为复杂数据结构的操作提供了支持。
  4. 与其他语言的兼容性
    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

分析数据

我先可以使用describeinfo快速地分析以下这个数据:

  • 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 提供了灵活的数据操作和分析功能,尤其擅长处理结构化数据,是数据清洗和分析的利器。

希望大家对这两个工具有了初步认识,未来可以结合实际场景深入学习和应用。


网站公告

今日签到

点亮在社区的每一天
去签到