Python单表查询

本文主要介绍了Python中常用的单表查询操作,包括:表结构查询、行查询、列查询,以及分组聚合和数据透视等。

1、表结构信息查询和修改

1.1、表结构信息查询

  • df.info():表基础信息
  • df.index:表索引
  • df.columns:表字段
  • df.dtypes:字段类型
1
2
import numpy as np
import pandas as pd
1
2
3
4
5
6
np.random.seed(8)
a = np.random.randint(60, 100, (10, 6))
df = pd.DataFrame(a)
df.columns = ['语文', '数学', '英语', '物理', '化学', '生物']
df.index = list('ABCDEFGHIJ')
print(df)
   语文  数学  英语  物理  化学  生物
A  63  80  65  86  68  79
B  81  70  87  73  69  75
C  89  94  78  74  98  89
D  69  64  67  86  62  98
E  69  97  77  75  88  87
F  82  91  80  81  68  88
G  88  91  70  60  67  62
H  98  67  91  96  85  98
I  87  64  97  62  78  98
J  82  99  66  91  92  69
1
2
# 查看表信息
print(df.info())
<class 'pandas.core.frame.DataFrame'>
Index: 10 entries, A to J
Data columns (total 6 columns):
 #   Column  Non-Null Count  Dtype
---  ------  --------------  -----
 0   语文      10 non-null     int32
 1   数学      10 non-null     int32
 2   英语      10 non-null     int32
 3   物理      10 non-null     int32
 4   化学      10 non-null     int32
 5   生物      10 non-null     int32
dtypes: int32(6)
memory usage: 320.0+ bytes
None
1
2
3
print(df.index)  # 查看索引标签
print(df.columns) # 查看字段标签
print(df.dtypes) # 查看字段类型
Index(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], dtype='object')
Index(['语文', '数学', '英语', '物理', '化学', '生物'], dtype='object')
语文    int32
数学    int32
英语    int32
物理    int32
化学    int32
生物    int32
dtype: object

1.2、表结构信息修改

1.21、修改字段名

  • 给所有字段重命名:df.columns
  • 给某个字段重命名:df.rename(columns = {‘原字段名’:’新字段名’}
1
2
3
4
5
6
np.random.seed(8)
a = np.random.randint(60, 100, (10, 6))
df = pd.DataFrame(a)
df.columns = ['语文', '数学', '英语', '物理', '化学', '生物']
df.index = list('ABCDEFGHIJ')
print(df)
   语文  数学  英语  物理  化学  生物
A  63  80  65  86  68  79
B  81  70  87  73  69  75
C  89  94  78  74  98  89
D  69  64  67  86  62  98
E  69  97  77  75  88  87
F  82  91  80  81  68  88
G  88  91  70  60  67  62
H  98  67  91  96  85  98
I  87  64  97  62  78  98
J  82  99  66  91  92  69
1
2
3
print(df.columns)
df.columns = list('ABCDEF')
print(df.columns)
Index(['语文', '数学', '英语', '物理', '化学', '生物'], dtype='object')
Index(['A', 'B', 'C', 'D', 'E', 'F'], dtype='object')
1
2
df = df.rename(columns={'A': '语文', 'B': '数学'})
print(df.columns)
Index(['语文', '数学', 'C', 'D', 'E', 'F'], dtype='object')

1.22 修改字段数据类型

1
print(df.dtypes)
语文    int32
数学    int32
C     int32
D     int32
E     int32
F     int32
dtype: object
1
2
df['语文'] = df['语文'].astype('float')
print(df.dtypes)
语文    float64
数学      int32
C       int32
D       int32
E       int32
F       int32
dtype: object

1.23、修改索引名

  • 给所有索引重命名:df.index
  • 给某个索引重命名:df.rename(index = {‘原索引名’:’新索引名’}
1
2
3
print(df.index)
df.index = list('0123456789') ## 注意此处索引是字符串,而不是数值!
print(df.index)
Index(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], dtype='object')
Index(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], dtype='object')
1
2
df = df.rename(index={'1': 11, '3': 33})
print(df.index)
Index(['0', 11, '2', 33, '4', '5', '6', '7', '8', '9'], dtype='object')

