อาร์กิวเมนต์ 'ระดับ', 'คีย์' และชื่อสำหรับในฟังก์ชัน concat ของ Pandas คืออะไร


97

คำถาม

  • ฉันจะใช้pd.concatอย่างไร?
  • เป็นสิ่งที่levelsโต้แย้งหรือไม่?
  • เป็นสิ่งที่keysโต้แย้งหรือไม่?
  • มีตัวอย่างมากมายที่ช่วยอธิบายวิธีใช้อาร์กิวเมนต์ทั้งหมดหรือไม่?

concatฟังก์ชั่นของ Pandas คือมีดของSwiss Armyของยูทิลิตี้ที่ผสานกัน ความหลากหลายของสถานการณ์ที่เป็นประโยชน์มีมากมาย เอกสารประกอบที่มีอยู่ให้รายละเอียดบางส่วนเกี่ยวกับอาร์กิวเมนต์ที่เป็นทางเลือกบางส่วน ในหมู่พวกเขามีข้อโต้แย้งlevelsและ keysฉันเริ่มคิดว่าข้อโต้แย้งเหล่านั้นทำอะไร

ฉันจะก่อให้เกิดคำถามว่าจะทำหน้าที่เป็นประตูเข้ามาในหลาย ๆ pd.concatแง่มุมของ

พิจารณากรอบข้อมูลd1, d2และd3:

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), [2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), [1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), [1, 3])

ถ้าฉันจะเชื่อมต่อสิ่งเหล่านี้เข้าด้วยกัน

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'])

ฉันได้รับผลลัพธ์ที่คาดหวังด้วย a pandas.MultiIndexสำหรับcolumnsวัตถุของฉัน:

        A    B    C    D
d1 2  0.1  0.2  0.3  NaN
   3  0.1  0.2  0.3  NaN
d2 1  NaN  0.4  0.5  0.6
   2  NaN  0.4  0.5  0.6
d3 1  0.7  0.8  NaN  0.9
   3  0.7  0.8  NaN  0.9

อย่างไรก็ตามฉันต้องการใช้levelsเอกสารประกอบการโต้แย้ง :

ระดับ : รายการลำดับเริ่มต้นไม่มี ระดับเฉพาะ (ค่าที่ไม่ซ้ำกัน) เพื่อใช้ในการสร้าง MultiIndex มิฉะนั้นจะถูกอนุมานจากคีย์

ฉันก็เลยผ่านไป

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2']])

และรับ KeyError

ValueError: Key d3 not in level Index(['d1', 'd2'], dtype='object')

สิ่งนี้สมเหตุสมผล ระดับที่ฉันสอบผ่านไม่เพียงพอที่จะอธิบายระดับที่จำเป็นที่ระบุโดยคีย์ หากฉันไม่ผ่านอะไรเลยอย่างที่ฉันทำข้างต้นระดับจะถูกอนุมาน (ตามที่ระบุไว้ในเอกสารประกอบ) แต่ฉันจะใช้อาร์กิวเมนต์นี้ให้ดีขึ้นได้อย่างไร

หากฉันลองสิ่งนี้แทน:

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3']])

ฉันและได้ผลลัพธ์เช่นเดียวกับด้านบน แต่เมื่อฉันเพิ่มค่าเข้าไปอีกระดับหนึ่ง

df = pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3', 'd4']])

ฉันลงเอยด้วยกรอบข้อมูลที่ดูเหมือนกัน แต่ผลลัพธ์MultiIndexมีระดับที่ไม่ได้ใช้

df.index.levels[0]

Index(['d1', 'd2', 'd3', 'd4'], dtype='object')

แล้วประเด็นของการlevelโต้แย้งคืออะไรและฉันควรใช้keysแตกต่างกันอย่างไร?

ฉันใช้ Python 3.6 และ Pandas 0.22

คำตอบ:


129

ในกระบวนการตอบคำถามนี้สำหรับตัวฉันเองฉันได้เรียนรู้หลายสิ่งหลายอย่างและฉันต้องการรวบรวมแคตตาล็อกตัวอย่างและคำอธิบายบางส่วน

คำตอบเฉพาะของประเด็นlevelsโต้แย้งจะมาถึงจุดสิ้นสุด

