Sáp nhập 101


364
  • Làm thế nào để thực hiện một ( LEFT| RIGHT| FULL) ( INNER| OUTER) tham gia với gấu trúc?
  • Làm cách nào để thêm NaN cho các hàng bị thiếu sau khi hợp nhất?
  • Làm cách nào để loại bỏ NaN sau khi hợp nhất?
  • Tôi có thể hợp nhất vào chỉ mục không?
  • Tham gia chéo với gấu trúc?
  • Làm cách nào để hợp nhất nhiều DataFrames?
  • merge? join? concat? update? WHO? Gì? Tại sao?!

... và hơn thế nữa. Tôi đã thấy những câu hỏi định kỳ này hỏi về các khía cạnh khác nhau của chức năng hợp nhất gấu trúc. Hầu hết các thông tin liên quan đến hợp nhất và các trường hợp sử dụng khác nhau của nó ngày nay bị phân tán trên hàng chục bài viết không được tìm kiếm, không được tìm kiếm. Mục đích ở đây là đối chiếu một số điểm quan trọng hơn cho hậu thế.

QnA này có nghĩa là phần tiếp theo trong một loạt các hướng dẫn sử dụng hữu ích về các thành ngữ gấu trúc thông thường (xem bài đăng này về xoay vòng , và bài đăng này về ghép nối , mà tôi sẽ tiếp tục, sau này).

Xin lưu ý rằng bài đăng này không có nghĩa là một sự thay thế cho tài liệu , vì vậy xin vui lòng đọc nó là tốt! Một số ví dụ được lấy từ đó.

Câu trả lời:


519

Bài đăng này nhằm mục đích cung cấp cho độc giả một bản tóm tắt về việc hợp nhất hương vị SQL với gấu trúc, cách sử dụng và khi không sử dụng nó.

Cụ thể, đây là những gì bài đăng này sẽ trải qua:

  • Khái niệm cơ bản - các loại liên kết (TRÁI, PHẢI, NGOÀI, VÀO)

    • hợp nhất với các tên cột khác nhau
    • tránh cột khóa hợp nhất trùng lặp trong đầu ra
  • Sáp nhập với chỉ số trong các điều kiện khác nhau
    • sử dụng hiệu quả chỉ mục được đặt tên của bạn
    • hợp nhất khóa là chỉ mục của một và cột khác
  • Multiway hợp nhất trên các cột và chỉ mục (duy nhất và không duy nhất)
  • Các lựa chọn thay thế đáng chú ý đến mergejoin

Những gì bài đăng này sẽ không đi qua:

  • Các cuộc thảo luận và thời gian liên quan đến hiệu suất (bây giờ). Chủ yếu là đề cập đáng chú ý của các lựa chọn thay thế tốt hơn, bất cứ nơi nào thích hợp.
  • Xử lý hậu tố, loại bỏ các cột bổ sung, đổi tên đầu ra và các trường hợp sử dụng cụ thể khác. Có những bài viết khác (đọc: tốt hơn) giải quyết vấn đề đó, vì vậy hãy tìm ra nó!

Lưu ý
Hầu hết các ví dụ mặc định cho các hoạt động INNER THAM GIA trong khi thể hiện các tính năng khác nhau, trừ khi có quy định khác.

Hơn nữa, tất cả các DataFram ở đây có thể được sao chép và sao chép để bạn có thể chơi với chúng. Ngoài ra, hãy xem bài đăng này về cách đọc DataFrames từ khay nhớ tạm của bạn.

Cuối cùng, tất cả các biểu diễn trực quan của các hoạt động THAM GIA đã được vẽ bằng tay bằng Google Drawings. Cảm hứng từ đây .

Nói đủ rồi, chỉ cho tôi cách sử dụng merge!

Thiết lập

np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})    
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})

left

  key     value
0   A  1.764052
1   B  0.400157
2   C  0.978738
3   D  2.240893

right

  key     value
0   B  1.867558
1   D -0.977278
2   E  0.950088
3   F -0.151357

Để đơn giản, cột khóa có cùng tên (bây giờ).

Một bên tham gia được đại diện bởi

Lưu ý
Điều này, cùng với các số liệu sắp tới đều tuân theo quy ước này:

  • màu xanh biểu thị các hàng có mặt trong kết quả hợp nhất
  • màu đỏ biểu thị các hàng được loại trừ khỏi kết quả (nghĩa là đã bị xóa)
  • màu xanh lá cây biểu thị các giá trị bị thiếu được thay thế bằng NaN trong kết quả

