Pandalarda boş değerleri (beyaz boşluk) NaN ile değiştirme


163

Beyaz boşluk (herhangi bir miktar) içeren bir Pandas veri çerçevesindeki tüm değerleri bulmak ve bu değerleri NaN'lerle değiştirmek istiyorum.

Bunun nasıl geliştirilebileceğine dair bir fikriniz var mı?

Temel olarak şunu döndürmek istiyorum:

                   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     

Bunun içine:

                   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

Bunu aşağıdaki kodla yapmayı başardım, ama adamım bu çirkin. Pythonic değil ve eminim pandaların en verimli kullanımı da değildir. Her sütunda döngü yapıyorum ve beyaz boşluklarla eşleşen her bir değer için normal ifade araması yapan bir işlev uygulayarak oluşturulan bir sütun maskesine karşı boole değişimi yapıyorum.

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

Yalnızca boş dizeler içerebilen alanlar arasında yineleme yapılarak biraz optimize edilebilir:

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

Ama bu pek bir gelişme değil

Ve son olarak, bu kod, hedef dizeleri, Pandaların gibi işlevlerle çalışan Yok olarak ayarlar fillna(), ancak NaNyerine doğrudan yerine bir ekleyebilseydim, bütünlük için iyi olurdu None.


2
Gerçekten istediğiniz şey replacebir normal ifadeyle kullanabilmektir ... (belki bu bir özellik olarak talep edilmelidir).
Andy Hayden

3
Bu özellik için bir github sorunu yaptım: github.com/pydata/pandas/issues/2285 . Halkla ilişkiler için minnettar olurum! :)
Chang She

Tam olarak tek bir boş karakteri eksik yapmak isteyenler için, aşağıdaki basit çözüme bakın
Ted Petrou

Yanıtlar:


215

Sanırım pandalar 0.13'tendf.replace() beri bu işi yapıyor :

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))

Üretir:

                   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

As TEMAK o çekti, kullanmak df.replace(r'^\s+$', np.nan, regex=True)ihtimaline karşı geçerli veri beyaz boşluklar içeriyor.


1
regex bir boole bayrağıdır. Belki de pd.Series(["1", "#", "9", " .", None]).replace(r"( +\.)|#", "X", regex=True).valueshangisini verir demek istiyorsun['1', 'X', '9', 'X', None]
patricksurry

2
2 yıl sonra, pandalar bunu desteklediğine göre, kabul edilen cevabı değiştirdim. Teşekkürler!
Chris Clark

37
NOT : Ortada boşluk içeren bir öğenin NaN kullanımıyla değiştirilmesini istemiyorsanızdf.replace(r'^\s+$', np.nan, regex=True)
Temak

7
Bunu kullanmayı denedim, ancak r '^ \ s * $' ifadesinin kullanılacak ifade olması gerektiğini öğrendim. ^ ve $ olmadan iki ardışık boşluk içeren herhangi bir dizeyle eşleşir. Ayrıca, NaN'ye dönüştürülecek şeyler listesine "" boş dizesini içerecek şekilde + olarak değiştirildi
Master Yogurt

1
Çözümünüzü kodumda deniyorum ama hiçbir etkisi olmadı. "Enerji [" Enerji Kaynağı "] deniyorum. Değiştir (to_replace =" ... ", değer = np.NaN)". "..." dizesini NaN değerlerine değiştirmek istiyor, ancak hiçbir şey yapmıyor ve aynı veri çerçevesini döndürüyor.
Archan Joshi

57

Eğer boş bir dize ve sadece boşluklarla kayıtları değiştirmek istiyorsanız, Doğru cevap !:

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

Kabul edilen cevap

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

Boş bir dizginin yerini almaz!, Biraz güncellenen verilen örnekle kendiniz deneyebilirsiniz:

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'))

Ayrıca, boşluk içermesine rağmen 'fo o'nun Nan ile değiştirilmediğini unutmayın. Ayrıca şunu unutmayın, basit:

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

Ya da işe yaramıyor - deneyin.


33

Peki ya:

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

applymapFonksiyon dataframe her hücreye işlev uygular.


Ne güzel bir gelişme! Geriye dönüp baktığımda bunu düşünmeliydim, ancak bir nedenden ötürü boole değiştirmeleri yapmaya takılı kaldım. Bir soru - sadece str (x) .isspace () yerine basestring kontrolü yapmanın bir avantajı var mı?
Chris Clark

