python:提高 - 数据预处理 - pandas -表的横向合并 纵向合并 merge() concat()

原文链接: https://pandas.pydata.org/pandas-docs/stable/merging.html

《Merge, join, and concatenate》笔记

PS默认情况下,所有合并函数生成文件的方式均是新生成,即不修改原DF/Series数据。


第一、常用的merge()函数、concat()函数:

常用merge()来添加新字段(即列),concat()来添加新记录(即行)

++++++++++ merge() ++++++++++

  • pandas.merge是pandas的全功能、高性能的的内存连接操作,在习惯上非常类似于SQL之类的关系数据库。
  • 相较于其他开源软件(如R中的base::merge.data.frame), pandas.merge的性能要好得多(在某些情况下好得多一个数量级)。其原因是在DataFrame中优化的算法设计和数据的内部布局。
DataFrame.merge(
right,                                    # 右DF,即要被merge的DataFrame
how='inner',                              # 取值有4个{‘left’, ‘right’, ‘outer’, ‘inner’}
on=None, left_on=None, right_on=None,     # 如果使用左&右DF的公共字段作为key,使用参数on;如果不使用左边右边的公共字段作为key,使用参数left_on和right_on。
left_index=False, right_index=False,      # 如果left_index=True,则left左边DF的index(即索引的列名称)是用来jion的keys。如果是MultiIndex,左DF和右DF的level数必须相等。right_index的作用与之相似。
sort=False,                               # 默认不对新合并表的结果按照字顺序排序,可以节省运算时间。
suffixes=('_x', '_y'), 
copy=True, 
indicator=False,                          # 如果True,会添加一列,显示数据的来源表名称。
Validate=None                             # 是否检查两个merge的DFkeys是一对一关系、一对多关系,返回布尔值( 'one_to_one'/ '1:1', 'one_to_many' / '1:m', 'many_to_one' / 'm:1')。默认情况下3种关系都可以,只是没有输出。
)

例子

  • merge两个DataFrame:
>>> A              >>> B
    lkey value         rkey value
0   foo  1         0   foo  5
1   bar  2         1   bar  6
2   baz  3         2   qux  7
3   foo  4         3   bar  8
>>> A.merge(B, left_on='lkey', right_on='rkey', how='outer')
   lkey  value_x  rkey  value_y
0  foo   1        foo   5
1  foo   4        foo   5
2  bar   2        bar   6
3  bar   2        bar   8
4  baz   3        NaN   NaN
5  NaN   NaN      qux   7
  • merge多个DataFrame与之类似,直接向后添加:
A.merge(B, right_on='col_r', left_on='col_l', how='outer').merge(C, right_on='col_r1', left_on='col_l1', how='outer')