1.24、索引与列的转换

  • 列转换成索引:df.set_index(列名)

  • 索引转换成列:df.reset_index()

1
2
3
df = pd.DataFrame([['小明', 89, 70], ['小篮', 45, 84], ['小红', 76, 99], ['小黑', 76, 88]],
columns=['姓名', '物理', '化学'])
print(df)
   姓名  物理  化学
0  小明  89  70
1  小篮  45  84
2  小红  76  99
3  小黑  76  88
1
2
df.set_index('姓名', inplace=True)  # 列转化为索引,inplace=True 生成的副本替换原变量
print(df)
    物理  化学
姓名        
小明  89  70
小篮  45  84
小红  76  99
小黑  76  88
1
2
print(df.reset_index())  # 重置索引,并将旧索引转成列
print(df.reset_index(drop=True)) # 仅重置索引
   姓名  物理  化学
0  小明  89  70
1  小篮  45  84
2  小红  76  99
3  小黑  76  88
   物理  化学
0  89  70
1  45  84
2  76  99
3  76  88

2、对行的查询

索引/选择的基本语法如下:

实现目的 语法 结果
选择列 df[col] Series
切片行 df[5:10] DataFrame
按标签选择行 df.loc[label] Series
按位置选择行 df.iloc[loc] Series

2.1、隐式索引查询

  • df[ 隐式索引切片 ]
  • df.iloc[ 隐式索引切片, ‘列索引’切片]
    切片的终止位置不能取
1
2
3
4
5
6
np.random.seed(8)
a = np.random.randint(60, 100, (10, 6))
df = pd.DataFrame(a)
df.columns = ['语文', '数学', '英语', '物理', '化学', '生物']
df.index = list('ABCDEFGHIJ')
print(df)
   语文  数学  英语  物理  化学  生物
A  63  80  65  86  68  79
B  81  70  87  73  69  75
C  89  94  78  74  98  89
D  69  64  67  86  62  98
E  69  97  77  75  88  87
F  82  91  80  81  68  88
G  88  91  70  60  67  62
H  98  67  91  96  85  98
I  87  64  97  62  78  98
J  82  99  66  91  92  69
1
print(df[1:3])  # 切片的终止位置不能取
   语文  数学  英语  物理  化学  生物
B  81  70  87  73  69  75
C  89  94  78  74  98  89
1
print(df.iloc[1:6:2, 1:4])
   数学  英语  物理
B  70  87  73
D  64  67  86
F  91  80  81

2.2、显式索引查询

  • df[ 显式索引切片]
  • df.loc[ 显式索引切片 , 字段名切片 ]
    切片的终止位置能取
1
print(df['B':'D'])  # 终止位置能取
   语文  数学  英语  物理  化学  生物
B  81  70  87  73  69  75
C  89  94  78  74  98  89
D  69  64  67  86  62  98
1
print(df.loc['B':'F', ])
   语文  数学  英语  物理  化学  生物
B  81  70  87  73  69  75
C  89  94  78  74  98  89
D  69  64  67  86  62  98
E  69  97  77  75  88  87
F  82  91  80  81  68  88

2.3、条件查询

  • df[ 条件表达式 ]
符号 含义 释义
| or 或者
& and 并且
~ not 取反
^ xor 异或
1
print(df[df.物理 > 80])
   语文  数学  英语  物理  化学  生物
A  63  80  65  86  68  79
D  69  64  67  86  62  98
F  82  91  80  81  68  88
H  98  67  91  96  85  98
J  82  99  66  91  92  69
1
print(df[(df.物理 > 80) | (df.化学 > 80)])  # 多条件要用()隔开
   语文  数学  英语  物理  化学  生物
