การลบค่าน่านออกจากอาร์เรย์


223

ฉันต้องการหาวิธีลบค่าน่านออกจากอาร์เรย์ของฉัน อาร์เรย์ของฉันมีลักษณะดังนี้:

x = [1400, 1500, 1600, nan, nan, nan ,1700] #Not in this exact configuration

ฉันจะลบnanค่าออกจากได้xอย่างไร


ต้องมีความชัดเจนโดย "แก่นแก้วลบ" คุณหมายถึงกรองเอาเฉพาะส่วนย่อยของค่าที่ไม่ใช่โมฆะ ไม่ใช่ "เติม NaNs ด้วยค่าบางอย่าง (ศูนย์, ค่าคงที่, ค่าเฉลี่ย, ค่ามัธยฐาน ฯลฯ )"
smci

คำตอบ:


362

หากคุณใช้ numpy สำหรับอาร์เรย์ของคุณคุณยังสามารถใช้

x = x[numpy.logical_not(numpy.isnan(x))]

เท่า

x = x[~numpy.isnan(x)]

[ขอบคุณ chbrown สำหรับชวเลขที่เพิ่ม]

คำอธิบาย

ฟังก์ชั่นด้านในnumpy.isnanส่งกลับอาร์เรย์แบบบูล / ตรรกะซึ่งมีค่าTrueทุกที่ที่xไม่ใช่ -a-number ตามที่เราต้องการตรงกันข้ามเราใช้ตัวดำเนินการแบบลอจิคัล - ไม่ใช่~เพื่อรับอาเรย์ด้วยTrues ทุก ๆ ที่x เป็นจำนวนที่ถูกต้อง

สุดท้ายเราใช้โลจิคัลอาเรย์นี้เพื่อทำดัชนีในอาเรย์ดั้งเดิมxเพื่อดึงค่าที่ไม่ใช่ NaN


31
หรือx = x[numpy.isfinite(x)]
lazy1 1

14
หรือx = x[~numpy.isnan(x)]ซึ่งเทียบเท่ากับคำตอบดั้งเดิมของ mutzmatron แต่สั้นกว่า ในกรณีที่คุณต้องการที่จะเก็บอนันต์ของรอบรู้ว่าnumpy.isfinite(numpy.inf) == Falseแน่นอน ~numpy.isnan(numpy.inf) == Trueแต่
chbrown

8
สำหรับผู้ที่กำลังมองหาวิธีแก้ปัญหานี้ด้วย ndarray และรักษามิติใช้numpy โดยที่ :np.where(np.isfinite(x), x, 0)
BoltzmannBrain

1
TypeError: เพียงจำนวนเต็มอาร์เรย์เกลาสามารถแปลงเป็นดัชนีเกลา
Towry

1
@towry: สิ่งนี้เกิดขึ้นเนื่องจากอินพุตของคุณxไม่ใช่อาร์เรย์ที่มีค่ามาก หากคุณต้องการใช้การทำดัชนีเชิงตรรกะมันจะต้องเป็นอาร์เรย์ - เช่นx = np.array(x)
jmetz

50
filter(lambda v: v==v, x)

ใช้ได้ทั้งกับ list และ numpy array ตั้งแต่ v! = v เฉพาะ NaN เท่านั้น


5
แฮ็ค แต่เป็นประโยชน์อย่างยิ่งในกรณีที่คุณกรอง nans จากอาร์เรย์ของวัตถุที่มีชนิดผสมเช่นสตริงและ nans
Austin Richardson

ทางออกที่สะอาดมาก
Moondra

2
สิ่งนี้อาจดูฉลาด แต่หากปิดบังตรรกะและวัตถุอื่นในทางทฤษฎี (เช่นคลาสที่กำหนดเอง) สามารถมีคุณสมบัตินี้ได้
Chris_Rands

ยังมีประโยชน์เพราะเพียงต้องการที่จะระบุเพียงครั้งเดียวเมื่อเทียบกับโซลูชั่นประเภทx x[~numpy.isnan(x)]สิ่งนี้จะสะดวกเมื่อxถูกกำหนดโดยนิพจน์แบบยาวและคุณไม่ต้องการให้โค้ดยุ่งเหยิงโดยการสร้างตัวแปรชั่วคราวเพื่อเก็บผลลัพธ์ของนิพจน์แบบยาวนี้
Christian O'Reilly

34

ลองสิ่งนี้:

import math
print [value for value in x if not math.isnan(value)]

สำหรับข้อมูลเพิ่มเติมอ่านในรายการ comprehensions


5
หากคุณใช้ทั้งคำตอบของฉันและโดย @ lazy1 เกือบจะเป็นลำดับความสำคัญเร็วกว่าความเข้าใจในรายการ - โซลูชั่นของ lazy1 นั้นเร็วกว่าเล็กน้อยเล็กน้อย
jmetz

อย่าลืมวงเล็บ :)print ([value for value in x if not math.isnan(value)])
hypers

หากคุณใช้ numpy เหมือนคำตอบที่ดีที่สุดคุณสามารถใช้คำตอบนี้เพื่อความเข้าใจกับnpแพ็คเกจ: ดังนั้นส่งคืนรายการของคุณโดยไม่มี nans:[value for value in x if not np.isnan(value)]
yeliabsalohcin


6

ทำข้างต้น:

x = x[~numpy.isnan(x)]

หรือ

x = x[numpy.logical_not(numpy.isnan(x))]