注:

  • 截止到2019上半年,merge()函数仍然会合并左右表的NaNNone,详见 GH22491 和GH22618。
  • 假如要删除NaNNone,使用new_df.dropna(subset=['key_or_keys], inplace=True)
"""NaN是float,None是object,虽然都可以在numpy中运行、但是None会把numpy计算性能拉到底,NaN不会。"""
s_bad = pd.Series([1, None], dtype=object)
s_good = pd.Series([1, np.nan])

print(s_bad)
print(s_good)
# 结果如下:
0       1
1    None
dtype: object
0    1.0
1    NaN
dtype: float64

print(s_bad.dropna())
print(s_good.dropna())
# 结果如下
0    1
dtype: object
0    1.0
dtype: float64

print(s_bad.isnull())
print(s_good.isnull())
# 结果如下
0    False
1     True
dtype: bool
0    False
1     True
dtype: bool

++++++++++ concat() ++++++++++

  • 默认按照axis=0执行合并,即默认向df1添加行。
  • 如果df2有df1没有的列,也添加列。

concat()函数一边按照an axis执行所有的复杂合并命令,同时(如果有的话)按其他axes执行运算,还执行参数"join"的设定 innor | outer命令。注意,之所以说“如果有”,是因为Series只有一个axis。

pandas.concat(
objs,                       # 要纵向合并的DataFrame列表。append也有(4个共同参数)
axis=0,                     # axis只能取值0或者1
join='outer',               # join只能取值innor或outer
sort=None,                  # append()也有(共4个共同参数),即默认空白。可取值为False/True,从23.0版本开始,不输入取值的话会收到warning提示,之前的版本中默认sort只等于True。
gnore_index=False,         # append()也有(共4个共同参数)
# 以下参数不太常用
verify_integrity=False,    # append()也有(共4个共同参数)
join_axes=None, keys=None, levels=None, names=None,copy=True)
其他参数(一下不怎么用得到,浏览一下即可):
  • 多个DataFrame的话,多注意 “按axes(即第一个axis之外的axis/axes)的合并”,还有“设置更多条件的合并”(axisjoin进一步有sort操作,且未来的join不再默认执行sort=True,需要主动设置)、
  • join = innor/outer操作的是axis(它其实是实际意义上的index,如果你对该函数较熟悉的话)。
  • 搭配keys合并后的表,可以快速的提取数据,key的对象随axis的取值变化而改变。
  • ignore_index搭配axis:实现用递增的数字,作为新DF的字段名称;
  • 把参数index换成参数join_axes可以实现相当于SQL的left join功能,即只保左边表df1的index。例如result = pd.concat([df1, df4], axis=1, join_axes=[df1.index])


第二、join()函数、append()函数(他俩不常用,仅供了解)

++++++++++ append() ++++++++++
功能:简化版的concat()(实际上比concat诞生的早)。同样是用来处理Dataframe/Series。

DataFrame.append(
other,                       # 其他的对象(Series/DF)
sort=None,                   # 是否排序
ignore_index=False,          # 是否使用原index。取值True会用0,1,2……数字作为index
verify_integrity=False)

附注:一个Series合并到一个DataFrame
如果我们要把一个Series合并到一个DataFrame的话,用DataFrame.assign()可以得到相同的结果。
但是对于任意数量的DataFrame/Series对象,请使用concat()

  • concat()append()通用的:
    – 比如2个表的index一个是[i, ii, iii, iv],一个是[a, b, c, d],通过设定ignore_index=True,即用新的index[0, 1, 2, 3]来添加合并对象。
    -仅适用于 concat()的:
    ignore_index=True搭配axis=1(行名称变成了事实上的Column,列名称反而成了事实上的index),可以在合并结果中用数字序号作为列名称

  • 仅适用于append()的:
    – 直接把一个手写Series 的 或者一个dict 的列集,合并到DataFrame 的后边得到一个新的DF。虽然不是特别有效率(因为函数应用的对象Series/DF需要手工码出来)。
    — e.g. 手写Series类型数据,手写dict类型数据。其结果不容易理解,一般使用merge或者concat:

import pandas as pd

df1 = pd.DataFrame([5, 6, 7, 8], index=['A', 'B', 'C', 'Y'])
print(df1)

s2 = pd.Series(['X0', 'X1', 'X2', 'X3'])
print(s2)

dicts = [{'A': 1, 'B': 2, 'C': 3, 'X': 4},
         {'A': 5, 'B': 6, 'C': 7, 'Y': 8}]
print(dicts)

# 结果如下
   0
A  5
B  6
C  7
Y  8

0    X0
1    X1
2    X2
3    X3
dtype: object

[{'A': 1, 'B': 2, 'C': 3, 'X': 4}, {'A': 5, 'B': 6, 'C': 7, 'Y': 8}]
result = df1.append(s2, ignore_index=True)
print(result)

b = df1.append(dicts, ignore_index=True)
print(b) 

# 结果如下
    0    1    2    3
0   5  NaN  NaN  NaN
1   6  NaN  NaN  NaN
2   7  NaN  NaN  NaN
3   8  NaN  NaN  NaN
4  X0   X1   X2   X3

     0    A    B    C    X    Y
0  5.0  NaN  NaN  NaN  NaN  NaN
1  6.0  NaN  NaN  NaN  NaN  NaN
2  7.0  NaN  NaN  NaN  NaN  NaN
3  8.0  NaN  NaN  NaN  NaN  NaN
4  NaN  1.0  2.0  3.0  4.0  NaN
5  NaN  5.0  6.0  7.0  NaN  8.0

++++++++++ JOIN() ++++++++++
它通过索引或者指定的列把来自其他DaraFrame的列添加到左DF上。
如果只按照索引进行join的话,可以迅速的同时jion多个DataFrame。

DataFrame.join(            # 如果第一个参数"other"传入的是"一个列表的DataFrame",参数"on", "lsuffix", "rsuffix"失效。
other,                     # 要jion的对象,可以是DataFrame、带有名称字段集合的Series、或者一个列表的DataFrame
on=None,                   # 指明join使用的column(s)。系统默认使用index。
how='left',                # 取值有4个{'left', 'right', 'outer', 'inner'}。默认值是'left'。
lsuffix='',                
rsuffix='',
sort=False                  # 默认False,即保留左DF的排序。True则按join的列对生成的DF进行排序
)

例子:
new_df = left.join(right, on=key_or_keys)

  • 等价于 new_df = pd.merge(left, right, left_on=key_or_keys, right_index=True, how='left', sort=False)
  • 还等价于new_df = left.merge(right, on=key_or_keys, how='left')

附注: join和merge有什么异同?stackoverflow链接
- pandas.merge()是所有用来merge/join的底层函数。

DataFrame提供了pandas.DataFrame.merge()pandas.DataFrame.join()作为使用pandas.merge()的快捷方式。
例如df1.merge(right=df2, ...),也即pandas.merge(left=df1, right=df2, ...)

- 不同点:df.join()df.merge()主要有三处不同
  1. 左连接 VS 内连接:df1.join(df2)默认使用左连接 保留左表df1的所有行,但是df.merge(df1, df2)默认使用内连接 保留df1df2共有的行。
  2. 如果需要从右表拉数据的话:默认情况,df1.join(df2)只能用df2的index,但是df1.merge(df2)即可以用df2的单列/多列,也可以通过right_index=True使用df2的index;
  3. 如果需要从左表拉数据的话:代码df1.join(df2, on=key_or_keys)df1.merge(df2, left_index=True)。默认情况,df1.join(df2)使用df1的index,同样df1.merge(df2)用的是df2的(单列的/多列的)index,;
杂项(待查证续写):DataFrame.assign()和map()

两者都能按照行名称匹配出新的一列。

  • map()在知道所有映射关系后,能方便快捷的匹配映射数据。
  • 貌似有很多路径可以实现类似EXCEL的VLOOKUP功能。

你可能感兴趣的:(python:数据预处理)