A  63  80  65  86  68  79
C  89  94  78  74  98  89
D  69  64  67  86  62  98
E  69  97  77  75  88  87
F  82  91  80  81  68  88
H  98  67  91  96  85  98
J  82  99  66  91  92  69

3、对列的查询

3.1、隐式索引查询

  • df.iloc[ 隐式索引切片, ‘列索引’切片]
    切片的终止位置不能取
1
print(df.iloc[:, 1:4])
   数学  英语  物理
A  80  65  86
B  70  87  73
C  94  78  74
D  64  67  86
E  97  77  75
F  91  80  81
G  91  70  60
H  67  91  96
I  64  97  62
J  99  66  91

3.2 显式索引查询

  • df[ 字段名 ]
  • df[ [字段名1,字段名2,…] ]
  • df.loc[ 显式索引切片 , 字段名切片 ]
    切片的终止位置能取
1
print(df['语文'])  # 查询单列
A    63
B    81
C    89
D    69
E    69
F    82
G    88
H    98
I    87
J    82
Name: 语文, dtype: int32
1
print(df[['语文', '物理']])  # 查询多列
   语文  物理
A  63  86
B  81  73
C  89  74
D  69  86
E  69  75
F  82  81
G  88  60
H  98  96
I  87  62
J  82  91
1
print(df.loc[:, '语文':'物理'])  # 使用切片
   语文  数学  英语  物理
A  63  80  65  86
B  81  70  87  73
C  89  94  78  74
D  69  64  67  86
E  69  97  77  75
F  82  91  80  81
G  88  91  70  60
H  98  67  91  96
I  87  64  97  62
J  82  99  66  91

3.3、查询特定数据类型的列

  • df.select_dtypes(include, excluede)
1
2
df['浮点型'] = 1.3
print(df.dtypes)
语文       int32
数学       int32
英语       int32
物理       int32
化学       int32
生物       int32
浮点型    float64
dtype: object
1
print(df.select_dtypes(include=float))  # 查找float类型的列
   浮点型
A  1.3
B  1.3
C  1.3
D  1.3
E  1.3
F  1.3
G  1.3
H  1.3
I  1.3
J  1.3
1
print(df.select_dtypes(exclude=float))  # 查找非float类型的列
   语文  数学  英语  物理  化学  生物
A  63  80  65  86  68  79
B  81  70  87  73  69  75
C  89  94  78  74  98  89
D  69  64  67  86  62  98
E  69  97  77  75  88  87
F  82  91  80  81  68  88
G  88  91  70  60  67  62
H  98  67  91  96  85  98
I  87  64  97  62  78  98
J  82  99  66  91  92  69
1
print(df.select_dtypes(include=[float, int]))  # 查找多种类型的列
   语文  数学  英语  物理  化学  生物  浮点型
A  63  80  65  86  68  79  1.3
B  81  70  87  73  69  75  1.3
C  89  94  78  74  98  89  1.3
D  69  64  67  86  62  98  1.3
E  69  97  77  75  88  87  1.3
F  82  91  80  81  68  88  1.3
G  88  91  70  60  67  62  1.3
H  98  67  91  96  85  98  1.3
I  87  64  97  62  78  98  1.3
J  82  99  66  91  92  69  1.3

4、分组聚合

4.1 数值型变量的统计描述

  • df.describe():查看数值型变量的特征
1
2
3
4
5
6
7
8
9
10
import random

np.random.seed(8)
a = np.random.randint(60, 100, (10, 6))
df = pd.DataFrame(a)
df.columns = ['语文', '数学', '英语', '物理', '化学', '生物']
df.insert(loc=0, column='姓名', value=list('ABCDEFGHIJ'))
df.insert(loc=1, column='性别', value=df.姓名.apply(lambda x: random.choice(['男','女'])))
df.insert(loc=2, column='班级', value=df.姓名.apply(lambda x: random.choice(['1班','2班','3班'])))
print(df)
  姓名 性别  班级  语文  数学  英语  物理  化学  生物
