数据集成变换与规约1

Posted 山城棒棒儿军

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据集成变换与规约1相关的知识,希望对你有一定的参考价值。

目录

本博客所涉及的jupyter notebook及数据资料请在百度网盘下载

6. 1 数据集成

6.1.1 数据集成概述

数据分析中需要的数据往往来自不同的途径,这些数据的格式、特点、质量千差万别,给数据分析或挖掘增加了难度。为提高数据分析的效率,多个数据源的数据需要合并到一个数据源,形成一致的数据存储,这一过程就是数据集成

在数据集成期间可能会面临很多问题,包括实体识别冗余属性识别元组重复数据值冲突等问题!

  • 实体识别:
    实体识别指从不同数据源中识别出现实世界的实体,主要用于统一不同数据源的矛盾之处,常见的矛盾包括同名异义、异名同义、单位不统一等!

  • 冗余属性识别:
    冗余属性是数据集成期间极易产生的问题,这一问题主要是因为同一属性多次出现、同一属性命名方式不一致造成的。

  • 元组重复:
    元组重复是数据集成期间另一个容易产生的数据冗余问题,这一问题主要是因为录入错误或未及时更新造成的。

由于存在如上问题,数据集成之后可能需要经过数据清理,以便清除可能存在的实体识别、冗余属性识别和元组重复问题。

pandas中有关数据集成的操作是合并数据,并为该操作提供了丰富的函数或方法。

6.1.2 合并数据

6.1.2.1 pandas中用于合并数据的函数与方法

pandas中内置了许多能轻松地合并数据的函数与方法,通过这些函数与方法可以将Series类对象或DataFrame类对象进行符合各种逻辑关系的合并操作,合并后生成一个整合的Series或DataFrame类对象

6.1.2.2 主键合并

主键合并数据类似于关系型数据库的连接操作,主要通过指定一个或多个键将两组数据进行连接,通常以两组数据中重复的列索引为合并键。

6.1.2.2.1 pd.merger()
  • pd.merge()的语法格式
pd.merge(left,   # 待合并的2个数据框                 
            right,                    
            how='inner',  # ‘left’, ‘right’, ‘outer’, ‘inner’, ‘cross’                 
            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)                    
  • 参数的具体解释为

    • left、right:表示参与合并的Series类对象或DataFrame类对象

    • how:数据合并的方式,有5种:‘left’, ‘right’, ‘outer’, ‘inner’, ‘cross’, 默认是 ‘inner’

      • 1、left:左连接,保留left的全部数据,类比于SQL的left join;

      • 2、right:右连接,保留right的全部数据,类比于SQL的right join

      • 3、outer:全连接功能,left与right的数据都将被保留,类似SQL的full outer join

      • 4、inner:基于left合right的共有键的交叉连接,类比于SQL的inner join

      • 5、cross:创建两个数据帧DataFrame的笛卡尔积,默认保留左边的顺序

    • on:连接的列属性;默认是两个DataFrame的相同字段

    • left_on/right_on:指定两个不同的键进行联结

    • left_index、right_index:通过索引进行合并

    • suffixes:指定我们自己想要的后缀

    • indictor:显示字段的来源

  • pd.merge()实例:

# 模拟数据
import pandas as pd
df_left = pd.DataFrame('key':['K0','K1','K2','K4'],
                             'A':['A0','A1','A2','A3'],
                             'B':['B0','B1','B2','B3'])
df_right = pd.DataFrame('key':['K0','K1','K2','K3'],
                              'C':['C0','C1','C2','C3'],
                              'D':['D0','D1','D2','D3'])
df_left
keyAB
0K0A0B0
1K1A1B1
2K2A2B2
3K4A3B3
df_right
keyCD
0K0C0D0
1K1C1D1
2K2C2D2
3K3C3D3

1. 内连接----共有键部分的连接

# 以key为主键,采用内连接的方式合并数据
result = pd.merge(df_left, df_right, on='key',how='inner')
result
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2

图解过程如下:

  • 两个数据框df_left、df_right有相同的字段key
  • 默认是通过相同的字段(键)进行关联,取出键中相同的值(K0,K1,K2),若每个键的记录要全部显示
# 默认参数情况下的连接及为内连接
result = pd.merge(df_left,df_right)
result
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2
# 也可以采用dataFrame对象的方法的方式调用
df_left.merge(df_right)
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2

2. 左外连接----以左数据为主,保留左侧全部的连接