pandas.concat: คู่มือที่หายไป

ลิงก์ไปยังเอกสารปัจจุบัน

นำเข้าและกำหนดวัตถุ

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), index=[2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), index=[1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), index=[1, 3])

s1 = pd.Series([1, 2], index=[2, 3])
s2 = pd.Series([3, 4], index=[1, 2])
s3 = pd.Series([5, 6], index=[1, 3])

อาร์กิวเมนต์

objs

ข้อโต้แย้งแรกที่เราพบคือobjs:

objs : ลำดับหรือการแมปของ Series, DataFrame หรือพาเนลออบเจ็กต์หากส่งคำสั่งไปแล้วคีย์ที่เรียงลำดับจะถูกใช้เป็นอาร์กิวเมนต์ของคีย์เว้นแต่จะมีการส่งผ่านซึ่งในกรณีนี้ค่าจะถูกเลือก (ดูด้านล่าง) วัตถุใด ๆ ที่ไม่มีจะถูกทิ้งอย่างเงียบ ๆ เว้นแต่ว่าจะไม่มีทั้งหมดซึ่งในกรณีนี้จะมีการเพิ่ม ValueError

  • โดยทั่วไปเราจะเห็นสิ่งนี้ใช้กับรายการSeriesหรือDataFrameวัตถุ
  • ฉันจะแสดงให้เห็นว่าdictมีประโยชน์มากเช่นกัน
  • เครื่องกำเนิดไฟฟ้าอาจใช้และมีประโยชน์เมื่อใช้งานmapเช่นกันmap(f, list_of_df)

สำหรับตอนนี้เราจะติดรายการของDataFrameและSeriesวัตถุบางส่วนที่กำหนดไว้ด้านบน ฉันจะแสดงให้เห็นว่าพจนานุกรมสามารถใช้ประโยชน์ได้อย่างไรเพื่อให้ได้MultiIndexผลลัพธ์ที่มีประโยชน์มากในภายหลัง

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

axis

อาร์กิวเมนต์ที่สองที่เราพบคือaxisค่าเริ่มต้นคือ0:

แกน : {0 / 'ดัชนี', 1 / 'คอลัมน์'}, ค่าเริ่มต้น 0 แกนที่จะเชื่อมต่อกัน

สองDataFrameวินาทีกับaxis=0(ซ้อนกัน)

สำหรับค่า0หรือindexเราหมายถึงการพูดว่า: "จัดแนวตามคอลัมน์และเพิ่มลงในดัชนี"

ดังที่แสดงไว้ด้านบนที่เราใช้axis=0เนื่องจาก0เป็นค่าเริ่มต้นและเราเห็นว่าดัชนีของการd2ขยายดัชนีd1แม้ว่าจะมีการทับซ้อนกันของค่า2:

pd.concat([d1, d2], axis=0)

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

สองคนDataFrameกับaxis=1(เคียงข้างกัน)

สำหรับค่า1หรือcolumnsเราหมายถึงการพูดว่า: "จัดแนวตามดัชนีและเพิ่มลงในคอลัมน์"

pd.concat([d1, d2], axis=1)

     A    B    C    B    C    D
1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN

เราจะเห็นว่าดัชนีที่เกิดขึ้นเป็นสหภาพของดัชนีและคอลัมน์ที่เกิดขึ้นเป็นส่วนขยายของคอลัมน์จากคอลัมน์ของd1d2

สอง (หรือสาม) Seriesกับaxis=0(ซ้อนกัน)

เมื่อรวมpandas.Seriesตามที่เราได้รับกลับมาaxis=0 pandas.Seriesชื่อของผลลัพธ์Seriesจะเป็นNoneเว้นแต่ว่าทั้งหมดSeriesที่รวมกันมีชื่อเดียวกัน ให้ความสนใจกับเมื่อเราพิมพ์ออกผล'Name: A' Seriesเมื่อมันไม่เป็นปัจจุบันเราสามารถเอาชื่อSeriesNone

               |                       |                        |  pd.concat(
               |  pd.concat(           |  pd.concat(            |      [s1.rename('A'),
 pd.concat(    |      [s1.rename('A'), |      [s1.rename('A'),  |       s2.rename('B'),
     [s1, s2]) |       s2])            |       s2.rename('A')]) |       s3.rename('A')])