0  A  男  2班  63  80  65  86  68  79
1  B  男  2班  81  70  87  73  69  75
2  C  女  2班  89  94  78  74  98  89
3  D  男  1班  69  64  67  86  62  98
4  E  男  1班  69  97  77  75  88  87
5  F  女  3班  82  91  80  81  68  88
6  G  女  3班  88  91  70  60  67  62
7  H  女  1班  98  67  91  96  85  98
8  I  男  2班  87  64  97  62  78  98
9  J  女  3班  82  99  66  91  92  69
1
print(df.describe().T)   # 只对数值型变量进行统计描述
    count  mean        std   min    25%   50%    75%   max
语文   10.0  80.8  10.809461  63.0  72.00  82.0  87.75  98.0
数学   10.0  81.7  14.298796  64.0  67.75  85.5  93.25  99.0
英语   10.0  77.8  11.123549  65.0  67.75  77.5  85.25  97.0
物理   10.0  78.4  11.824645  60.0  73.25  78.0  86.00  96.0
化学   10.0  77.5  12.474418  62.0  68.00  73.5  87.25  98.0
生物   10.0  84.3  12.702143  62.0  76.00  87.5  95.75  98.0

4.2、分组

4.21、groupby对象

创建groupby对象

  • df.groupby(by) 当依据多个字段分组时,by用列表

groupby对象的属性和方法

  • gp.groups查看分组情况查看分组的情况
  • len(gp)查看分成了多少组
  • gp.size()查看每组包含多少条记录
  • gp.get_groups(某组)获得分组后的某组
1
2
gp = df.groupby(by=['性别'])
print(gp) # 分组得到的是一个惰性对象
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000020CCBEE2B90>
1
2
3
4
print(gp.groups)   # 返回的是一个字典
print(len(gp)) # 返回组数
print(gp.size()) # 返回每组条数(分组计数)
print(gp.get_group('男').reset_index(drop=True)) # 返回组子集
{'女': [2, 5, 6, 7, 9], '男': [0, 1, 3, 4, 8]}
2
性别
女    5
男    5
dtype: int64
  姓名 性别  班级  语文  数学  英语  物理  化学  生物
0  A  男  2班  63  80  65  86  68  79
1  B  男  2班  81  70  87  73  69  75
2  D  男  1班  69  64  67  86  62  98
3  E  男  1班  69  97  77  75  88  87
4  I  男  2班  87  64  97  62  78  98

在 Python 的 pandas 库中,.groupby 是一个强大的功能,它允许用户根据一个或多个键对数据进行分组,并对每个组执行某些操作。
了解其内部原理有助于更好地理解其工作方式以及为何在某些情况下它的性能表现如此出色。