1
@ChrisClark: Her ikisi de iyi, ancak isinstancebiraz daha hızlı olacağını tahmin ediyorum .
BrenBarn

13
Yukarıdaki kodda "basestring" referansı Python 3'te çalışmayacaktır .... bu durumda, bunun yerine "str" ​​kullanmayı deneyin.
Spike Williams

4
Bu çözümün boş dizelerin yerini almadığını unutmayın ''. Boş dizeleri de dikkate almak için şunu kullanın:d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and (not x or x.isspace()) else x)
tuomastik

18

Bunu yapacağım:

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

veya

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

Tüm dizeleri soyabilir, ardından boş dizeleri değiştirebilirsiniz np.nan.


lambda x: x.str.strip () lambda x: x.strip () olmalıdır? küçük öneri: önüne .astype (str) ekleyin, bu benim için diğer veri sorunlarını çözer. Bu benim için çalışıyor: df = df.apply ['column']. Astype (str) .apply (lambda x: x.strip ()). Replace ('', np.nan)
Wouter

İkinci kod satırı hem int / float hem de string türü sütunlarını işler. Güzel. Tks!
Kate Stohr

6

Tüm çözümlerin en basiti:

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

5

Verileri CSV dosyasından dışa aktarıyorsanız, bu kadar basit olabilir:

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

Bu, veri çerçevesini oluşturacak ve boş değerleri Na olarak değiştirecektir.


2
Başka bir seçenek .. kullanmak skipinitialspace=True, sınırlayıcıdan sonra herhangi bir uzunluktaki beyaz boşluğa, boş dizelerin okunmasına neden olacak tüm boşlukları da kaldırır nan. Bununla birlikte, başlangıçtaki boşlukları herhangi bir nedenle korumak istiyorsanız, bu seçenek iyi bir seçim değildir.
Rajshekar Reddy

1
@RajshekarReddy, lütfen bunu cevap olarak bir yere koyar mısın, bu mükemmeldi!
Kullanıcı2321

2

Tek bir değere karşı eşitliği kontrol ettiğiniz çok hızlı ve basit bir çözüm için maskyöntemi kullanabilirsiniz .

df.mask(df == ' ')

1

Bunların hepsi doğru cevaba yakın, ancak kodunuzu okuyan diğerlerine en çok okunabilir kalarak sorunu çözemeyeceğim. Cevabın, BrenBarn'ın Cevabı ve tuomasttik'in bu cevabın altındaki yorumunun bir kombinasyonu olduğunu söyleyebilirim . BrenBarn'ın cevabı isspaceyerleşik kullanır , ancak OP'nin talep ettiği gibi boş dizelerin kaldırılmasını desteklemez ve bunu dizeleri null ile değiştirmenin standart kullanım durumu olarak nitelendirme eğilimindeyim.

.applyİle yeniden yazdım , böylece bir pd.Seriesveya üzerinde diyebilirsiniz pd.DataFrame.


Python 3:

Boş dizeleri veya tamamen boşluklardan oluşan dizeleri değiştirmek için:

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

Tamamen boşluklardan oluşan dizeleri değiştirmek için:

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

Python 2'de bu kullanmak için, değiştirmeniz gerekir strile basestring.

Python 2:

Boş dizeleri veya tamamen boşluklardan oluşan dizeleri değiştirmek için:

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

Tamamen boşluklardan oluşan dizeleri değiştirmek için:

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

1

Bu benim için çalıştı. Csv dosyamı içe aktardığımda na_values ​​= '' ekledim. Boşluklar, varsayılan NaN değerlerine dahil edilmez.

df = pd.read_csv (dosya yolu, na_values ​​= '')


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

Bu zarif bir çözüm değil, ancak işe yarayan şey XLSX'e kaydetmek ve ardından onu geri almaktır. Bu sayfadaki diğer çözümler benim için işe yaramadı, nedenini bilmiyorum.

data.to_excel(filepath, index=False)
data = pd.read_excel(filepath)

0

Bu çalışmalı

df.loc[df.Variable == '', 'Variable'] = 'Value'

veya

df.loc[df.Variable1 == '', 'Variable2'] = 'Value'

-1

bunu yapmak için bir filtre de kullanabilirsiniz.

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)

1
Bu kodun her satırı (veri hariç) hatalıdır.
Julius
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.