# 以key为主键,采用左外连接的方式合并数据
result = pd.merge(df_left, df_right, on='key', how='left')
result
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2
3K4A3B3NaNNaN
# 类似的
result = df_left.merge(df_right,on='key',how='left')
result
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2
3K4A3B3NaNNaN

图解过程如下:

  • 以左边数据框中的键(K0,K1,K2,K4)为基准;
  • 如果左边存在(K4)但是右边不存在(K4),则右边用NaN表示

3. 右外连接----以右数据为主,保留右侧全部的连接

# 以key为主键,采用右外连接的方式合并数据
result = pd.merge(df_left, df_right, on='key', how='right')
result
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2
3K3NaNNaNC3D3

图解过程如下:

  • 以右边数据框中的键(K0,K1,K2,K3)为基准;
  • 如果右边存在(K3)但是右边不存在(K3),则左边用NaN表示

4. 全外连接----左右两侧数据都完全保留的连接

# 以key为主键,采用全外连接的方式合并数据
result = pd.merge(df_left, df_right, on='key', how='outer')
result
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2
3K4A3B3NaNNaN
4K3NaNNaNC3D3

图解过程如下:
outer称之为外连接,在拼接的过程中会取两个数据框中键的并集进行拼接

  • 外连接,取出全部交集键的并集。例子中是user的并集
  • 如果某个键在某个数据框中不存在数据,则为NaN

5. 笛卡尔积----两个数据框中的数据交叉匹配,出现n1*n2的数据量

# 以key为主键,采用笛卡尔积连接的方式合并数据
result = pd.merge(df_left, df_right, how='cross')
print(result)
   key_x   A   B key_y   C   D
0     K0  A0  B0    K0  C0  D0
1     K0  A0  B0    K1  C1  D1
2     K0  A0  B0    K2  C2  D2
3     K0  A0  B0    K3  C3  D3
4     K1  A1  B1    K0  C0  D0
5     K1  A1  B1    K1  C1  D1
6     K1  A1  B1    K2  C2  D2
7     K1  A1  B1    K3  C3  D3
8     K2  A2  B2    K0  C0  D0
9     K2  A2  B2    K1  C1  D1
10    K2  A2  B2    K2  C2  D2
11    K2  A2  B2    K3  C3  D3
12    K4  A3  B3    K0  C0  D0
13    K4  A3  B3    K1  C1  D1
14    K4  A3  B3    K2  C2  D2
15    K4  A3  B3    K3  C3  D3

笛卡尔积的图解过程如下:

  • 出现的数据量是4*2,userid下面的数据交叉匹配
  • 在最终结果中相同的字段userid为了避免混淆,会带上默认的后缀_x、_y
6.1.2.2.2 pd.merge_ordered()

使用可选的填充/插值对有序数据执行合并。专为时间序列数据等有序数据而设计。

  • pd.merge_ordered()语法格式:
 pandas.merge_ordered(left, 
                right, 
                on=None, 
                left_on=None, 
                right_on=None, 
                left_by=None, 
                right_by=None, 
                fill_method=None, 
                suffixes=('_x', '_y'), 
                how='outer')
  • 参数解释:

    • left: 用于连接的 左DataFrame

    • right: 用于连接的 右DataFrame

    • on: 连接关键字。必须 同时存在于 左DataFrame、右DataFrame

    • left_on: 左DataFrame 中用于连接的关键字

    • right_on: 右DataFrame 中用于连接的关键字

    • left_by: 对 左DataFrame 进行分组的关键字

    • right_by: 对 右DataFrame 进行分组的关键字

    • fill_method: 对缺失数据填充的值

    • suffixes: 连接后,同时存在于 左DataFrame、右DataFrame 中的字段,添加的后缀名

    • how: 连接方式。默认为 外连接

  • 注意:

    • 使用参数 on 时,不能同时使用 “left_on” 或 “right_on”

    • left_on 与 right_on 必须同时存在

    • 如果 on、left_on 、right_on 的参数值均为空时,默认以 同时存在于两个 DataFrame 中的列,为连接关键字。
      如果不存在共同列,将会报错:pandas.errors.MergeError: No common columns to perform merge on.

    • left_by 与 right_by 不能同时存在

pd.merge_ordered()实例:

  • 构建实例数据
df1 = pd.DataFrame(
    
        "key": ["a", "c", "e", "a", "c", "e"],
        "lvalue": [1, 2, 3, 1, 2, 3],
        "group": ["a", "a", "a", "b", "b", "b"]
    
)

