首页 > 其他分享 >饮冰三年-人工智能-Pandas-80-Pandas 数据扩增

饮冰三年-人工智能-Pandas-80-Pandas 数据扩增

时间:2022-10-15 18:22:15浏览次数:83  
标签:11 02 17 16 id 2022 饮冰 80 Pandas

上一篇:饮冰三年-人工智能-Pandas-78-Pandas 新增、统计、排序

 数据准备可参考:饮冰三年-人工智能-Django淘宝拾遗-75-数据准备

一、索引

索引(index)是 Pandas 的重要工具,通过索引可以从 DataFame 中选择特定的行数和列数,这种选择数据的方式称为“子集选择”。在 Pandas 中,索引值也被称为标签(label)

索引作用:

  1. 方便数据查询
  2. 使用index可以提升性能
    • 如果index是唯一的,Pandas会使用 哈希表优化,查询性能为O(1);
    • 如果index不是唯一的,但是有序,Pandas会使用 二分查找算法,查询性能为O(logN);
    • 如果index不是唯一的,而且无序,Pandas只能扫描全表,查询性能为O(N);
  3. 自动的数据对齐功能
  4. 更强大的数据结构支持
    • Categoricall Index :基于分类的index,提升性能
    • Multi Index :多维索引,用于group by 多维聚合后结果
    • Datetime Index :时间类型索引,强大的日期和时间的方法支持

1.1 方便查询

from timeit import timeit

import pandas as pd

from api_service.pandas_ import get_data_from_db

df = get_data_from_db()


def query_easy():
    print(df.head())
    """
       id  gender  ...            add_time         modify_time
0   7       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
1   8       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
2   9       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
3  10       1  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
4  11       1  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
    """
    df.set_index("student_id", inplace=True, drop=False)  # drop=False 让索引列还保持在 column
    print(df.head())
    """
                id  gender  ...            add_time         modify_time
student_id              ...                                        
101          7       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
102          8       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
103          9       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
114         10       1  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
115         11       1  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
    """
    # 方式一: 使用index的查询方法
    df_easy = df.loc[101].head()
    print(df_easy)
    """
                 id  gender  ...            add_time         modify_time
student_id               ...                                        
101           7       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101          13       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101          19       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101          25       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101         103       0  ... 2022-02-22 17:16:52 2022-02-22 17:16:54
    """
    # 方式二: 使用column的condition查询方法
    df_hard = df.loc[df["student_id"] == 101].head()
    print(df_hard)
    """
                 id  gender  ...            add_time         modify_time
student_id               ...                                        
101           7       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101          13       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101          19       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101          25       0  ... 2022-02-11 17:16:52 2022-02-11 17:16:54
101         103       0  ... 2022-02-22 17:16:52 2022-02-22 17:16:54
    """
代码

1.2 提升性能

1.3 数据对齐

def align_data():
    s1 = pd.Series([1, 2, 3], index=list("abc"))
    s2 = pd.Series([2, 3, 4], index=list("bcd"))
    print(s1 + s2)
    """
    a    NaN
    b    4.0
    c    6.0
    d    NaN
    dtype: float64
    """
代码

二、merge

pandas 的 Merge,相当于SQL的Join,将不同的表按key关联到一个表。官方文档

2.1 Merge语法

merge语法:DataFrame.merge(right, how='inner', on=None, left_on=None, right_on=None,left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
right:要merge的 DataFrame 或者 有named的Series
how:join类型,‘left’, ‘right’, ‘outer’, ‘inner’
on:join的key,left和right都需要有这个key
left_on:left的df或者series的key
right_on:right的df或者seires的key
left_index,right_index:使用index而不是普通的column做join
suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是(‘_x’, ‘_y’)

2.2 Merge时表之间的对应关系

one-to-one:一对一关系,关联的key都是唯一的
one-to-many:一对多关系,左边唯一key,右边不唯一key。 eg:查看专业开设了哪些课程

many-to-many:多对多关系,这种会涉及到第三张表。eg:查看学生各科成绩

import pandas as pd
from django.utils.http import urlquote
from sqlalchemy import create_engine

from api_service.pandas_ import MYSQL_USER, MYSQL_PASSWORD, MYSQL_HOST, MYSQL_PORT, MYSQL_NAME


def get_data_from_db():
    """
    新版本的pandas库中con参数使用sqlalchemy库创建的create_engine对象
    创建create_engine对象(格式类似于URL地址):
    """
    create_engine(f'postgresql+psycopg2://')

    engine = create_engine(
        f'mysql+pymysql://{MYSQL_USER}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_NAME}')
    profession = pd.read_sql("SELECT id,profession_name FROM tb_profession", engine)  # 专业表,
    course = pd.read_sql("SELECT id,profession_id,subject_name FROM tb_course", engine)  # 课程表,
    score = pd.read_sql("SELECT id,student_id,course_id,exams_date,score_total FROM tb_score", engine)  # 成绩表
    student = pd.read_sql("SELECT id,student_name FROM tb_student", engine)  # 学生表
    return profession, course, score, student


def get_merge():
    pd.set_option('display.width', 2000)
    pd.set_option('display.max_columns', None)

    profession, course, score, student = get_data_from_db()
    print(student.head(), profession.head(), course.head(), score.head(), )
    '''
        id student_name
0  101         小明-经
1  102         小红-经
2  103         小花-经
3  114         张三-经
4  115         李四-经
    id profession_name
0   1           经济与管理
1   2             计算机
2   3           文学与历史
3   4             挖掘机
    id  profession_id subject_name
0  11              1         语文-经
1  12              1         数学-经
2  13              1         英语-经
3  14              1        经济学-经
4  21              2         语文-计
    id  student_id  course_id  exams_date  score_total
0   7         101         11  2022-02-11         77.0
1   8         102         11  2022-02-11         60.0
2   9         103         11  2022-02-11         50.0
3  10         114         11  2022-02-11        100.0
4  11         115         11  2022-02-11         80.0

    '''
    # 01 查看专业开设了哪些课程(专业:课程《==》1:N)
    df_profession_course = pd.merge(profession, course, left_on="id", right_on="profession_id", how="inner")
    print(df_profession_course)
    '''
       id_x profession_name  id_y  profession_id subject_name
0      1           经济与管理    11              1         语文-经
1      1           经济与管理    12              1         数学-经
2      1           经济与管理    13              1         英语-经
3      1           经济与管理    14              1        经济学-经
4      2             计算机    21              2         语文-计
5      2             计算机    22              2         数学-计
6      2             计算机    23              2         英语-计
7      2             计算机    24              2        计算机-计
8      3           文学与历史    31              3         语文-文
9      3           文学与历史    32              3         数学-文
10     3           文学与历史    33              3         英语-文
11     3           文学与历史    34              3        世界史-文
12     4             挖掘机    41              4         语文-挖
13     4             挖掘机    42              4         数学-挖
14     4             挖掘机    43              4         英语-挖
15     4             挖掘机    44              4      挖掘机实操-挖
    '''
    # 02 查看学生各科成绩(需要借助中间表:成绩表)(多对多)
    df_student_course_score = pd.merge(pd.merge(student, score, left_on="id", right_on="student_id", how="inner"),
                                       course, left_on="course_id", right_on="id", how="inner")
    print(df_student_course_score)
    '''
         id_x student_name  id_y  student_id  course_id  exams_date  score_total  id  profession_id subject_name
0     101         小明-经     7         101         11  2022-02-11         77.0  11              1         语文-经
1     101         小明-经   103         101         11  2022-02-22         77.0  11              1         语文-经
2     101         小明-经   199         101         11  2022-02-15         77.0  11              1         语文-经
3     101         小明-经   295         101         11  2022-03-08         77.0  11              1         语文-经
4     101         小明-经   391         101         11  2022-03-14         77.0  11              1         语文-经
..    ...          ...   ...         ...        ...         ...          ...  ..            ...          ...
475   416         王五-挖   102         416         44  2022-02-11         90.0  44              4      挖掘机实操-挖
476   416         王五-挖   198         416         44  2022-02-22         90.0  44              4      挖掘机实操-挖
477   416         王五-挖   294         416         44  2022-02-15         90.0  44              4      挖掘机实操-挖
478   416         王五-挖   390         416         44  2022-03-08         90.0  44              4      挖掘机实操-挖
479   416         王五-挖   486         416         44  2022-03-14         90.0  44              4      挖掘机实操-挖
    '''
 
代码

字段重复会默认加后缀,也可以通过suffixes手动设置

  # 字段重复会默认加后缀,也可以通过suffixes手动设置
    df_student_course_score = pd.merge(
        pd.merge(student, score, left_on="id", right_on="student_id", how="inner", suffixes=('_学生', '_成绩')),
        course, left_on="course_id", right_on="id", how="inner", suffixes=('_成绩', '_课程'))
    print(df_student_course_score)
    """
         id_学生 student_name  id_成绩  student_id  course_id  exams_date  score_total  id  profession_id subject_name
0      101         小明-经      7         101         11  2022-02-11         77.0  11              1         语文-经
    """
View Code

2.3 Merge时表之间的连接的区别

  1. inner join(内连接)默认的连接方式,当key两个表都存在的时候才作为返回表的key
  2. left join(左连接)左边所有的key都会作为返回表的key,而右边针对这一key没有对应值则填充Null
  3. right join(右连接)与左连接相反,右边的所有key都会出现在返回的表中,如果左边没有相应的则填充Null
  4. outer join(外连接)左右两边的key都会出现在返回表中,如果没有对应值,则填充Null

 

def join_way():
    left = pd.DataFrame({
        'key': ['K0', 'K1', 'K2', 'K3'],
        'A': ['A0', 'A1', 'A2', 'A3'],
        'B': ['B0', 'B1', 'B2', 'B3'],
    })
    right = pd.DataFrame({
        'key': ['K0', 'K1', 'K4', 'K5'],
        'C': ['C0', 'C1', 'C4', 'C5'],
        'D': ['D0', 'D1', 'D4', 'D5'],
    })
    print(left)
    """
      key   A   B
    0  K0  A0  B0
    1  K1  A1  B1
    2  K2  A2  B2
    3  K3  A3  B3
    """
    print(right)
    """  
      key   C   D
    0  K0  C0  D0
    1  K1  C1  D1
    2  K4  C4  D4
    3  K5  C5  D5
    """
    # inner join(内连接)默认的连接方式,当key两个表都存在的时候才作为返回表的key
    inner_join = pd.merge(left, right, how="inner")
    print(inner_join)
    """
      key   A   B   C   D
    0  K0  A0  B0  C0  D0
    1  K1  A1  B1  C1  D1
    """
    # left join(左连接)左边所有的key都会作为返回表的key,而右边针对这一key没有对应值则填充Null
    left_join = pd.merge(left, right, how="left")
    print(left_join)
    """
      key   A   B    C    D
    0  K0  A0  B0   C0   D0
    1  K1  A1  B1   C1   D1
    2  K2  A2  B2  NaN  NaN
    3  K3  A3  B3  NaN  NaN
    """
    # right join(右连接)与左连接相反,右边的所有key都会出现在返回的表中,如果左边没有相应的则填充Null
    right_join = pd.merge(left, right, how="right")
    print(right_join)
    """
      key    A    B   C   D
    0  K0   A0   B0  C0  D0
    1  K1   A1   B1  C1  D1
    2  K4  NaN  NaN  C4  D4
    3  K5  NaN  NaN  C5  D5
    """
    # outer join(外连接)左右两边的key都会出现在返回表中,如果没有对应值,则填充Null
    outer_join = pd.merge(left, right, how="outer")
    print(outer_join)
    """
      key    A    B    C    D
    0  K0   A0   B0   C0   D0
    1  K1   A1   B1   C1   D1
    2  K2   A2   B2  NaN  NaN
    3  K3   A3   B3  NaN  NaN
    4  K4  NaN  NaN   C4   D4
    5  K5  NaN  NaN   C5   D5
    """
join类型

三、concat

 

Pandas实现数据的合并concat

使用场景:批量合并相同格式的Excel、给DataFrame添加行或列

官方文档1官方文档2官方文档之append

3.1 concat

concat语法(按照轴向合并pandas对象)

  • pandas.concat(objs, axis=0, join='outer', ignore_index=False)
  1. objs:一个列表,内容可以是DataFrame或者Series,可以混合
  2. axis:默认是0代表按行合并,如果等于1代表按列合并
  3. join:合并的时候索引的对齐方式,默认是outer join,也可以是inner join
  4. ignore_index:是否忽略掉原来的数据索引

一言以蔽之:
  使用某种合并方式(inner/outer)
  沿着某个轴向(axis=0/1)
  把多个Pandas对象(DataFrame/Series)合并成一个

def test_concat():
    # 一、使用pandas.concat合并数据
    df1 = pd.DataFrame({
        'A': ['A0', 'A1', 'A2', 'A3'],
        'B': ['B0', 'B1', 'B2', 'B3'],
        'C': ['C0', 'C1', 'C2', 'C3'],
        'D': ['D0', 'D1', 'D2', 'D3'],
        'E': ['E0', 'E1', 'E2', 'E3'],
    })
    df2 = pd.DataFrame({
        'A': ['A4', 'A5', 'A6', 'A7'],
        'B': ['B4', 'B5', 'B6', 'B7'],
        'C': ['C4', 'C5', 'C6', 'C7'],
        'D': ['D4', 'D5', 'D6', 'D7'],
        'F': ['F4', 'F5', 'F6', 'F7'],
    })
    print(df1)
    print(df2)
    """
        A   B   C   D   E
    0  A0  B0  C0  D0  E0
    1  A1  B1  C1  D1  E1
    2  A2  B2  C2  D2  E2
    3  A3  B3  C3  D3  E3
    
        A   B   C   D   F
    0  A4  B4  C4  D4  F4
    1  A5  B5  C5  D5  F5
    2  A6  B6  C6  D6  F6
    3  A7  B7  C7  D7  F7
    """
    # 1:默认的concat,参数为axis=0,join=outer,ignore_index=False
    df_result_1 = pd.concat([df1, df2])
    print(df_result_1)
    """
        A   B   C   D    E    F
    0  A0  B0  C0  D0   E0  NaN
    1  A1  B1  C1  D1   E1  NaN
    2  A2  B2  C2  D2   E2  NaN
    3  A3  B3  C3  D3   E3  NaN
    0  A4  B4  C4  D4  NaN   F4
    1  A5  B5  C5  D5  NaN   F5
    2  A6  B6  C6  D6  NaN   F6
    3  A7  B7  C7  D7  NaN   F7
    """
    # 2:使用 ignore_index=False 忽略掉原来的数据索引
    df_result_2 = pd.concat([df1, df2], ignore_index=True)
    print(df_result_2)
    """
        A   B   C   D    E    F
    0  A0  B0  C0  D0   E0  NaN
    1  A1  B1  C1  D1   E1  NaN
    2  A2  B2  C2  D2   E2  NaN
    3  A3  B3  C3  D3   E3  NaN
    4  A4  B4  C4  D4  NaN   F4
    5  A5  B5  C5  D5  NaN   F5
    6  A6  B6  C6  D6  NaN   F6
    7  A7  B7  C7  D7  NaN   F7
    """
    # 3:使用 join:过滤匹配不到的列
    df_result_3 = pd.concat([df1, df2], join="inner", ignore_index=True)
    print(df_result_3)
    """
        A   B   C   D
    0  A0  B0  C0  D0
    1  A1  B1  C1  D1
    2  A2  B2  C2  D2
    3  A3  B3  C3  D3
    0  A4  B4  C4  D4
    1  A5  B5  C5  D5
    2  A6  B6  C6  D6
    3  A7  B7  C7  D7
    """
    # 4_1:添加一列Series
    s1 = pd.Series(list(range(4)), name="F")
    df_result_4_1 = pd.concat([df1, s1], axis=1)
    print(df_result_4_1)
    """
        A   B   C   D   E  F
    0  A0  B0  C0  D0  E0  0
    1  A1  B1  C1  D1  E1  1
    2  A2  B2  C2  D2  E2  2
    3  A3  B3  C3  D3  E3  3
    """
    # 4_2:添加多列Series
    s2 = df1.apply(lambda x: x["A"] + "_GG", axis=1)
    s2.name = "G"
    df_result_4_2 = pd.concat([s1, df1, s2], axis=1)  # 列表顺序随意的
    print(df_result_4_2)
    """
       F   A   B   C   D   E      G
    0  0  A0  B0  C0  D0  E0  A0_GG
    1  1  A1  B1  C1  D1  E1  A1_GG
    2  2  A2  B2  C2  D2  E2  A2_GG
    3  3  A3  B3  C3  D3  E3  A3_GG
    """
    df_result_4_3 = pd.concat([s1, s2], axis=1)  # 列表内容可以只有Series
    print(df_result_4_3)
    """
       F      G
    0  0  A0_GG
    1  1  A1_GG
    2  2  A2_GG
    3  3  A3_GG
    """
代码

3.2 append(不建议使用)

真香警告:FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.

大概意思是:后期不在支持append语法,建议使用concat。

append语法

  • pandas.concat(objs, axis=0, join='outer', ignore_index=False)
  1. other:单个dataframe、series、dict,或者列表
  2. ignore_index:是否忽略掉原来的数据索引
def test_append():
    # 二、使用pandas.concat合并数据
    # FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead
    df1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
    df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))

    # 1:给一个DataFrame添加一个DataFrame
    df_result_1 = df1.append(df2, ignore_index=True)  # 建议用:df_result_1 = pd.concat([df1, df2], ignore_index=True)
    print(df_result_1)
    """
       A  B
    0  1  2
    1  3  4
    2  5  6
    3  7  8
    """
代码

 

标签:11,02,17,16,id,2022,饮冰,80,Pandas
From: https://www.cnblogs.com/YK2012/p/16789386.html

相关文章