下面是 .groupby 的内部原理的基本概述:

  1. 创建分组键
    当你调用 .groupby 方法并传入一个或多个列名时,pandas 会首先根据这些列的值创建分组键。这些键是唯一的,用于标识每个分组。
    例如,如果你根据一个包含 ['foo', 'bar', 'foo', 'bar'] 的列进行分组,那么你会得到两个分组键:'foo''bar'

  2. 哈希映射
    为了高效地查找每个键对应的行,pandas 使用哈希映射(通常是字典)来存储分组键和它们对应的行索引。
    这样,当你需要访问某个键的所有行时,可以立即通过哈希查找得到,而不需要遍历整个数据集。

  3. 分组对象
    .groupby 方法返回的是一个分组对象(GroupBy object),它并不包含实际的分组数据,而是存储了如何根据分组键访问原始数据的信息。
    这个对象非常轻量级,因为它没有复制数据,只是保存了分组逻辑。

  4. 惰性计算
    分组对象是惰性的,这意味着它不会立即执行任何计算。只有当你调用聚合函数(如 mean(), sum(), count() 等)或其他方法(如 apply())时,
    pandas 才会根据分组键对数据进行实际的分组和计算。这种惰性计算方式可以显著提高性能,特别是在处理大型数据集时。

  5. 聚合操作
    当你对分组对象调用聚合函数时,pandas 会遍历每个分组,并对每个分组内的数据应用指定的聚合函数。
    由于分组键和对应的行索引已经通过哈希映射建立好了,所以这个过程是非常高效的。

  6. 返回结果
    最后,.groupby 操作会返回一个新的 DataFrame 或 Series,其中包含了每个分组的聚合结果。
    这个结果的索引通常是分组键,列则是聚合函数的输出。

  7. 性能优化
    为了进一步提高性能,pandas 在实现 .groupby 时还采用了一些优化技术,如使用 Cython(一种 Python 的扩展语言,
    用于编写 C 风格的代码以提高性能)编写的底层代码、内部多线程处理以及缓存机制等。

    总的来说,.groupby 的内部原理基于哈希映射和惰性计算,这使得它能够高效地处理大型数据集,并为用户提供灵活且强大的分组聚合功能。

4.3、聚合

  • gp.agg()

.agg() 函数是 pandas 库中用于对 groupby 对象应用聚合函数的一个非常强大的工具。通过 .agg(),你可以对分组后的数据应用一个或多个聚合函数,并返回结果。这允许你以灵活的方式对分组数据进行摘要统计。

下面是如何使用 .agg() 函数的一些示例:

4.31、对单个列应用单个聚合函数

1
2
3
4
5
6
7
8
9
10
11
12
# 创建一个简单的 DataFrame
df = pd.DataFrame({
'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
'B': [1, 2, 3, 4, 5, 6, 7, 8],
'C': [9, 10, 11, 12, 13, 14, 15, 16]
})

# 根据列 'A' 分组,并对列 'B' 应用 mean 聚合函数
gp = df.groupby('A')
result = gp['B'].agg('mean')

print(result)
A
bar    4.0
foo    4.8
Name: B, dtype: float64

注意:
通过 gp[‘B’],你可以专注于特定的列,并对其应用聚合操作,而不是对整个 DataFrame 应用操作。这使得 groupby 操作更加灵活和高效。

gp.head() 获取各组前n行
gp.tail() 获取各组后n行

在 pandas 中,当你使用 grouped.head() 时,你实际上是在对分组后的每个组调用 head() 方法,以获取每个组的前几行数据。
这里的关键是,虽然你根据某个键进行了分组,但 head() 方法返回的是原始 DataFrame 中的行,而不是重新构建的、仅包含分组键的 DataFrame。

因此,grouped.head() 返回的索引仍然是原始 DataFrame 的索引,而不是分组键。这是因为 head() 只是简单地选择每个组的前几行,并没有改变这些行的索引。

1
2
3
print(gp.head(1))
print(gp.head(1))
print(gp.tail(1))
     A  B   C
0  foo  1   9
1  bar  2  10
     A  B   C
0  foo  1   9
1  bar  2  10
     A  B   C
5  bar  6  14
7  foo  8  16

4.32、对单个列应用多个聚合函数

1
2
3
4
# 根据列 'A' 分组,并对列 'B' 应用多个聚合函数
result = gp['B'].agg(['mean', 'sum', 'count'])

print(result)
     mean  sum  count
A                    
bar   4.0   12      3
foo   4.8   24      5

4.33、对多个列应用聚合函数

1
2
3
4
# 对多个列应用不同的聚合函数
result = gp.agg({'B': ['mean', 'sum'], 'C': 'count'})

print(result)
       B         C
    mean sum count
A                 
bar  4.0  12     3
foo  4.8  24     5

4.34、使用自定义函数

