Sửa đổi tập hợp con của các hàng trong khung dữ liệu gấu trúc


143

Giả sử tôi có một DataFrame gấu trúc có hai cột, A và B. Tôi muốn sửa đổi DataFrame này (hoặc tạo một bản sao) để B luôn là NaN mỗi khi A bằng 0. Làm thế nào tôi đạt được điều đó?

Tôi đã thử như sau

df['A'==0]['B'] = np.nan

df['A'==0]['B'].values.fill(np.nan)

không thành công.


Nếu bạn đang tìm kiếm một giải pháp rất nhanh, hãy sử dụng NumPy wherenhư đã thấy trong giải pháp này bên dưới
Ted Petrou

Câu trả lời:


243

Sử dụng .locđể lập chỉ mục dựa trên nhãn:

df.loc[df.A==0, 'B'] = np.nan

Các df.A==0biểu hiện tạo ra một loạt boolean rằng chỉ số các hàng, 'B'chọn cột. Bạn cũng có thể sử dụng điều này để chuyển đổi một tập hợp con của một cột, ví dụ:

df.loc[df.A==0, 'B'] = df.loc[df.A==0, 'B'] / 2

Tôi không biết đủ về các chú gấu trúc để biết chính xác lý do tại sao nó hoạt động, nhưng vấn đề cơ bản là đôi khi việc lập chỉ mục vào DataFrame trả về một bản sao kết quả và đôi khi nó trả về một khung nhìn trên đối tượng ban đầu. Theo tài liệu ở đây , hành vi này phụ thuộc vào hành vi numpy tiềm ẩn. Tôi thấy rằng việc truy cập mọi thứ trong một thao tác (thay vì [một] [hai]) có nhiều khả năng hoạt động để cài đặt.


Phần thứ hai của đây là một câu trả lời hay cho một câu hỏi thậm chí chưa được hỏi ;-) Tôi tự hỏi liệu đây có phải là câu trả lời của gấu trúc không, đặc biệt là đó là một vi phạm DRY rõ ràng, mặc dù tôi cho rằng nó là Thực tế cần thiết để vi phạm DRY với những hạn chế của gấu trúc? (Tôi có thể đăng chính xác loại câu hỏi này, chi tiết hơn, nhưng muốn xem bạn có câu trả lời nhanh trước khi tôi làm như vậy không)
JohnE

Làm cách nào để tập hợp một Dataframe không có tên cột, làm thế nào để tập hợp df chỉ theo chỉ mục? df.loc [df [0] == 0] không hoạt động ... Cái gì thay thế? Cảm ơn bạn
amipro

89

Đây là từ tài liệu gấu trúc về lập chỉ mục nâng cao:

Phần này sẽ giải thích chính xác những gì bạn cần! Hóa ra df.loc(như .ix đã không được chấp nhận - như nhiều người đã chỉ ra dưới đây) có thể được sử dụng để cắt / cắt nhỏ mát của một khung dữ liệu. Và. Nó cũng có thể được sử dụng để thiết lập mọi thứ.

df.loc[selection criteria, columns I want] = value

Vì vậy, câu trả lời của Bren là nói 'tìm cho tôi tất cả các địa điểm df.A == 0, chọn cột Bvà đặt thành np.nan'


2
Bạn làm cho ngày của tôi. Giải thích rõ ràng.
TwinPenguins

1
Vâng, bằng cách nào đó loc[selection criteria, columns I want]hoàn toàn bám vào tâm trí của bạn ...
EmEs

29

Bắt đầu từ gấu trúc 0,20 ix không được chấp nhận . Cách đúng là sử dụng df.loc

đây là một ví dụ làm việc

>>> import pandas as pd 
>>> import numpy as np 
>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN
>>> 

Giải trình:

Như đã giải thích trong tài liệu ở đây , .loc chủ yếu dựa trên nhãn, nhưng cũng có thể được sử dụng với một mảng boolean .

Vì vậy, những gì chúng tôi đang làm ở trên là áp dụng df.loc[row_index, column_index]bởi:

  • Khai thác thực tế loccó thể lấy một mảng boolean làm mặt nạ cho gấu trúc biết tập hợp con nào của hàng chúng ta muốn thay đổirow_index
  • Khai thác thực tế loccũng là nhãn dựa trên để chọn cột bằng nhãn 'B'trongcolumn_index

Chúng ta có thể sử dụng logic, điều kiện hoặc bất kỳ hoạt động nào trả về một loạt các booleans để xây dựng mảng booleans. Trong ví dụ trên, chúng tôi muốn bất kỳ rowscái nào chứa a 0, mà chúng tôi có thể sử dụng df.A == 0, như bạn có thể thấy trong ví dụ dưới đây, điều này trả về một loạt các booleans.

>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df 
   A  B
0  0  2
1  1  0
2  0  5
>>> df.A == 0 
0     True
1    False
2     True
Name: A, dtype: bool
>>> 

Sau đó, chúng tôi sử dụng mảng booleans ở trên để chọn và sửa đổi các hàng cần thiết:

>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN

Để biết thêm thông tin kiểm tra các tài liệu lập chỉ mục nâng cao ở đây .


11

Để tăng tốc độ lớn, hãy sử dụng chức năng NumPy.

Thiết lập

Tạo một DataFrame hai cột với 100.000 hàng với một số không.

df = pd.DataFrame(np.random.randint(0,3, (100000,2)), columns=list('ab'))

Giải pháp nhanh với numpy.where

df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)

Thời gian

%timeit df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)
685 µs ± 6.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.loc[df['a'] == 0, 'b'] = np.nan
3.11 ms ± 17.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Numpy wherenhanh hơn khoảng 4 lần


Tôi tò mò về điều này vì vậy tôi đã tự mình kiểm tra và sự khác biệt thậm chí còn lớn hơn khi sử dụng các tham số khác. Numpy đã nhanh hơn gần 10 lần khi thay 0 bằng một số nguyên thay vì np.nan. Tôi tự hỏi những gì mất thêm thời gian.
Alexander

Có cần thiết phải sử dụng .valuestrong np.where(df.a.values == 0, np.nan, df.b.values)? Hình như np.where(df.a == 0, np.nan, df.b)cũng có tác dụng?
hsl

4

Để thay thế nhiều cột chuyển đổi sang mảng numpy bằng cách sử dụng .values :

df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
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.