-------------- | --------------------- | ---------------------- | ----------------------
2    1         | 2    1                | 2    1                 | 2    1
3    2         | 3    2                | 3    2                 | 3    2
1    3         | 1    3                | 1    3                 | 1    3
2    4         | 2    4                | 2    4                 | 2    4
dtype: int64   | dtype: int64          | Name: A, dtype: int64  | 1    5
               |                       |                        | 3    6
               |                       |                        | dtype: int64

สอง (หรือสาม) Seriesกับaxis=1(เคียงข้างกัน)

เมื่อรวมpandas.Seriesพร้อมaxis=1มันเป็นแอตทริบิวต์ที่เราดูเพื่อที่จะสรุปชื่อคอลัมน์ในที่เกิดnamepandas.DataFrame

                       |                       |  pd.concat(
                       |  pd.concat(           |      [s1.rename('X'),
 pd.concat(            |      [s1.rename('X'), |       s2.rename('Y'),
     [s1, s2], axis=1) |       s2], axis=1)    |       s3.rename('Z')], axis=1)
---------------------- | --------------------- | ------------------------------
     0    1            |      X    0           |      X    Y    Z
1  NaN  3.0            | 1  NaN  3.0           | 1  NaN  3.0  5.0
2  1.0  4.0            | 2  1.0  4.0           | 2  1.0  4.0  NaN
3  2.0  NaN            | 3  2.0  NaN           | 3  2.0  NaN  6.0

ผสมSeriesและDataFrameกับaxis=0(ซ้อนกัน)

เมื่อทำการเชื่อมต่อของ a SeriesและDataFrameพร้อมaxis=0เราจะแปลงทั้งหมดSeriesเป็นคอลัมน์เดียวDataFrames

จดพิเศษที่ว่านี้คือการเรียงต่อกันพร้อมaxis=0; นั่นหมายถึงการขยายดัชนี (แถว) ในขณะที่จัดแนวคอลัมน์ ในตัวอย่างด้านล่างเราจะเห็นดัชนีกลายเป็นดัชนี[2, 3, 2, 3]ที่ต่อท้ายดัชนีโดยไม่เลือกปฏิบัติ คอลัมน์จะไม่ทับซ้อนกันเว้นแต่ฉันจะบังคับให้ตั้งชื่อSeriesคอลัมน์ด้วยอาร์กิวเมนต์เป็นto_frame:

 pd.concat(               |
     [s1.to_frame(), d1]) |  pd.concat([s1, d1])
------------------------- | ---------------------
     0    A    B    C     |      0    A    B    C
2  1.0  NaN  NaN  NaN     | 2  1.0  NaN  NaN  NaN
3  2.0  NaN  NaN  NaN     | 3  2.0  NaN  NaN  NaN
2  NaN  0.1  0.2  0.3     | 2  NaN  0.1  0.2  0.3
3  NaN  0.1  0.2  0.3     | 3  NaN  0.1  0.2  0.3

คุณสามารถเห็นผลลัพธ์ของpd.concat([s1, d1])มันเหมือนกับว่าฉันได้ทำให้to_frameตัวเองสมบูรณ์แบบ

to_frameแต่ผมสามารถควบคุมชื่อของคอลัมน์ที่เกิดกับพารามิเตอร์ไป การเปลี่ยนชื่อSeriesด้วยrenameวิธีการที่ไม่ได้DataFrameควบคุมชื่อคอลัมน์ในที่เกิด

 # Effectively renames       |                            |
 # `s1` but does not align   |  # Does not rename.  So    |  # Renames to something
 # with columns in `d1`      |  # Pandas defaults to `0`  |  # that does align with `d1`
 pd.concat(                  |  pd.concat(                |  pd.concat(
     [s1.to_frame('X'), d1]) |      [s1.rename('X'), d1]) |      [s1.to_frame('B'), d1])
---------------------------- | -------------------------- | ----------------------------
     A    B    C    X        |      0    A    B    C      |      A    B    C
2  NaN  NaN  NaN  1.0        | 2  1.0  NaN  NaN  NaN      | 2  NaN  1.0  NaN
3  NaN  NaN  NaN  2.0        | 3  2.0  NaN  NaN  NaN      | 3  NaN  2.0  NaN
2  0.1  0.2  0.3  NaN        | 2  NaN  0.1  0.2  0.3      | 2  0.1  0.2  0.3
3  0.1  0.2  0.3  NaN        | 3  NaN  0.1  0.2  0.3      | 3  0.1  0.2  0.3

ผสมSeriesและDataFrameด้วยaxis=1(เคียงข้างกัน)

นี่ค่อนข้างใช้งานง่าย Seriesชื่อคอลัมน์มีค่าเริ่มต้นเป็นการแจงนับของอSeriesอบเจ็กต์ดังกล่าวเมื่อไม่มีnameแอตทริบิวต์

                    |  pd.concat(
 pd.concat(         |      [s1.rename('X'),
     [s1, d1],      |       s2, s3, d1],
     axis=1)        |      axis=1)
------------------- | -------------------------------
   0    A    B    C |      X    0    1    A    B    C
2  1  0.1  0.2  0.3 | 1  NaN  3.0  5.0  NaN  NaN  NaN
3  2  0.1  0.2  0.3 | 2  1.0  4.0  NaN  0.1  0.2  0.3
                    | 3  2.0  NaN  6.0  0.1  0.2  0.3

join

อาร์กิวเมนต์ที่สามคือการjoinอธิบายว่าการผสานผลลัพธ์ควรเป็นการผสานภายนอก (ค่าเริ่มต้น) หรือการผสานภายใน

join : {'inner', 'outer'}, default 'outer'
วิธีจัดการดัชนีบนแกนอื่น ๆ

ปรากฎว่าไม่มีleftหรือrightตัวเลือกใดที่pd.concatสามารถจัดการกับวัตถุมากกว่าสองชิ้นเพื่อรวมเข้าด้วยกัน

ในกรณีd1และd2ตัวเลือกมีลักษณะดังนี้:

outer

pd.concat([d1, d2], axis=1, join='outer')

     A    B    C    B    C    D
1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN

inner

pd.concat([d1, d2], axis=1, join='inner')

     A    B    C    B    C    D
2  0.1  0.2  0.3  0.4  0.5  0.6

join_axes

ข้อโต้แย้งประการที่สี่คือสิ่งที่ช่วยให้เราทำการleftผสานและอื่น ๆ

join_axes : รายการดัชนีวัตถุ
ดัชนีเฉพาะที่จะใช้สำหรับแกน n - 1 อื่น ๆ แทนการใช้ตรรกะชุดภายใน / ภายนอก

ผสานซ้าย

pd.concat([d1, d2, d3], axis=1, join_axes=[d1.index])

     A    B    C    B    C    D    A    B    D
2  0.1  0.2  0.3  0.4  0.5  0.6  NaN  NaN  NaN
3  0.1  0.2  0.3  NaN  NaN  NaN  0.7  0.8  0.9

ผสานขวา

pd.concat([d1, d2, d3], axis=1, join_axes=[d3.index])

     A    B    C    B    C    D    A    B    D
1  NaN  NaN  NaN  0.4  0.5  0.6  0.7  0.8  0.9
3  0.1  0.2  0.3  NaN  NaN  NaN  0.7  0.8  0.9

ignore_index

Ignore_index : boolean ค่าเริ่มต้น False
If True อย่าใช้ค่าดัชนีตามแกนการเรียงต่อกัน แกนผลลัพธ์จะมีป้ายกำกับว่า 0, ... , n - 1 สิ่งนี้มีประโยชน์หากคุณกำลังต่อวัตถุที่แกนการเรียงต่อกันไม่มีข้อมูลการทำดัชนีที่มีความหมาย โปรดสังเกตว่าค่าดัชนีบนแกนอื่น ๆ ยังคงเคารพในการรวม

เช่นเดียวกับเมื่อฉันแต็คd1ที่ด้านบนของd2ถ้าฉันไม่สนใจเกี่ยวกับค่าดัชนีฉันจะรีเซ็ตพวกเขาหรือไม่สนใจพวกเขา

                      |  pd.concat(             |  pd.concat(
                      |      [d1, d2],          |      [d1, d2]
 pd.concat([d1, d2])  |      ignore_index=True) |  ).reset_index(drop=True)
--------------------- | ----------------------- | -------------------------
     A    B    C    D |      A    B    C    D   |      A    B    C    D
2  0.1  0.2  0.3  NaN | 0  0.1  0.2  0.3  NaN   | 0  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN | 1  0.1  0.2  0.3  NaN   | 1  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6 | 2  NaN  0.4  0.5  0.6   | 2  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6 | 3  NaN  0.4  0.5  0.6   | 3  NaN  0.4  0.5  0.6

และเมื่อใช้axis=1:

                                   |     pd.concat(
                                   |         [d1, d2], axis=1,
 pd.concat([d1, d2], axis=1)       |         ignore_index=True)
-------------------------------    |    -------------------------------
     A    B    C    B    C    D    |         0    1    2    3    4    5
1  NaN  NaN  NaN  0.4  0.5  0.6    |    1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6    |    2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN    |    3  0.1  0.2  0.3  NaN  NaN  NaN

keys

เราสามารถส่งรายการค่าสเกลาร์หรือทูเพิลเพื่อกำหนดค่าทูเพิลหรือสเกลาร์ให้กับ MultiIndex ที่เกี่ยวข้อง ความยาวของรายการที่ส่งผ่านจะต้องมีความยาวเท่ากับจำนวนรายการที่ต่อกัน

คีย์ : ลำดับค่าเริ่มต้นไม่มี
หากผ่านไปหลายระดับควรมีทูเปิล สร้างดัชนีลำดับชั้นโดยใช้ปุ่มที่ผ่านเป็นระดับนอกสุด

axis=0

เมื่อต่อSeriesวัตถุเข้าด้วยกันaxis=0(ขยายดัชนี)

คีย์เหล่านั้นกลายเป็นระดับเริ่มต้นใหม่ของMultiIndexอ็อบเจ็กต์ในแอตทริบิวต์ดัชนี

 #           length 3             length 3           #         length 2        length 2
 #          /--------\         /-----------\         #          /----\         /------\
 pd.concat([s1, s2, s3], keys=['A', 'B', 'C'])       pd.concat([s1, s2], keys=['A', 'B'])
----------------------------------------------      -------------------------------------
A  2    1                                           A  2    1
   3    2                                              3    2
B  1    3                                           B  1    3
   2    4                                              2    4
C  1    5                                           dtype: int64
   3    6
dtype: int64

อย่างไรก็ตามเราสามารถใช้มากกว่าค่าสเกลาร์ในkeysอาร์กิวเมนต์เพื่อสร้างMultiIndex. ที่นี่เราส่งต่อtuplesความยาว 2 ก่อนหน้าสองระดับใหม่ของ a MultiIndex:

 pd.concat(
     [s1, s2, s3],
     keys=[('A', 'X'), ('A', 'Y'), ('B', 'X')])
-----------------------------------------------
A  X  2    1
      3    2
   Y  1    3
      2    4
B  X  1    5
      3    6
dtype: int64

axis=1

แตกต่างกันเล็กน้อยเมื่อขยายตามคอลัมน์ เมื่อเราใช้axis=0(ดูด้านบน) การkeysกระทำของเราเป็นMultiIndexระดับนอกเหนือจากดัชนีที่มีอยู่ สำหรับaxis=1เรากำลังอ้างถึงแกนที่Seriesวัตถุไม่มีนั่นคือcolumnsแอตทริบิวต์

รูปแบบของสองSerieswtihaxis=1

สังเกตว่าการตั้งชื่อs1และมีความs2สำคัญตราบเท่าที่ไม่มีการkeysส่งผ่าน แต่จะถูกแทนที่หากkeysมีการส่งผ่าน

               |                       |                        |  pd.concat(
               |  pd.concat(           |  pd.concat(            |      [s1.rename('U'),
 pd.concat(    |      [s1, s2],        |      [s1.rename('U'),  |       s2.rename('V')],
     [s1, s2], |      axis=1,          |       s2.rename('V')], |       axis=1,
     axis=1)   |      keys=['X', 'Y']) |       axis=1)          |       keys=['X', 'Y'])
-------------- | --------------------- | ---------------------- | ----------------------
     0    1    |      X    Y           |      U    V            |      X    Y
1  NaN  3.0    | 1  NaN  3.0           | 1  NaN  3.0            | 1  NaN  3.0
2  1.0  4.0    | 2  1.0  4.0           | 2  1.0  4.0            | 2  1.0  4.0
3  2.0  NaN    | 3  2.0  NaN           | 3  2.0  NaN            | 3  2.0  NaN
MultiIndexด้วยSeriesและaxis=1
 pd.concat(
     [s1, s2],
     axis=1,
     keys=[('W', 'X'), ('W', 'Y')])
-----------------------------------
     W
     X    Y
1  NaN  3.0
2  1.0  4.0
3  2.0  NaN
สองDataFrameกับaxis=1

เช่นเดียวกับaxis=0ตัวอย่างให้keysเพิ่มระดับให้กับ a MultiIndexแต่คราวนี้ให้กับวัตถุที่เก็บไว้ในcolumnsแอตทริบิวต์

 pd.concat(                     |  pd.concat(
     [d1, d2],                  |      [d1, d2],
     axis=1,                    |      axis=1,
     keys=['X', 'Y'])           |      keys=[('First', 'X'), ('Second', 'X')])
------------------------------- | --------------------------------------------
     X              Y           |   First           Second
     A    B    C    B    C    D |       X                X
1  NaN  NaN  NaN  0.4  0.5  0.6 |       A    B    C      B    C    D
2  0.1  0.2  0.3  0.4  0.5  0.6 | 1   NaN  NaN  NaN    0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN | 2   0.1  0.2  0.3    0.4  0.5  0.6
                                | 3   0.1  0.2  0.3    NaN  NaN  NaN
SeriesและDataFrameด้วยaxis=1

นี่เป็นเรื่องยุ่งยาก ในกรณีนี้ค่าคีย์สเกลาร์ไม่สามารถทำหน้าที่เป็นดัชนีระดับเดียวสำหรับSeriesออบเจ็กต์ได้เมื่อมันกลายเป็นคอลัมน์ในขณะที่ทำหน้าที่เป็นระดับแรกของ a MultiIndexสำหรับDataFrame. ดังนั้น Pandas จะใช้nameแอตทริบิวต์ของSeriesวัตถุเป็นที่มาของชื่อคอลัมน์อีกครั้ง

 pd.concat(           |  pd.concat(
     [s1, d1],        |      [s1.rename('Z'), d1],
     axis=1,          |      axis=1,
     keys=['X', 'Y']) |      keys=['X', 'Y'])
--------------------- | --------------------------
   X    Y             |    X    Y
   0    A    B    C   |    Z    A    B    C
2  1  0.1  0.2  0.3   | 2  1  0.1  0.2  0.3
3  2  0.1  0.2  0.3   | 3  2  0.1  0.2  0.3
ข้อ จำกัดkeysและการMultiIndexอนุมาน

Pandas ดูเหมือนจะอนุมานชื่อคอลัมน์จากSeriesชื่อเท่านั้น แต่จะไม่เติมในช่องว่างเมื่อทำการเชื่อมต่อแบบอะนาล็อกระหว่างเฟรมข้อมูลที่มีระดับคอลัมน์ที่แตกต่างกัน

d1_ = pd.concat(
    [d1], axis=1,
    keys=['One'])
d1_

   One
     A    B    C
2  0.1  0.2  0.3
3  0.1  0.2  0.3

จากนั้นเชื่อมต่อกับกรอบข้อมูลอื่นที่มีเพียงระดับเดียวในออบเจ็กต์คอลัมน์และ Pandas จะปฏิเสธที่จะลองสร้างสิ่งที่เป็นMultiIndexวัตถุและรวมกรอบข้อมูลทั้งหมดราวกับว่าเป็นวัตถุระดับเดียวสเกลาร์และสิ่งทอ

pd.concat([d1_, d2], axis=1)

   (One, A)  (One, B)  (One, C)    B    C    D