df2 = pd.DataFrame("key": ["b", "c", "d"], "rvalue": [1, 2, 3])
df1
keylvaluegroup
0a1a
1c2a
2e3a
3a1b
4c2b
5e3b
df2 
keyrvalue
0b1
1c2
2d3
# df1                         df2
#   key    lvalue group           key  rvalue
# 0   a       1     a         0   b       1
# 1   c       2     a         1   c       2
# 2   e       3     a         2   d       3
# 3   a       1     b              
# 4   c       2     b              
# 5   e       3     b                    

1. 如果 left_by 与 right_by 均为空,等价于 merge

pd.merge_ordered(df1, df2).sort_values(by=["key", "lvalue"], ignore_index=True)
keylvaluegrouprvalue
0a1.0aNaN
1a1.0bNaN
2bNaNNaN1.0
3c2.0a2.0
4c2.0b2.0
5dNaNNaN3.0
6e3.0aNaN
7e3.0bNaN

等价于如下:

pd.merge(df1, df2, how="outer").sort_values(by=["key", "lvalue"], ignore_index=True) 
keylvaluegrouprvalue
0a1.0aNaN
1a1.0bNaN
2bNaNNaN1.0
3c2.0a2.0
4c2.0b2.0
5dNaNNaN3.0
6e3.0aNaN
7e3.0bNaN

2. 如果 left_by 或 right_by 不为空,会先按这个参数值对 DataFrame 进行分组,将分组后的 DataFrame 再进行连接

pd.merge_ordered(df1, df2, left_by="group")
#第一步:将 df1 根据 group 进行分组
# 第二步:将分组后的 df1 中每一组的数据,通过连接关键字 key 与 df2 进行连接 
keylvaluegrouprvalue
0a1.0aNaN
1bNaNa1.0
2c2.0a2.0
3dNaNa3.0
4e3.0aNaN
5a1.0bNaN
6bNaNb1.0
7c2.0b2.0
8dNaNb3.0
9e3.0bNaN
pd.merge_ordered(df1, df2, right_by="rvalue")
# 第一步:将 df2 根据 rvalue 进行分组
# 第二步:将分组后的 df2 中每一组的数据,通过连接关键字 key 与 df1 进行连接
keylvaluegrouprvalue
0a1.0a1
1a1.0b1
2bNaNNaN1
3c2.0a1
4c2.0b1
5e3.0a1
6e3.0b1
7a1.0a2
8a1.0b2
9c2.0a2
10c2.0b2
11e3.0a2
12e3.0b2
13a1.0a3
14a1.0b3
15c2.0a3
16c2.0b3
17dNaNNaN3
18e3.0a3
19e3.0b3

3. 如果,“left_by 或 right_by 的值” 与 “连接关键字” 相同,那无论是什么连接方式,结果都一样

pd.merge_ordered(df1, df2, left_by="key")
keylvaluegrouprvalue
0a1aNaN
1a1bNaN
2c2a2.0
3c2b2.0
4e3aNaN
5e3bNaN
pd.merge_ordered(df1, df2, left_by="key", how="inner") 
keylvaluegrouprvalue
0a1aNaN
1a1bNaN
2c2a2.0
3c2b2.0
4e3aNaN
5e3bNaN
pd.merge_ordered(df1, df2, left_by="key", how="right")
keylvaluegrouprvalue
0a1aNaN
1a1bNaN
2c2a2.0
3c2b2.0
4e3aNaN
5e3bNaN
6.1.2.2.3 pd.merge_asof()

pandas 的 merge_asof() 类似于有序的LEFT JOIN,只是我们在最近的键上匹配,而不是相等键。

  • pd.merge_asof()语法格式:
pandas.merge_asof(left,
            right,
            on=None, 
            left_on=None, 
            right_on=None, 
            left_index=False, 
            right_index=False, 
            by=None, 
            left_by=None, 
            right_by=None, 
            suffixes=(‘_x’, ‘_y’), 
            tolerance=None, 
            allow_exact_matches=True, 
            direction=’backward’, )
  • 参数说明:

    • left, right: DataFrame
    • on:标签,要加入的字段名称。必须在两个DataFrame中都找到。
    • left_on:标签,要在左侧DataFrame中加入的字段名称。
    • right_on:标签,要在右侧DataFrame中加入的字段名称。
    • left_index:布尔值,使用左侧DataFrame的索引作为连接键。
    • right_index:布尔值,使用正确的DataFrame的索引作为连接键。
  • pd.merge_asof()实例:

# importing package 
import pandas 
  