Để thực hiện INNER THAM GIA, hãy gọi mergeDataFrame bên trái, chỉ định DataFrame bên phải và khóa tham gia (ít nhất là) làm đối số.

left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278

Điều này chỉ trả về các hàng từ leftrightchia sẻ một khóa chung (trong ví dụ này là "B" và "D).

MỘT THAM GIA TRÁI PHIẾU , hoặc THAM GIA TRÁI được đại diện bởi

Điều này có thể được thực hiện bằng cách chỉ định how='left'.

left.merge(right, on='key', how='left')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278

Lưu ý cẩn thận vị trí của NaNs ở đây. Nếu bạn chỉ định how='left', thì chỉ các khóa từ leftđược sử dụng và dữ liệu bị thiếu rightđược thay thế bằng NaN.

Và tương tự, đối với THAM GIA RIGHT OUTER , hoặc RIGHT THAM GIA là ...

... ghi rõ how='right':

left.merge(right, on='key', how='right')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278
2   E       NaN  0.950088
3   F       NaN -0.151357

Tại đây, các khóa từ rightđược sử dụng và dữ liệu bị thiếu leftđược thay thế bằng NaN.

Cuối cùng, đối với FULL OUTER THAM GIA , được đưa ra bởi

ghi rõ how='outer'.

left.merge(right, on='key', how='outer')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278
4   E       NaN  0.950088
5   F       NaN -0.151357

Điều này sử dụng các khóa từ cả hai khung và NaN được chèn cho các hàng bị thiếu trong cả hai.

Các tài liệu tóm tắt những sự hợp nhất khác nhau độc đáo:

nhập mô tả hình ảnh ở đây

THAM GIA khác - Không bao gồm, loại trừ, loại trừ và loại trừ hoàn toàn / loại trừ ANTI

Nếu bạn cần THAM GIA TRÁI PHẢIloại trừ THAM GIA trong hai bước.

Đối với THAM GIA TRÁI PHIẾU, được trình bày dưới dạng

Bắt đầu bằng cách thực hiện LEFT OUTER THAM GIA và sau đó lọc (không bao gồm!) Các hàng chỉ đến từ left,

(left.merge(right, on='key', how='left', indicator=True)
     .query('_merge == "left_only"')
     .drop('_merge', 1))

  key   value_x  value_y
0   A  1.764052      NaN
2   C  0.978738      NaN

Ở đâu,

left.merge(right, on='key', how='left', indicator=True)

  key   value_x   value_y     _merge
0   A  1.764052       NaN  left_only
1   B  0.400157  1.867558       both
2   C  0.978738       NaN  left_only
3   D  2.240893 -0.977278       both

Và tương tự, đối với THAM GIA QUYỀN, không bao gồm THAM GIA,

(left.merge(right, on='key', how='right', indicator=True)
     .query('_merge == "right_only"')
     .drop('_merge', 1))

  key  value_x   value_y
2   E      NaN  0.950088
3   F      NaN -0.151357

Cuối cùng, nếu bạn được yêu cầu thực hiện hợp nhất chỉ giữ lại các khóa từ bên trái hoặc bên phải, nhưng không phải cả hai (IOW, thực hiện ANTI-THAM GIA ),

Bạn có thể làm điều này trong thời trang tương tự

(left.merge(right, on='key', how='outer', indicator=True)
     .query('_merge != "both"')
     .drop('_merge', 1))

  key   value_x   value_y
0   A  1.764052       NaN
2   C  0.978738       NaN
4   E       NaN  0.950088
5   F       NaN -0.151357

Tên khác nhau cho các cột quan trọng

Nếu các cột chính được đặt tên khác nhau ví dụ, leftkeyLeft, và rightkeyRightthay vì key-Sau đó bạn sẽ phải chỉ định left_onright_onnhư các đối số thay vì on:

left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)

left2

  keyLeft     value
0       A  1.764052
1       B  0.400157
2       C  0.978738
3       D  2.240893

right2

  keyRight     value
0        B  1.867558
1        D -0.977278
2        E  0.950088
3        F -0.151357

left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')

  keyLeft   value_x keyRight   value_y
0       B  0.400157        B  1.867558
1       D  2.240893        D -0.977278

Tránh cột khóa trùng lặp trong đầu ra

Khi hợp nhất keyLefttừ leftkeyRighttừ right, nếu bạn chỉ muốn một trong hai keyLefthoặc keyRight(nhưng không phải cả hai) trong đầu ra, bạn có thể bắt đầu bằng cách đặt chỉ mục làm bước sơ bộ.

left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')

    value_x keyRight   value_y
0  0.400157        B  1.867558
1  2.240893        D -0.977278

Tương phản điều này với đầu ra của lệnh ngay trước đó (thứ là, đầu ra của left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')), bạn sẽ thấy keyLeftthiếu. Bạn có thể tìm ra cột nào cần giữ dựa trên chỉ mục của khung nào được đặt làm khóa. Điều này có thể quan trọng khi, giả sử, thực hiện một số thao tác OUTER THAM GIA.

Hợp nhất chỉ một cột từ một trong các DataFrames

Ví dụ, xem xét

right3 = right.assign(newcol=np.arange(len(right)))
right3
  key     value  newcol
0   B  1.867558       0
1   D -0.977278       1
2   E  0.950088       2
3   F -0.151357       3

Nếu bạn được yêu cầu chỉ hợp nhất "new_val" (không có bất kỳ cột nào khác), bạn thường chỉ có thể đặt các cột con trước khi hợp nhất:

left.merge(right3[['key', 'newcol']], on='key')

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

Nếu bạn đang thực hiện TRÁI PHIẾU TRÁI PHIẾU, một giải pháp hiệu quả hơn sẽ liên quan đến map:

# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

Như đã đề cập, điều này tương tự, nhưng nhanh hơn

left.merge(right3[['key', 'newcol']], on='key', how='left')

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

Sáp nhập trên nhiều cột

Để tham gia vào nhiều hơn một cột, xác định một danh sách cho on(hoặc left_onright_on, nếu thích hợp).

left.merge(right, on=['key1', 'key2'] ...)

Hoặc, trong trường hợp tên khác nhau,

left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])

Các merge*hoạt động và chức năng hữu ích khác

Phần này chỉ bao gồm những điều cơ bản, và được thiết kế để chỉ kích thích sự thèm ăn của bạn. Để biết thêm các ví dụ và các trường hợp, xem tài liệu hướng dẫn trên merge, joinconcat cũng như các liên kết đến các thông số kỹ thuật chức năng.


Dựa trên chỉ mục * -JOIN (+ cột chỉ mục merge)

Thiết lập

np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])    
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'

left
           value
idxkey          
A      -0.602923
B      -0.402655
C       0.302329
D      -0.524349

right

           value
idxkey          
B       0.543843
D       0.013135
E      -0.326498
F       1.385076

Thông thường, một sự hợp nhất trên chỉ mục sẽ trông như thế này:

left.merge(right, left_index=True, right_index=True)


         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Hỗ trợ tên chỉ mục

Nếu chỉ số của bạn được đặt tên, sau đó v0.23 người dùng cũng có thể chỉ định tên cấp để on(hoặc left_onright_onkhi cần thiết).

left.merge(right, on='idxkey')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Sáp nhập vào chỉ mục của một, cột (s) của người khác

Có thể (và khá đơn giản) để sử dụng chỉ mục của một và cột của người khác, để thực hiện hợp nhất. Ví dụ,

left.merge(right, left_on='key1', right_index=True)

Hoặc ngược lại ( right_on=...left_index=True).

right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2

  colkey     value
0      B  0.543843
1      D  0.013135
2      E -0.326498
3      F  1.385076

left.merge(right2, left_index=True, right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

Trong trường hợp đặc biệt này, chỉ mục cho leftđược đặt tên, vì vậy bạn cũng có thể sử dụng tên chỉ mục với left_on, như sau:

left.merge(right2, left_on='idxkey', right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

DataFrame.join
Bên cạnh đó, có một lựa chọn cô đọng khác. Bạn có thể sử dụng DataFrame.joinmặc định để tham gia vào chỉ mục. DataFrame.joinkhông có THAM GIA TRÊN THAM GIA theo mặc định, vì vậy how='inner'cần thiết ở đây.

left.join(right, how='inner', lsuffix='_x', rsuffix='_y')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Lưu ý rằng tôi cần chỉ định lsuffixvà các rsuffixđối số vì joinnếu không sẽ xảy ra lỗi:

left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')

Vì các tên cột là như nhau. Điều này sẽ không thành vấn đề nếu chúng được đặt tên khác.

left.rename(columns={'value':'leftvalue'}).join(right, how='inner')

        leftvalue     value
idxkey                     
B       -0.402655  0.543843
D       -0.524349  0.013135

pd.concat
Cuối cùng, để thay thế cho các phép nối dựa trên chỉ mục, bạn có thể sử dụng pd.concat:

pd.concat([left, right], axis=1, sort=False, join='inner')

           value     value
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Bỏ qua join='inner'nếu bạn cần THAM GIA HOÀN TOÀN (mặc định):

pd.concat([left, right], axis=1, sort=False)

      value     value
A -0.602923       NaN
B -0.402655  0.543843
C  0.302329       NaN
D -0.524349  0.013135
E       NaN -0.326498
F       NaN  1.385076

Để biết thêm thông tin, hãy xem bài viết kinh điển này trên pd.concat@piRSquared .


Tổng quát hóa: mergeing nhiều DataFrames

Thông thường, tình huống phát sinh khi nhiều DataFrames được hợp nhất với nhau. Ngây thơ, điều này có thể được thực hiện bằng cách mergegọi các chuỗi :

df1.merge(df2, ...).merge(df3, ...)

Tuy nhiên, điều này nhanh chóng vượt khỏi tầm tay của nhiều DataFrames. Hơn nữa, có thể cần phải khái quát hóa cho một số lượng DataFram không xác định.

Ở đây tôi giới thiệu pd.concatvề các phép nối đa chiều trên các phím duy nhấtDataFrame.joincho các phép nối đa chiều trên các phím không duy nhất . Đầu tiên, thiết lập.

# Setup.
np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})    
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C] 

# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')

dfs2 = [A2, B2, C2]

Hợp nhất nhiều đường trên các khóa duy nhất (hoặc chỉ mục)

Nếu các khóa của bạn (ở đây, khóa có thể là một cột hoặc một chỉ mục) là duy nhất, thì bạn có thể sử dụng pd.concat. Lưu ý rằng pd.concattham gia DataFrames trên chỉ mục .

# merge on `key` column, you'll need to set the index before concatenating
pd.concat([
    df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# merge on `key` index
pd.concat(dfs2, axis=1, sort=False, join='inner')

       valueA    valueB  valueC
key                            
D    2.240893 -0.977278     1.0

Bỏ qua join='inner'cho một THAM GIA HOÀN TOÀN. Lưu ý rằng bạn không thể chỉ định tham gia LEFT hoặc RIGHT OUTER (nếu bạn cần những thứ này, hãy sử dụng join, được mô tả bên dưới).

Multiway hợp nhất trên các khóa với các bản sao

concatlà nhanh, nhưng có những thiếu sót của nó. Nó không thể xử lý các bản sao.

A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})

pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)

Trong tình huống này, chúng ta có thể sử dụng joinvì nó có thể xử lý các khóa không duy nhất (lưu ý rằng jointham gia DataFrames trên chỉ mục của chúng; nó gọi mergebên dưới mui xe và thực hiện TRÁI PHIẾU TRÁI PHIẾU trừ khi có quy định khác).

# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
    [df.set_index('key') for df in (B, C)], how='inner').reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# join on `key` index
A3.set_index('key').join([B2, C2], how='inner')

       valueA    valueB  valueC
key                            
D    1.454274 -0.977278     1.0
D    0.761038 -0.977278     1.0

49

Một cái nhìn trực quan bổ sung của pd.concat([df0, df1], kwargs). Lưu ý rằng, ý nghĩa của kwarg axis=0hoặc axis=1'không trực quan bằng df.mean()hoặcdf.apply(func)


trên pd.concat ([df0, df1])


9
Đây là một sơ đồ tốt đẹp. Tôi có thể hỏi làm thế nào bạn sản xuất nó?
cs95

6
tính năng "insert ==> vẽ ... ==> mới" của Google doc (tính đến năm 2019-tháng 5). Nhưng, rõ ràng: lý do duy nhất tôi sử dụng google doc cho bức ảnh này là vì các ghi chú của tôi được lưu trữ trong google doc và tôi muốn một hình ảnh có thể được sửa đổi nhanh chóng trong chính google doc. Trên thực tế bây giờ bạn đã đề cập đến nó, công cụ vẽ của google doc khá gọn gàng.
eliu

Wow, điều này thật tuyệt. Đến từ thế giới SQL, phép nối "dọc" không phải là phép nối trong đầu tôi, vì cấu trúc của bảng luôn được cố định. Bây giờ thậm chí nghĩ rằng gấu trúc nên hợp nhất concatmergevới một tham số hướng là horizontalhoặc vertical.
Ufos

2
@Ufos Đó không phải là chính xác axis=1axis=0là gì?
cs95

2
vâng, hiện nay đang mergeconcatvà trục và bất cứ điều gì. Tuy nhiên, như @eliu chỉ ra, tất cả chỉ là cùng một khái niệm hợp nhất với "trái" và "phải" và "ngang" hoặc "dọc". Cá nhân tôi phải xem xét tài liệu mỗi khi tôi phải nhớ "trục" nào 0và cái nào là 1.
Ufos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.