1
2
3
4
5
6
7
8
# 定义一个自定义函数
def custom_func(x):
return x.sum() / len(x)

# 对列 'B' 应用自定义函数
result = gp['B'].agg(custom_func)

print(result)
A
bar    4.0
foo    4.8
Name: B, dtype: float64

4.35、使用 lambda 函数

1
2
3
4
# 使用 lambda 函数计算列 'B' 的标准差
result = gp['B'].agg(lambda x: x.std())

print(result)
A
bar    2.000000
foo    2.863564
Name: B, dtype: float64

在这些示例中,.agg() 函数接受一个函数、函数列表、字典或者字符串作为参数,这些参数定义了如何聚合数据。
你可以传递内置的聚合函数(如 ‘mean’, ‘sum’, ‘count’ 等),自定义函数,或者 lambda 函数。如果传递字典,则字典的键是列名,值是聚合函数或函数列表。

.agg() 函数的强大之处在于其灵活性,它允许你以多种方式组合和定制你的聚合操作,从而得到你想要的统计摘要。

5、数据透视表

5.1、数据透视

1
2
3
4
5
6
7
8
9
10
import random

np.random.seed(8)
a = np.random.randint(60, 100, (10, 6))
df = pd.DataFrame(a)
df.columns = ['语文', '数学', '英语', '物理', '化学', '生物']
df.insert(loc=0, column='姓名', value=list('ABCDEFGHIJ'))
df.insert(loc=1, column='性别', value=df.姓名.apply(lambda x: random.choice(['男','女'])))
df.insert(loc=2, column='班级', value=df.姓名.apply(lambda x: random.choice(['1班','2班','3班'])))
print(df)
  姓名 性别  班级  语文  数学  英语  物理  化学  生物
0  A  女  3班  63  80  65  86  68  79
1  B  男  3班  81  70  87  73  69  75
2  C  女  3班  89  94  78  74  98  89
3  D  女  3班  69  64  67  86  62  98
4  E  男  2班  69  97  77  75  88  87
5  F  男  2班  82  91  80  81  68  88
6  G  男  2班  88  91  70  60  67  62
7  H  女  2班  98  67  91  96  85  98
8  I  男  3班  87  64  97  62  78  98
9  J  女  2班  82  99  66  91  92  69
1
2
df_pivot1 = pd.pivot_table(df, values='语文', index='班级', columns='性别', aggfunc=['mean'])
print(df_pivot1)
         mean           
性别          女          男
班级                      
2班  90.000000  79.666667
3班  73.666667  84.000000
1
2
df_pivot2 = pd.pivot_table(df, values=['语文','数学'], index=['班级','姓名'], columns=['性别'], aggfunc=['mean'])
print(df_pivot2)
       mean                  
         数学          语文      
性别        女     男     女     男
班级 姓名                        
2班 E    NaN  97.0   NaN  69.0
   F    NaN  91.0   NaN  82.0
   G    NaN  91.0   NaN  88.0
   H   67.0   NaN  98.0   NaN
   J   99.0   NaN  82.0   NaN
3班 A   80.0   NaN  63.0   NaN
   B    NaN  70.0   NaN  81.0
   C   94.0   NaN  89.0   NaN
   D   64.0   NaN  69.0   NaN
   I    NaN  64.0   NaN  87.0

5.2、逆透视

1
2
result = df_pivot1.stack().reset_index().head()
print(result)
   班级 性别       mean
0  2班  女  90.000000
1  2班  男  79.666667
2  3班  女  73.666667
3  3班  男  84.000000
1
2
3
# 逆透视两次
result = df_pivot2.stack().stack().reset_index().head()
print(result)
   班级 姓名 性别 level_3  mean
0  2班  E  男      数学  97.0
1  2班  E  男      语文  69.0
2  2班  F  男      数学  91.0
3  2班  F  男      语文  82.0
4  2班  G  男      数学  91.0
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2022-2024 归一
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信