# creating data 
left = pandas.DataFrame('a':[1, 5, 10],  
                         'left_val':['a', 'b', 'c']) 
  
right = pandas.DataFrame('a':[1, 2, 3, 6, 7], 
                          'right_val':[1, 2, 3, 6, 7]) 
  
# view data 
print(left) 
print(right) 
  
# applying merge_asof on data 
print(pandas.merge_asof(left, right, on='a')) 
print(pandas.merge_asof(left, right, on='a',allow_exact_matches=False))
    a left_val
0   1        a
1   5        b
2  10        c
   a  right_val
0  1          1
1  2          2
2  3          3
3  6          6
4  7          7
    a left_val  right_val
0   1        a          1
1   5        b          3
2  10        c          7
    a left_val  right_val
0   1        a        NaN
1   5        b        3.0
2  10        c        7.0

6.1.2.3 堆叠合并数据

  • dataframe.join(): 根据行索引连接多组数据
  • pd.concat(): 沿着某个轴方向堆叠多组数据
  • dataframe.append(): 向数据末尾追加若干行数据
6.1.2.3.0 构建数据
import pandas as pd
import numpy as np

df1 = pd.DataFrame(
    "姓名":["小明","小红","小周"],
    "年龄":[18,24,20]
)
df1
姓名年龄
0小明18
1小红24
2小周20
df2 = pd.DataFrame(
    "姓名":["小孙","小芳"],
    "年龄":[25,19]
)
df2
姓名年龄
0小孙25
1小芳19
df3 = pd.DataFrame(
    "地址":["深圳","广州","珠海"],
    "成绩":[600,630,598]
)
df3
地址成绩
0深圳600
1广州630
2珠海598
df4 = pd.DataFrame(
    "地址":["深圳","广州","东莞"],
    "爱好":["乒乓球","羽毛球","高尔夫"]
)
df4
地址爱好
0深圳乒乓球
1广州羽毛球
2东莞高尔夫
df5 = pd.DataFrame(
    "地址":["深圳","广州","东莞","上海","北京"],
    "爱好":["乒乓球","羽毛球","高尔夫","跑步","健身"]
)
df5
地址爱好
0深圳乒乓球
1广州羽毛球
2东莞高尔夫
3上海跑步
4北京健身
6.1.2.3.1 pd.concat()

解决两个表或者多个表按照纵向或者横向拼接。

  • pd.concat()的语法格式:
 pandas.concat(objs,  # 合并对象
             axis=0,   # 合并方向,默认是0纵轴方向
             join='outer', # 合并取的是交集inner还是并集outer
             ignore_index=False, # 合并之后索引是否重新
             keys=None, # 在行索引的方向上带上原来数据的名字;主要是用于层次化索引,可以是任意的列表、数组、元组或者列表数组
             levels=None, # 指定用作层次化索引各级别上的索引,如果是设置了keys
             names=None, # 行索引的名字,列表形式
             verify_integrity=False, # 检查行索引是否重复;有则报错
             sort=False, # 对非连接的轴进行排序
             copy=True   # 是否进行深拷贝
            )
  • pd.concat()的参数详细说明:

    • objs:Series,DataFrame或Panel对象的序列或映射。如果传递了dict,则排序的键将用作键参数,除非它被传递,在这种情况下,将选择值(见下文)。任何无对象将被静默删除,除非它们都是无,在这种情况下将引发一个ValueError。
    • axis:0,1,…,默认为0。沿着连接的轴。
    • join:‘inner’,‘outer’,默认为“outer”。如何处理其他轴上的索引。outer为联合和inner为交集。
    • ignore_index:boolean,default False。如果为True,请不要使用并置轴上的索引值。结果轴将被标记为0,…,n-1。如果要连接其中并置轴没有有意义的索引信息的对象,这将非常有用。注意,其他轴上的索引值在连接中仍然受到尊重。
    • join_axes:Index对象列表。用于其他n-1轴的特定索引,而不是执行内部/外部设置逻辑。
    • keys:序列,默认值无。使用传递的键作为最外层构建层次索引。如果为多索引,应该使用元组。
    • levels:序列列表,默认值无。用于构建MultiIndex的特定级别(唯一值)。否则,它们将从键推断。
    • names:list,default无。结果层次索引中的级别的名称。
    • verify_integrity:boolean,default False。检查新连接的轴是否包含重复项。这相对于实际的数据串联可能是非常昂贵的。
    • copy:boolean,default True。如果为False,请勿不必要地复制数据。
  • pd.concat()使用实例: