Trong quá trình trả lời câu hỏi này cho bản thân, tôi đã học được nhiều điều, và tôi muốn tập hợp một danh mục các ví dụ và một số giải thích.
Câu trả lời cụ thể cho quan điểm của cuộc levels
tranh luận sẽ đến ở phần cuối.
pandas.concat
: Hướng dẫn sử dụng còn thiếu
Liên kết đến tài liệu hiện tại
Nhập và xác định đối tượng
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])
Tranh luận
objs
Đối số đầu tiên mà chúng ta gặp phải là objs
:
objs : một chuỗi hoặc ánh xạ của các đối tượng Series, DataFrame hoặc Panel Nếu một dict được chuyển, các khóa đã sắp xếp sẽ được sử dụng làm đối số khóa, trừ khi nó được truyền, trong trường hợp đó các giá trị sẽ được chọn (xem bên dưới). Mọi đối tượng Không có sẽ bị loại bỏ âm thầm trừ khi tất cả chúng đều Không có. Trong trường hợp đó, một ValueError sẽ được nâng lên
- Chúng tôi thường thấy điều này được sử dụng với một danh sách
Series
hoặc DataFrame
các đối tượng.
- Tôi sẽ chỉ ra rằng điều đó
dict
cũng có thể rất hữu ích.
- Máy phát điện cũng có thể được sử dụng và có thể hữu ích khi sử dụng
map
như trongmap(f, list_of_df)
Bây giờ, chúng ta sẽ gắn bó với danh sách một số đối tượng DataFrame
và Series
đối tượng được xác định ở trên. Tôi sẽ chỉ ra cách tận dụng từ điển để đưa ra những MultiIndex
kết quả rất hữu ích sau này.
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
Đối số thứ hai mà chúng ta gặp phải axis
có giá trị mặc định là 0
:
trục : {0 / 'index', 1 / 'cột'}, mặc định là 0 Trục để nối với nhau.
Hai DataFrame
s với axis=0
(xếp chồng lên nhau)
Đối với các giá trị của 0
hoặc index
chúng tôi muốn nói: "Căn chỉnh dọc theo các cột và thêm vào chỉ mục".
Như được hiển thị ở trên nơi chúng tôi đã sử dụng axis=0
, vì 0
là giá trị mặc định và chúng tôi thấy rằng chỉ mục của d2
mở rộng chỉ mục của d1
mặc dù có sự chồng chéo của giá trị 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
Hai DataFrame
s với axis=1
(cạnh nhau)
Đối với các giá trị 1
hoặc columns
chúng tôi muốn nói: "Căn chỉnh theo chỉ mục và thêm vào các cột",
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
Chúng ta có thể thấy rằng chỉ mục kết quả là sự kết hợp của các chỉ số và các cột kết quả là phần mở rộng của các cột từ d1
các cột của d2
.
Hai (hoặc Ba) Series
với axis=0
(xếp chồng lên nhau)
Khi kết hợp pandas.Series
cùng nhau axis=0
, chúng ta nhận được lại a pandas.Series
. Tên của kết quả Series
sẽ là None
trừ khi tất cả Series
được kết hợp có cùng tên. Hãy chú ý đến thời 'Name: A'
điểm chúng tôi in ra kết quả Series
. Khi nó không có mặt, chúng ta có thể cho rằng Series
tên là None
.
| | | 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
Hai (hoặc Ba) Series
với axis=1
(cạnh nhau)
Khi kết hợp pandas.Series
cùng axis=1
, nó là name
thuộc tính mà chúng tôi tham chiếu đến để suy ra tên cột trong kết quả pandas.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
Hỗn hợp Series
và DataFrame
với axis=0
(xếp chồng lên nhau)
Khi thực hiện nối a Series
và DataFrame
cùng axis=0
, chúng ta chuyển tất cả Series
thành cột đơn DataFrame
s.
Hãy đặc biệt lưu ý rằng đây là một nối cùng axis=0
; điều đó có nghĩa là mở rộng chỉ mục (hàng) trong khi căn chỉnh các cột. Trong các ví dụ dưới đây, chúng ta thấy chỉ số trở thành [2, 3, 2, 3]
một chỉ số nối tiếp một cách bừa bãi. Các cột không chồng lên nhau trừ khi tôi buộc đặt tên của Series
cột với đối số là 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
Bạn có thể thấy kết quả của pd.concat([s1, d1])
giống như thể tôi đã to_frame
tự làm sạch.
Tuy nhiên, tôi có thể kiểm soát tên của cột kết quả với một tham số là to_frame
. Đổi tên Series
với rename
phương thức không kiểm soát tên cột trong kết quả 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
Hỗn hợp Series
và DataFrame
với axis=1
(cạnh nhau)
Điều này là khá trực quan. Series
tên cột mặc định là danh sách các Series
đối tượng như vậy khi name
không có thuộc tính.
| 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
Đối số thứ ba join
mô tả liệu hợp nhất kết quả nên là hợp nhất bên ngoài (mặc định) hay hợp nhất bên trong.
join : {'inside', 'external'}, default 'external'
Cách xử lý các chỉ mục trên (các) trục khác.
Hóa ra, không có left
hoặc right
tùy chọn pd.concat
có thể xử lý nhiều hơn hai đối tượng để hợp nhất.
Trong trường hợp d1
và d2
, các tùy chọn trông giống như:
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
Đối số thứ tư là thứ cho phép chúng tôi thực hiện left
hợp nhất và hơn thế nữa.
join_axes : danh sách các đối tượng Chỉ mục Chỉ mục
cụ thể để sử dụng cho n - 1 trục khác thay vì thực hiện logic tập hợp bên trong / bên ngoài.
Hợp nhất trái
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
Hợp nhất bên phải
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, mặc định Sai
Nếu Đúng, không sử dụng các giá trị chỉ mục dọc theo trục nối. Trục kết quả sẽ được gắn nhãn 0, ..., n - 1. Điều này rất hữu ích nếu bạn đang nối các đối tượng mà trục nối không có thông tin chỉ mục có ý nghĩa. Lưu ý rằng các giá trị chỉ mục trên các trục khác vẫn được tôn trọng trong phép nối.
Giống như khi tôi xếp chồng d1
lên nhau d2
, nếu tôi không quan tâm đến các giá trị chỉ mục, tôi có thể đặt lại chúng hoặc bỏ qua chúng.
| 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
Và khi sử dụng 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
Chúng ta có thể chuyển một danh sách các giá trị vô hướng hoặc các bộ giá trị để gán các bộ giá trị hoặc bộ giá trị vô hướng cho MultiIndex tương ứng. Độ dài của danh sách đã thông qua phải bằng độ dài với số mục được nối.
các phím : trình tự, mặc định Không có
Nếu nhiều cấp được vượt qua, phải chứa các bộ giá trị. Xây dựng chỉ mục phân cấp bằng cách sử dụng các khóa được truyền làm cấp ngoài cùng
axis=0
Khi nối Series
các đối tượng dọc theo axis=0
(mở rộng chỉ mục).
Các khóa đó, trở thành cấp ban đầu mới của một MultiIndex
đối tượng trong thuộc tính chỉ mục.
# 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
Tuy nhiên, chúng ta có thể sử dụng nhiều hơn các giá trị vô hướng trong keys
đối số để tạo ra một sâu hơn MultiIndex
. Ở đây chúng ta vượt qua tuples
độ dài 2 để thêm vào trước hai cấp độ mới của 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
Nó hơi khác một chút khi mở rộng dọc theo các cột. Khi chúng tôi sử dụng axis=0
(xem ở trên), chúng tôi keys
hoạt động như MultiIndex
các cấp ngoài chỉ mục hiện có. Vì axis=1
, chúng tôi đang đề cập đến một trục mà Series
các đối tượng không có, đó là columns
thuộc tính.
Các biến thể của Two
Series
wtih
axis=1
Lưu ý rằng đặt tên cho s1
và s2
các vấn đề miễn là không keys
được thông qua, nhưng nó sẽ bị ghi đè nếu keys
được thông qua.
| | | 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
với
Series
và
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
Hai
DataFrame
với
axis=1
Như với các axis=0
ví dụ, hãy keys
thêm cấp độ vào a MultiIndex
, nhưng lần này là đối tượng được lưu trữ trong columns
thuộc tính.
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
và
DataFrame
với
axis=1
Điều này là khó khăn. Trong trường hợp này, giá trị khóa vô hướng không thể hoạt động như cấp chỉ mục duy nhất cho Series
đối tượng khi nó trở thành một cột trong khi cũng hoạt động như cấp đầu tiên của a MultiIndex
cho DataFrame
. Vì vậy, Pandas sẽ lại sử dụng name
thuộc tính của Series
đối tượng làm nguồn của tên cột.
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
Hạn chế của
keys
và suy luận
MultiIndex
.
Con gấu trúc dường như chỉ suy ra tên cột từ Series
tên, nhưng nó sẽ không điền vào chỗ trống khi thực hiện nối tương tự giữa các khung dữ liệu có số lượng cấp cột khác nhau.
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
Sau đó, nối khung dữ liệu này với một khung dữ liệu khác chỉ có một cấp trong đối tượng cột và Pandas sẽ từ chối thử tạo các bộ giá trị của MultiIndex
đối tượng và kết hợp tất cả các khung dữ liệu như thể một cấp độ duy nhất của các đối tượng, vô hướng và bộ giá trị.
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
Vượt qua một dict
thay vì mộtlist
Khi truyền từ điển, pandas.concat
sẽ sử dụng các khóa từ từ điển làm keys
tham số.
# 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
Điều này được sử dụng cùng với keys
đối số. Khi levels
được để làm giá trị mặc định của nó None
, Pandas sẽ lấy các giá trị duy nhất của mỗi cấp của kết quả MultiIndex
và sử dụng nó làm đối tượng được sử dụng trong index.levels
thuộc tính kết quả .
cấp độ : danh sách trình tự, mặc định Không có Cấp
độ cụ thể (giá trị duy nhất) để sử dụng để tạo MultiIndex. Nếu không, chúng sẽ được suy ra từ các phím.
Nếu Pandas đã suy ra những cấp độ này thì có lợi gì để tự mình chỉ định nó? Tôi sẽ đưa ra một ví dụ và để bạn nghĩ ra những lý do khác tại sao điều này có thể hữu ích.
Thí dụ
Theo tài liệu, levels
đối số là một danh sách các chuỗi. Điều này có nghĩa là chúng ta có thể sử dụng cái khác pandas.Index
làm một trong những chuỗi đó.
Hãy xem xét khung dữ liệu df
là kết nối của d1
, d2
và 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
Các cấp độ của đối tượng cột là:
print(df, *df.columns.levels, sep='\n')
Index(['First', 'Second', 'Fourth'], dtype='object')
Index(['A', 'B', 'C', 'D'], dtype='object')
Nếu chúng tôi sử dụng sum
trong một, groupby
chúng tôi nhận được:
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
Nhưng điều gì sẽ xảy ra nếu thay vì ['First', 'Second', 'Fourth']
có một danh mục bị thiếu khác được đặt tên Third
và Fifth
? Và tôi muốn chúng được đưa vào kết quả của một groupby
tổng hợp? Chúng tôi có thể làm điều này nếu chúng tôi có pandas.CategoricalIndex
. Và chúng tôi có thể chỉ định điều đó trước vớilevels
đối số.
Vì vậy, thay vào đó, hãy định nghĩa df
là:
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
Nhưng mức đầu tiên của đối tượng cột là:
df.columns.levels[0]
CategoricalIndex(
['First', 'Second', 'Third', 'Fourth', 'Fifth'],
categories=['First', 'Second', 'Third', 'Fourth', 'Fifth'],
ordered=True, dtype='category')
Và groupby
tổng kết của chúng tôi trông giống như:
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
Điều này được sử dụng để đặt tên cho các mức của một kết quả MultiIndex
. Độ dài của names
danh sách phải khớp với số cấp trong kết quả MultiIndex
.
tên : danh sách, mặc định Không có
Tên cho các cấp trong chỉ mục phân cấp kết quả
# 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
Tài liệu tự giải thích
verify_integrity : boolean, default False
Kiểm tra xem trục nối mới có chứa các bản sao không. Điều này có thể rất tốn kém so với việc ghép dữ liệu thực tế.
Bởi vì chỉ mục kết quả từ việc nối d1
và d2
không phải là duy nhất, nó sẽ không kiểm tra được tính toàn vẹn.
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
Và
pd.concat([d1, d2], verify_integrity=True)
> ValueError: Các chỉ mục có các giá trị chồng chéo: [2]