1       NaN       NaN       NaN  0.4  0.5  0.6
2       0.1       0.2       0.3  0.4  0.5  0.6
3       0.1       0.2       0.3  NaN  NaN  NaN

ผ่าน a dictแทน alist

เมื่อผ่านพจนานุกรมpandas.concatจะใช้คีย์จากพจนานุกรมเป็นkeysพารามิเตอร์

 # axis=0               |  # axis=1
 pd.concat(             |  pd.concat(
     {0: d1, 1: d2})    |      {0: d1, 1: d2}, axis=1)
----------------------- | -------------------------------
       A    B    C    D |      0              1
0 2  0.1  0.2  0.3  NaN |      A    B    C    B    C    D
  3  0.1  0.2  0.3  NaN | 1  NaN  NaN  NaN  0.4  0.5  0.6
1 1  NaN  0.4  0.5  0.6 | 2  0.1  0.2  0.3  0.4  0.5  0.6
  2  NaN  0.4  0.5  0.6 | 3  0.1  0.2  0.3  NaN  NaN  NaN

levels

สิ่งนี้ใช้ร่วมกับkeysอาร์กิวเมนต์เมื่อlevelsถูกปล่อยให้เป็นค่าเริ่มต้นของNoneมัน Pandas จะรับค่าที่ไม่ซ้ำกันของแต่ละระดับของผลลัพธ์MultiIndexและใช้เป็นวัตถุที่ใช้ในindex.levelsแอตทริบิวต์ผลลัพธ์

ระดับ : รายการลำดับเริ่มต้นไม่มี
ระดับเฉพาะ (ค่าที่ไม่ซ้ำกัน) เพื่อใช้ในการสร้าง MultiIndex มิฉะนั้นจะถูกอนุมานจากคีย์

ถ้าแพนด้าสรุปได้แล้วว่าระดับเหล่านี้ควรเป็นอย่างไรจะมีประโยชน์อะไรที่จะระบุได้เอง? ฉันจะแสดงตัวอย่างและปล่อยให้คุณคิดเหตุผลอื่น ๆ ที่อาจเป็นประโยชน์

ตัวอย่าง

ตามเอกสารประกอบlevelsอาร์กิวเมนต์คือรายการของลำดับ ซึ่งหมายความว่าเราสามารถใช้อีกpandas.Indexอันหนึ่งเป็นหนึ่งในลำดับเหล่านั้นได้

พิจารณากรอบข้อมูลdfที่เป็น concatenation ของd1, d2และd3:

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'])

df

  First           Second           Fourth
      A    B    C      B    C    D      A    B    D
1   NaN  NaN  NaN    0.4  0.5  0.6    0.7  0.8  0.9
2   0.1  0.2  0.3    0.4  0.5  0.6    NaN  NaN  NaN
3   0.1  0.2  0.3    NaN  NaN  NaN    0.7  0.8  0.9

ระดับของวัตถุคอลัมน์คือ:

print(df, *df.columns.levels, sep='\n')

Index(['First', 'Second', 'Fourth'], dtype='object')
Index(['A', 'B', 'C', 'D'], dtype='object')

หากเราใช้sumภายในgroupbyเราจะได้รับ:

df.groupby(axis=1, level=0).sum()

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

แต่สิ่งที่ถ้าแทนที่จะ['First', 'Second', 'Fourth']มีคนอีกประเภทที่หายไปชื่อThirdและFifth? และฉันต้องการให้รวมอยู่ในผลลัพธ์ของการgroupbyรวม? เราสามารถทำได้ถ้าเรามีไฟล์pandas.CategoricalIndex. และเราสามารถระบุสิ่งนั้นล่วงหน้าพร้อมกับlevelsอาร์กิวเมนต์ได้

ดังนั้นให้กำหนดdfเป็น:

cats = ['First', 'Second', 'Third', 'Fourth', 'Fifth']
lvl = pd.CategoricalIndex(cats, categories=cats, ordered=True)

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'],
    levels=[lvl]
)

df

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

แต่ระดับแรกของวัตถุคอลัมน์คือ:

df.columns.levels[0]

