Thay thế các giá trị trống (khoảng trắng) bằng NaN trong gấu trúc


150

Tôi muốn tìm tất cả các giá trị trong khung dữ liệu Pandas có chứa khoảng trắng (bất kỳ số lượng tùy ý nào) và thay thế các giá trị đó bằng NaN.

Bất kỳ ý tưởng làm thế nào điều này có thể được cải thiện?

Về cơ bản tôi muốn biến điều này:

                   A    B    C
2000-01-01 -0.532681  foo    0
2000-01-02  1.490752  bar    1
2000-01-03 -1.387326  foo    2
2000-01-04  0.814772  baz     
2000-01-05 -0.222552         4
2000-01-06 -1.176781  qux     

Vào đây:

                   A     B     C
2000-01-01 -0.532681   foo     0
2000-01-02  1.490752   bar     1
2000-01-03 -1.387326   foo     2
2000-01-04  0.814772   baz   NaN
2000-01-05 -0.222552   NaN     4
2000-01-06 -1.176781   qux   NaN

Tôi đã quản lý để làm điều đó với mã dưới đây, nhưng con người thật xấu xí. Đó không phải là Pythonic và tôi chắc chắn đó cũng không phải là cách sử dụng gấu trúc hiệu quả nhất. Tôi lặp qua từng cột và thực hiện thay thế boolean bằng mặt nạ cột được tạo bằng cách áp dụng hàm thực hiện tìm kiếm regex của từng giá trị, khớp trên khoảng trắng.

for i in df.columns:
    df[i][df[i].apply(lambda i: True if re.search('^\s*$', str(i)) else False)]=None

Nó có thể được tối ưu hóa một chút bằng cách chỉ lặp qua các trường có thể chứa các chuỗi trống:

if df[i].dtype == np.dtype('object')

Nhưng đó không phải là một cải tiến nhiều

Và cuối cùng, mã này đặt các chuỗi mục tiêu thành Không, hoạt động với các chức năng của Pandas như thế fillna(), nhưng sẽ rất tuyệt nếu tôi thực sự có thể chèn NaNtrực tiếp thay vì None.


2
Những gì bạn thực sự muốn là có thể sử dụng replacevới regex ... (có lẽ điều này nên được yêu cầu như một tính năng).
Andy Hayden

3
Tôi đã tạo một vấn đề github cho tính năng này: github.com/pydata/pandas/issues/2285 . Sẽ biết ơn các PR! :)
Chang She

Đối với những người muốn biến chính xác một ký tự trống thành thiếu, hãy xem giải pháp đơn giản dưới đây
Ted Petrou

Câu trả lời:


198

Tôi nghĩ rằng df.replace()công việc, kể từ gấu trúc 0.13 :

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

# replace field that's entirely space (or empty) with NaN
print(df.replace(r'^\s*$', np.nan, regex=True))

Sản xuất:

                   A    B   C
2000-01-01 -0.532681  foo   0
2000-01-02  1.490752  bar   1
2000-01-03 -1.387326  foo   2
2000-01-04  0.814772  baz NaN
2000-01-05 -0.222552  NaN   4
2000-01-06 -1.176781  qux NaN

Như Temak đã chỉ ra, hãy sử dụng df.replace(r'^\s+$', np.nan, regex=True)trong trường hợp dữ liệu hợp lệ của bạn chứa khoảng trắng.


1
regex là một cờ boolean. Có lẽ bạn có nghĩa là pd.Series(["1", "#", "9", " .", None]).replace(r"( +\.)|#", "X", regex=True).valuescho['1', 'X', '9', 'X', None]
patricksurry

2
Sau 2 năm, tôi đã thay đổi câu trả lời được chấp nhận cho điều này, bây giờ gấu trúc hỗ trợ nó. Cảm ơn!
Chris Clark

35
LƯU Ý : nếu bạn không muốn một phần tử chứa khoảng trống ở giữa được thay thế bằng sử dụng NaNdf.replace(r'^\s+$', np.nan, regex=True)
Temak

7
Tôi đã thử sử dụng cái này, nhưng phát hiện ra rằng r '^ \ s * $' nên là biểu thức để sử dụng. không có ^ và $ nó sẽ khớp với bất kỳ chuỗi nào có hai khoảng trống liên tiếp. Đồng thời thay đổi + thành * để bao gồm chuỗi trống "" trong danh sách những thứ cần chuyển đổi thành NaN
Master Yogurt

1
Tôi đang thử giải pháp của bạn trong mã của tôi, nhưng nó không có hiệu lực. Tôi đang thử "năng lượng [" Cung cấp năng lượng "]. Thay thế (to numplace =" ... ", value = np.NaN)". Muốn thay đổi chuỗi "..." thành giá trị NaN, nhưng nó không làm gì và trả về cùng một khung dữ liệu.
Archan Joshi

49

Nếu bạn muốn thay thế một chuỗi trống và các bản ghi chỉ bằng dấu cách, câu trả lời đúng là !:

df = df.replace(r'^\s*$', np.nan, regex=True)

Câu trả lời được chấp nhận

df.replace(r'\s+', np.nan, regex=True)

Không thay thế một chuỗi trống!, Bạn có thể tự thử với ví dụ đã cập nhật một chút:

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'fo o', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', ''],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

Lưu ý rằng 'fo o' không được thay thế bằng Nan, mặc dù nó chứa một khoảng trắng. Lưu ý thêm, đó là một đơn giản:

df.replace(r'', np.NaN)

Nó cũng không hoạt động - hãy thử nó.


33

Làm thế nào về:

d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)

Các applymapchức năng áp dụng một chức năng để mỗi tế bào của dataframe.