ฉันพบว่าการรีเซ็ตเป็นตัวแปรเดียวกัน (x) ไม่ได้ลบค่าน่านจริงและต้องใช้ตัวแปรอื่น การตั้งค่าให้กับตัวแปรที่แตกต่างลบ nans เช่น

y = x[~numpy.isnan(x)]

มันแปลก ๆ; ตามเอกสารนั้นการทำดัชนีอาเรย์บูลีน (ซึ่งก็คือ) นั้นอยู่ภายใต้การจัดทำดัชนีขั้นสูงซึ่งเห็นได้ชัดว่า "ส่งคืนสำเนาของข้อมูลเสมอ" ดังนั้นคุณควรเขียนทับxด้วยค่าใหม่ (เช่นไม่มี NaNs ... ) . คุณสามารถให้ข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่อาจเกิดขึ้นได้หรือไม่
jmetz

5

ตามที่ปรากฏโดยคนอื่น ๆ

x[~numpy.isnan(x)]

โรงงาน แต่มันจะโยนข้อผิดพลาดถ้า ntyty dtype ไม่ใช่ชนิดข้อมูลดั้งเดิมตัวอย่างเช่นถ้ามันเป็นวัตถุ ในกรณีนี้คุณสามารถใช้นุ่น

x[~pandas.isna(x)] or x[~pandas.isnull(x)]

4

คำตอบที่ได้รับการยอมรับการเปลี่ยนแปลงรูปร่างสำหรับอาร์เรย์ 2 มิติ ฉันขอเสนอวิธีแก้ปัญหาที่นี่โดยใช้ฟังก์ชั่นPandas dropna () มันใช้งานได้กับ 1D และ 2D อาร์เรย์ ในกรณี 2D ท่านสามารถเลือกสภาพอากาศที่จะวางแถวหรือคอลัมน์np.nanที่มี

import pandas as pd
import numpy as np

def dropna(arr, *args, **kwarg):
    assert isinstance(arr, np.ndarray)
    dropped=pd.DataFrame(arr).dropna(*args, **kwarg).values
    if arr.ndim==1:
        dropped=dropped.flatten()
    return dropped

x = np.array([1400, 1500, 1600, np.nan, np.nan, np.nan ,1700])
y = np.array([[1400, 1500, 1600], [np.nan, 0, np.nan] ,[1700,1800,np.nan]] )


print('='*20+' 1D Case: ' +'='*20+'\nInput:\n',x,sep='')
print('\ndropna:\n',dropna(x),sep='')

print('\n\n'+'='*20+' 2D Case: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna (rows):\n',dropna(y),sep='')
print('\ndropna (columns):\n',dropna(y,axis=1),sep='')

print('\n\n'+'='*20+' x[np.logical_not(np.isnan(x))] for 2D: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna:\n',x[np.logical_not(np.isnan(x))],sep='')

ผลลัพธ์:

==================== 1D Case: ====================
Input:
[1400. 1500. 1600.   nan   nan   nan 1700.]

dropna:
[1400. 1500. 1600. 1700.]


==================== 2D Case: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna (rows):
[[1400. 1500. 1600.]]

dropna (columns):
[[1500.]
 [   0.]
 [1800.]]


==================== x[np.logical_not(np.isnan(x))] for 2D: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna:
[1400. 1500. 1600. 1700.]

3

หากคุณกำลังใช้ numpy

# first get the indices where the values are finite
ii = np.isfinite(x)

# second get the values
x = x[ii]

1

วิธีที่ง่ายที่สุดคือ:

numpy.nan_to_num(x)

เอกสารประกอบ: https://docs.scipy.org/doc/numpy/reference/generated/numpy.nan_to_num.html


2
ยินดีต้อนรับสู่ SO! โซลูชันที่คุณเสนอไม่ตอบปัญหา: โซลูชันของคุณใช้แทนNaNจำนวนมากในขณะที่ OP ขอให้ลบองค์ประกอบทั้งหมด
ท่าเรือเปาโล

0

นี่เป็นวิธีการของฉันในการกรองndarray "X" สำหรับ NaN และ infs

ฉันสร้างแผนที่ของแถวโดยไม่ต้องใดNaNinfดังนี้:

idx = np.where((np.isnan(X)==False) & (np.isinf(X)==False))

idx เป็นสิ่งอันดับ มันคือคอลัมน์ที่สอง ( idx[1]) มีดัชนีของอาร์เรย์ที่ไม่มีNaNหรือinfที่พบข้ามแถว

แล้ว:

filtered_X = X[idx[1]]

filtered_Xมี X โดยไม่ต้อง มิได้NaNinf


0

@ คำตอบของ jmetzน่าจะเป็นสิ่งที่คนส่วนใหญ่ต้องการ; อย่างไรก็ตามมันให้ผลเป็นอาร์เรย์หนึ่งมิติเช่นทำให้ไม่สามารถลบแถวหรือคอลัมน์ทั้งหมดในเมทริกซ์ได้

ในการทำเช่นนั้นหนึ่งควรลดอาร์เรย์โลจิคัลเป็นหนึ่งมิติจากนั้นทำดัชนีอาร์เรย์เป้าหมาย ตัวอย่างเช่นต่อไปนี้จะลบแถวที่มีค่า NaN อย่างน้อยหนึ่งค่า:

x = x[~numpy.isnan(x).any(axis=1)]

ดูรายละเอียดเพิ่มเติมที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.