CategoricalIndex(
    ['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    categories=['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    ordered=True, dtype='category')

และการgroupbyสรุปของเราดูเหมือนว่า:

df.groupby(axis=1, level=0).sum()

   First  Second  Third  Fourth  Fifth
1    0.0     1.5    0.0     2.4    0.0
2    0.6     1.5    0.0     0.0    0.0
3    0.6     0.0    0.0     2.4    0.0

names

MultiIndexนี้จะใช้ชื่อในระดับที่ส่งผล ความยาวของรายการควรจะตรงกับจำนวนของระดับในที่เกิดnamesMultiIndex

ชื่อ : รายการค่าเริ่มต้น None
Names สำหรับระดับในดัชนีลำดับชั้นที่เป็นผลลัพธ์

 # axis=0                     |  # axis=1
 pd.concat(                   |  pd.concat(
     [d1, d2],                |      [d1, d2],
     keys=[0, 1],             |      axis=1, keys=[0, 1],
     names=['lvl0', 'lvl1'])  |      names=['lvl0', 'lvl1'])
----------------------------- | ----------------------------------
             A    B    C    D | lvl0    0              1
lvl0 lvl1                     | lvl1    A    B    C    B    C    D
0    2     0.1  0.2  0.3  NaN | 1     NaN  NaN  NaN  0.4  0.5  0.6
     3     0.1  0.2  0.3  NaN | 2     0.1  0.2  0.3  0.4  0.5  0.6
1    1     NaN  0.4  0.5  0.6 | 3     0.1  0.2  0.3  NaN  NaN  NaN
     2     NaN  0.4  0.5  0.6 |

verify_integrity

เอกสารอธิบายตนเอง

Verify_integrity : boolean, default False
ตรวจสอบว่าแกนที่ต่อกันใหม่มีรายการที่ซ้ำกันหรือไม่ ซึ่งอาจมีราคาแพงมากเมื่อเทียบกับการต่อข้อมูลจริง

เนื่องจากดัชนีผลลัพธ์จากการเรียงต่อกันd1และd2ไม่ซ้ำกันจึงทำให้การตรวจสอบความสมบูรณ์ล้มเหลว

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

และ

pd.concat([d1, d2], verify_integrity=True)

> ValueError: ดัชนีมีค่าที่ทับซ้อนกัน: [2]


23
มันจะมีประโยชน์มากกว่าสำหรับชุมชนเพียงแค่ทำการดึงคำขอเพื่อเพิ่มตัวอย่างที่ขาดหายไป (เพียงไม่กี่ตัว) ลงในเอกสารหลัก SO สามารถค้นหาได้และไม่สามารถเรียกดูได้ การใส่ลิงก์ไปยังเอกสารเพิ่มเติมจะเป็นประโยชน์ที่นี่ - ส่วนใหญ่เอกสารนี้ดีและสมบูรณ์อยู่แล้ว
Jeff

6
@ เจฟฟ์มีขนาดของการเติบโตของฉันที่ช้า การใช้คอมไพล์เป็นหนึ่งในนั้น ฉันสัญญาว่านั่นคือสิ่งที่ฉันต้องการจะเริ่มทำ
piRSquared

ใช้ผลิตเป็นผลที่แตกต่างกันมากกว่าpd.concat(..., levels=[lvl]).groupby(axis=1, level=0).sum() pd.concat(..., levels=[cats]).groupby(axis=1, level=0).sum()คุณรู้ไหมว่าทำไม? เอกสารบอกว่าlevelsควรเป็นรายการลำดับเท่านั้น
unutbu

1
คำตอบที่ดี แต่ฉันคิดว่าส่วนที่เกี่ยวกับPassing a dict instead of a listต้องการตัวอย่างโดยใช้คำสั่งไม่ใช่รายการ
unutbu

1
@unutbu ฉันแก้ไขdictตัวอย่างแล้วขอบคุณ สาเหตุที่lvlเป็นดัชนีชี้วัดและcatsเป็นเพียงรายการ เมื่อจัดกลุ่มตามประเภทหมวดหมู่หมวดหมู่ที่ขาดหายไปจะถูกเติมด้วยศูนย์และค่าว่างตามความเหมาะสม ดูสิ่งนี้
piRSquared
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.