Sự mơ hồ trong định nghĩa "trục" của Pandas Dataframe / Numpy Array


91

Tôi đã rất bối rối về cách các trục python được xác định và liệu chúng có tham chiếu đến các hàng hoặc cột của DataFrame hay không. Hãy xem xét đoạn mã dưới đây:

>>> df = pd.DataFrame([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]], columns=["col1", "col2", "col3", "col4"])
>>> df
   col1  col2  col3  col4
0     1     1     1     1
1     2     2     2     2
2     3     3     3     3

Vì vậy, nếu chúng ta gọi df.mean(axis=1), chúng ta sẽ nhận được giá trị trung bình trên các hàng:

>>> df.mean(axis=1)
0    1
1    2
2    3

Tuy nhiên, nếu chúng ta gọi df.drop(name, axis=1), chúng ta thực sự thả một cột , không phải một hàng:

>>> df.drop("col4", axis=1)
   col1  col2  col3
0     1     1     1
1     2     2     2
2     3     3     3

Ai đó có thể giúp tôi hiểu ý nghĩa của một "trục" trong gấu trúc / numpy / scipy không?

Một lưu ý phụ, DataFrame.meanchỉ có thể được định nghĩa sai. Nó nói trong tài liệu cho DataFrame.meanđiều đó axis=1được cho là có nghĩa trên các cột, không phải các hàng ...


Để có giải thích chi tiết về bí danh, 'cột''chỉ mục' / 'hàng', hãy xem câu trả lời này bên dưới .
Ted Petrou

Điều này thật kỳ lạ. Trục phải nhất quán trên meandrop. Cần có tư duy phi tuyến để đi đến hành vi thực tế.
StephenBoesch

Câu trả lời:


167

Có lẽ đơn giản nhất để nhớ nó là 0 = xuống1 = ngang .

Điều này có nghĩa là:

  • Sử dụng axis=0để áp dụng một phương pháp xuống từng cột hoặc cho các nhãn hàng (chỉ mục).
  • Sử dụng axis=1để áp dụng một phương pháp trên mỗi hàng hoặc cho các nhãn cột.

Đây là hình ảnh để hiển thị các phần của DataFrame mà mỗi trục đề cập đến:

Cũng hữu ích khi nhớ rằng Pandas tuân theo cách sử dụng từ này của NumPy axis. Việc sử dụng được giải thích trong bảng chú giải thuật ngữ của NumPy :

Trục được xác định cho các mảng có nhiều hơn một chiều. Mảng 2 chiều có hai trục tương ứng: trục thứ nhất chạy dọc xuống dưới qua các hàng (trục 0)trục thứ hai chạy ngang qua các cột (trục 1) . [ sự nhấn mạnh của tôi ]

Vì vậy, liên quan đến phương pháp trong câu hỏi df.mean(axis=1), dường như đã được xác định chính xác. Nó lấy giá trị trung bình của các mục nhập theo chiều ngang qua các cột , tức là dọc theo từng hàng riêng lẻ. Mặt khác, df.mean(axis=0)sẽ là một phép toán hoạt động theo chiều dọc xuống dưới qua các hàng .

Tương tự, df.drop(name, axis=1)đề cập đến một hành động trên các nhãn cột, vì chúng đi qua trục hoành một cách trực quan. axis=0Thay vào đó, chỉ định sẽ làm cho phương thức hoạt động trên các hàng.


3
Điều khiến tôi gặp khó khăn là df.apply (..., axis = 0), không "chạy qua" trục 0 (chỉ mục), mà chạy qua các cột, truy xuất Chuỗi chứa tất cả các chỉ mục. Đầu mối là, df.apply (..., axis = 0) trả về Chuỗi để BẠN có thể áp dụng một hoạt động chạy trên chỉ mục hoàn chỉnh.
moritzschaefer,

2
Tôi nghĩ rằng nó cũng hữu ích nếu bạn xem df.applytương tự như một phương pháp chẳng hạn df.sum. Ví dụ: tính df.sum(axis=0)tổng từng cột của DataFrame. Tương tự, bạn có thể viết df.apply(sum, axis=0)để thực hiện chính xác các hoạt động tương tự. Trong khi hoạt động thực sự là áp dụng cho từng cột trong DataFrame, chức năng thực tế chạy xuống trục 0.
Alex Riley