Thật là một cải tiến tốt đẹp! Tôi nên nghĩ về điều này khi nhìn lại, nhưng đã gác máy khi thực hiện thay thế boolean vì một số lý do. Một câu hỏi - có một lợi thế để thực hiện kiểm tra cơ sở so với chỉ str (x) .isspace () không?
Chris Clark

1
@ChrisClark: Một trong hai đều ổn, mặc dù tôi đoán rằng nó isinstancesẽ nhanh hơn một chút.
BrenBarn

13
Tham chiếu đến "basestring" trong đoạn mã trên sẽ không hoạt động trong Python 3 .... trong trường hợp đó, hãy thử sử dụng "str" ​​thay thế.
Spike Williams

4
Lưu ý rằng giải pháp này không thay thế các chuỗi trống ''. Để xem xét các chuỗi trống, sử dụng:d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and (not x or x.isspace()) else x)
tuomastik

18

Tôi sẽ làm điều này:

df = df.apply(lambda x: x.str.strip()).replace('', np.nan)

hoặc là

df = df.apply(lambda x: x.str.strip() if isinstance(x, str) else x).replace('', np.nan)

Bạn có thể tước tất cả str, sau đó thay thế str trống bằng np.nan.


lambda x: x.str.strip () nên là lambda x: x.strip ()? đề nghị nhỏ: thêm .astype (str) ở phía trước, điều này giải quyết các vấn đề dữ liệu khác cho tôi. Điều này hoạt động với tôi: df = df.apply ['cột']. Astype (str) .apply (lambda x: x.strip ()). Thay thế ('', np.nan)
Wouter

Dòng mã thứ hai xử lý cả cột kiểu int / float và kiểu chuỗi. Đẹp. Tks!
Kate Stohr

6

Đơn giản nhất trong tất cả các giải pháp:

df = df.replace(r'^\s+$', np.nan, regex=True)

5

Nếu bạn đang xuất dữ liệu từ tệp CSV, nó có thể đơn giản như sau:

df = pd.read_csv(file_csv, na_values=' ')

Điều này sẽ tạo khung dữ liệu cũng như thay thế các giá trị trống như Na


2
Một tùy chọn khác..sử dụng skipinitialspace=Truecũng loại bỏ bất kỳ khoảng trắng nào sau dấu phân cách sẽ gây ra bất kỳ độ dài của khoảng trắng, các chuỗi trống được đọc là nan. Tuy nhiên nếu bạn muốn giữ lại các không gian ban đầu vì lý do gì thì tùy chọn này không phải là một lựa chọn tốt.
Rajshekar Reddy

1
@RajshekarReddy bạn có thể vui lòng đặt câu hỏi này làm câu trả lời ở đâu đó không, điều này thật tuyệt vời!
Người dùng 2321

2

Đối với một giải pháp rất nhanh và đơn giản trong đó bạn kiểm tra sự bằng nhau đối với một giá trị duy nhất, bạn có thể sử dụng maskphương pháp.

df.mask(df == ' ')

1

Đây là tất cả gần với câu trả lời đúng, nhưng tôi sẽ không nói bất kỳ giải quyết vấn đề trong khi những người khác đọc mã của bạn dễ đọc nhất. Tôi muốn nói rằng câu trả lời là sự kết hợp giữa Câu trả lời của BrenBarn và bình luận của tuomasttik bên dưới câu trả lời đó . Câu trả lời của BrenBarn sử dụng isspacenội dung dựng sẵn, nhưng không hỗ trợ loại bỏ các chuỗi trống, như OP yêu cầu và tôi có xu hướng quy kết đó là trường hợp sử dụng tiêu chuẩn để thay thế chuỗi bằng null.

Tôi viết lại nó với .apply, vì vậy bạn có thể gọi nó trên một pd.Serieshoặc pd.DataFrame.


Con trăn 3:

Để thay thế các chuỗi trống hoặc chuỗi hoàn toàn không gian:

df = df.apply(lambda x: np.nan if isinstance(x, str) and (x.isspace() or not x) else x)

Để thay thế các chuỗi không gian hoàn toàn:

df = df.apply(lambda x: np.nan if isinstance(x, str) and x.isspace() else x)

Để sử dụng điều này trong Python 2, bạn sẽ cần thay thế strbằng basestring.

Con trăn 2:

Để thay thế các chuỗi trống hoặc chuỗi hoàn toàn không gian:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and (x.isspace() or not x) else x)

Để thay thế các chuỗi không gian hoàn toàn:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)

1

Điều này làm việc cho tôi. Khi tôi nhập tệp csv của mình, tôi đã thêm na_values ​​= ''. Không gian không được bao gồm trong các giá trị NaN mặc định.

df = pd.read_csv (filepath, na_values ​​= '')


0

bạn cũng có thể sử dụng bộ lọc để làm điều đó.

df = PD.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '])
    df[df=='']='nan'
    df=df.astype(float)

Mỗi dòng mã này (không bao gồm dữ liệu) đều bị lỗi.
Julius

0
print(df.isnull().sum()) # check numbers of null value in each column

modifiedDf=df.fillna("NaN") # Replace empty/null values with "NaN"

# modifiedDf = fd.dropna() # Remove rows with empty values

print(modifiedDf.isnull().sum()) # check numbers of null value in each column

0

Đây không phải là một giải pháp tao nhã, nhưng những gì dường như hoạt động là tiết kiệm cho XLSX và sau đó nhập lại. Các giải pháp khác trên trang này không hiệu quả với tôi, không biết tại sao.

data.to_excel(filepath, index=False)
data = pd.read_excel(filepath)
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.