Thật không may là các quy ước đặt tên và thứ tự trái ngược với hàm áp dụng của R - trong R, giá trị thấp hơn MARGIN(tương tự như axisở gấu trúc) của "1" tương ứng với "hàng" có nghĩa là hàm được áp dụng cho mỗi hàng , trong khi giá trị lớn hơn của "2" đề cập đến "cột" có nghĩa là hàm được áp dụng cho mỗi cột .
Keith Hughitt

nó là một lỗi phá hoại trong gấu trúc
Calculus

10

Một cách khác để giải thích:

// Not realistic but ideal for understanding the axis parameter 
df = pd.DataFrame([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]],
                  columns=["idx1", "idx2", "idx3", "idx4"],
                  index=["idx1", "idx2", "idx3"]
                 )

---------------------------------------1
|          idx1  idx2  idx3  idx4
|    idx1     1     1     1     1
|    idx2     2     2     2     2
|    idx3     3     3     3     3
0

Giới thiệu df.drop(trục có nghĩa là vị trí)

A: I wanna remove idx3.
B: **Which one**? // typing while waiting response: df.drop("idx3",
A: The one which is on axis 1
B: OK then it is >> df.drop("idx3", axis=1)

// Result
---------------------------------------1
|          idx1  idx2     idx4
|    idx1     1     1     1
|    idx2     2     2     2
|    idx3     3     3     3
0

Giới thiệu df.apply(trục có nghĩa là hướng)

A: I wanna apply sum.
B: Which direction? // typing while waiting response: df.apply(lambda x: x.sum(),
A: The one which is on *parallel to axis 0*
B: OK then it is >> df.apply(lambda x: x.sum(), axis=0)

// Result
idx1    6
idx2    6
idx3    6
idx4    6

Bạn không nghĩ rằng, trên trục 1 và song song với trục 0 có nghĩa là giống nhau?
Nuance

9

Đã có câu trả lời thích hợp, nhưng tôi cung cấp cho bạn một ví dụ khác với> 2 thứ nguyên.

Tham số axiscó nghĩa là trục được thay đổi .
Ví dụ: hãy xem xét rằng có một khung dữ liệu với thứ nguyên axbxc .

  • df.mean(axis=1)trả về khung dữ liệu với kích thước ax 1 xc .
  • df.drop("col4", axis=1)trả về khung dữ liệu có thứ nguyên ax (b-1) xc .

Ở đây, axis=1có nghĩa là trục thứ hai b, vì vậy bgiá trị sẽ được thay đổi trong các ví dụ này.


1
Câu trả lời này đối với tôi trực quan hơn bất kỳ hình dung nào tôi đã thấy về chủ đề này. Tuy nhiên, xarray tốt hơn cho mảng đa chiều hơn là gấu trúc.
alys

2

Cần được biết rộng rãi hơn rằng bí danh chuỗi 'chỉ số''cột' có thể được sử dụng thay cho các số nguyên 0/1. Các bí danh rõ ràng hơn nhiều và giúp tôi nhớ các phép tính diễn ra như thế nào. Một bí danh khác cho 'chỉ mục' là 'hàng' .

Khi nào axis='index'được sử dụng, thì các phép tính sẽ xảy ra ở các cột, điều này rất khó hiểu. Nhưng, tôi nhớ rằng nó nhận được một kết quả có cùng kích thước với một hàng khác.

Hãy lấy một số dữ liệu trên màn hình để xem tôi đang nói về điều gì:

df = pd.DataFrame(np.random.rand(10, 4), columns=list('abcd'))
          a         b         c         d
0  0.990730  0.567822  0.318174  0.122410
1  0.144962  0.718574  0.580569  0.582278
2  0.477151  0.907692  0.186276  0.342724
3  0.561043  0.122771  0.206819  0.904330
4  0.427413  0.186807  0.870504  0.878632
5  0.795392  0.658958  0.666026  0.262191
6  0.831404  0.011082  0.299811  0.906880
7  0.749729  0.564900  0.181627  0.211961
8  0.528308  0.394107  0.734904  0.961356
9  0.120508  0.656848  0.055749  0.290897

Khi chúng ta muốn lấy giá trị trung bình của tất cả các cột, chúng ta sử dụng axis='index'để lấy như sau:

df.mean(axis='index')
a    0.562664
b    0.478956
c    0.410046
d    0.546366
dtype: float64

Kết quả tương tự sẽ nhận được bởi:

df.mean() # default is axis=0
df.mean(axis=0)
df.mean(axis='rows')

Để sử dụng một thao tác từ trái sang phải trên các hàng, hãy sử dụng axis = 'cột'. Tôi nhớ nó bằng cách nghĩ rằng một cột bổ sung có thể được thêm vào DataFrame của tôi:

df.mean(axis='columns')
0    0.499784
1    0.506596
2    0.478461
3    0.448741
4    0.590839
5    0.595642
6    0.512294
7    0.427054
8    0.654669
9    0.281000
dtype: float64

Kết quả tương tự sẽ nhận được bởi:

df.mean(axis=1)

Thêm một hàng mới với axis = 0 / index / rows

Hãy sử dụng các kết quả này để thêm các hàng hoặc cột bổ sung để hoàn thành phần giải thích. Vì vậy, bất cứ khi nào sử dụng axis = 0 / index / rows, nó giống như nhận được một hàng mới của DataFrame. Hãy thêm một hàng:

df.append(df.mean(axis='rows'), ignore_index=True)

           a         b         c         d
0   0.990730  0.567822  0.318174  0.122410
1   0.144962  0.718574  0.580569  0.582278
2   0.477151  0.907692  0.186276  0.342724
3   0.561043  0.122771  0.206819  0.904330
4   0.427413  0.186807  0.870504  0.878632
5   0.795392  0.658958  0.666026  0.262191
6   0.831404  0.011082  0.299811  0.906880
7   0.749729  0.564900  0.181627  0.211961
8   0.528308  0.394107  0.734904  0.961356
9   0.120508  0.656848  0.055749  0.290897
10  0.562664  0.478956  0.410046  0.546366

Thêm một cột mới với axis = 1 / cột

Tương tự, khi axis = 1 / column, nó sẽ tạo dữ liệu có thể dễ dàng tạo thành cột của riêng nó:

df.assign(e=df.mean(axis='columns'))

          a         b         c         d         e
0  0.990730  0.567822  0.318174  0.122410  0.499784
1  0.144962  0.718574  0.580569  0.582278  0.506596
2  0.477151  0.907692  0.186276  0.342724  0.478461
3  0.561043  0.122771  0.206819  0.904330  0.448741
4  0.427413  0.186807  0.870504  0.878632  0.590839
5  0.795392  0.658958  0.666026  0.262191  0.595642
6  0.831404  0.011082  0.299811  0.906880  0.512294
7  0.749729  0.564900  0.181627  0.211961  0.427054
8  0.528308  0.394107  0.734904  0.961356  0.654669
9  0.120508  0.656848  0.055749  0.290897  0.281000

Dường như bạn có thể thấy tất cả các bí danh với các biến riêng tư sau:

df._AXIS_ALIASES
{'rows': 0}

df._AXIS_NUMBERS
{'columns': 1, 'index': 0}

df._AXIS_NAMES
{0: 'index', 1: 'columns'}

1

Khi axis = 'lines' hoặc axis = 0, có nghĩa là truy cập các phần tử theo hướng của các hàng, từ trên xuống dưới. Nếu áp dụng tổng dọc theo trục = 0, nó sẽ cho chúng ta tổng của mỗi cột.

Khi axis = 'cột' hoặc axis = 1, điều đó có nghĩa là truy cập các phần tử theo hướng của các cột, từ trái sang phải. Nếu áp dụng tổng dọc theo trục = 1, chúng ta sẽ nhận được tổng của mỗi hàng.

Vẫn khó hiểu! Nhưng ở trên làm cho nó dễ dàng hơn một chút cho tôi.


0

Tôi thấy tất cả các câu trả lời khác khó hiểu. Đây là cách tôi nghĩ về nó:

axis=0: hình dạng của kết quả nằm ngang (một hàng)
axis=1: hình dạng của kết quả là dọc (một cột)

Vì thế

  • df.drop(name, axis=1): thả một cột
  • df.mean(axis=1): tính toán một cột (kết quả có thể được thêm vào dưới dạng một cột mới)
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.