簡體   English   中英

僅使用 Pandas 來填補空白,而不是在末端使用 NaN

[英]Using pandas to fill gaps only, and not NaNs on the ends

我有一些跨越大約 8 個月的房價數據,並跟蹤房屋上市直至售出時的價格。 我想填充中間的數據中的幾個空白,但我想保留每個末尾的 NaN 不變。

舉一個簡單的例子,假設我們有 house1,它在“第 4 天”以 200000 的價格上市,在“第 9 天”以 190000 的價格出售。 我們的 house2 在第 1 天到第 12 天保持在 180000 並且在那個時間窗口內不出售。 但是,第 6 天和第 7 天出了點問題,我丟失了數據:

house1 = [NaN, NaN, NaN, 200000, 200000, NaN, NaN, 200000, 190000, NaN, NaN, NaN]
house2 = [180000, 180000, 180000, 180000, 180000, NaN, NaN, 180000, 180000, 180000, 180000, 180000]

現在想象一下,這些是 Pandas Dataframes 中按日期索引的列,而不是常規數組。

問題是,我通常用來填補這里空白的函數是DataFrame.fillna()使用 backfill 或 ffill 方法。 如果我使用填充,house1 會返回:

house1 = [NaN, NaN, NaN, 200000, 200000, 200000, 200000, 200000, 190000, 190000, 190000, 190000]

這填補了空白,但也錯誤地填充了銷售日之后的數據。 如果我改用回填,我會得到這個:

house1 = [200000, 200000, 200000, 200000, 200000, 200000, 200000, 200000, 190000, NaN, NaN, NaN]

再次,它填補了空白,但這次它也填補了數據的前端。 如果我將 'limit=2' 與填充一起使用,那么我得到的是:

house1 = [NaN, NaN, NaN, 200000, 200000, 200000, 200000, 200000, 190000, 190000, 190000, NaN]

它再次填補了空白,但隨后它也開始填充超出“真實”數據結束位置的數據。

到目前為止,我的解決方案是編寫以下函數:

def fillGaps(houseDF):
    """Fills up holes in the housing data"""

    def fillColumns(column):
        filled_col = column
        lastValue = None
        # Keeps track of if we are dealing with a gap in numbers
        gap = False
        i = 0
        for currentValue in filled_col:
            # Loops over all the nans before the numbers begin
            if not isANumber(currentValue) and lastValue is None:
                pass
            # Keeps track of the last number we encountered before a gap
            elif isANumber(currentValue) and (gap is False):
                lastIndex = i
                lastValue = currentValue
            # Notes when we encounter a gap in numbers
            elif not isANumber(currentValue):
                gap = True
            # Fills in the gap
            elif isANumber(currentValue):
                gapIndicies = range(lastIndex + 1, i)
                for j in gapIndicies:
                    filled_col[j] = lastValue
                gap = False
            i += 1
        return filled_col

    filled_df = houseDF.apply(fillColumns, axis=0)
    return filled_df

它只是跳過前面的所有 NaN,填充間隙(由真實值之間的 NaN 組定義),並且最后不填充 NaN。

有沒有更干凈的方法來做到這一點,或者我不知道的內置熊貓功能?

一年后我找到了這個答案,但需要它在具有多列的 DataFrame 上工作,所以我想把我的解決方案留在這里,以防其他人需要同樣的解決方案。 我的功能只是YS-L的修改版

def fillna_downbet(df):
    df = df.copy()
    for col in df:
        non_nans = df[col][~df[col].apply(np.isnan)]
        start, end = non_nans.index[0], non_nans.index[-1]
        df[col].loc[start:end] = df[col].loc[start:end].fillna(method='ffill')
    return df

謝謝!

具有多列的 DataFrame 的另一種解決方案

df.fillna(method='ffill') + (df.fillna(method='bfill') * 0)

它是如何工作的?

第一個fillna執行值的前向填充。 這幾乎就是我們想要的,除了它在每個系列的末尾留下一串填充值。

第二個fillna對我們乘以零的值進行向后填充。 結果是我們不需要的尾隨值將是 NaN,而其他所有值都將是 0。

最后,我們將兩者相加,利用 x + 0 = x 和 x + NaN = NaN 的事實。

您可以在系列的某些部分使用fillna 根據您的描述, fillna應該只在第一個非 NaN 之后和最后一個非 NaN 之前填充 NaN:

import numpy as np
import pandas as pd


def fill_column(house):
    house = house.copy()
    non_nans = house[~house.apply(np.isnan)]
    start, end = non_nans.index[0], non_nans.index[-1]
    house.ix[start:end] = house.ix[start:end].fillna(method='ffill')
    return house


house1 = pd.Series([np.nan, np.nan, np.nan, 200000, 200000, np.nan, np.nan, 200000, 190000, np.nan, np.nan, np.nan])
print fill_column(house1)

輸出:

0        NaN
1        NaN
2        NaN
3     200000
4     200000
5     200000
6     200000
7     200000
8     190000
9        NaN
10       NaN
11       NaN

請注意,這假設系列包含至少兩個非 NaN,對應於第一天和最后一天的價格。

這是一個適用於現代熊貓 (>=1.1) 的函數,有多個間隙,完全沒有間隙,最重要的是, .groupby()

def fill_gap(s, method="ffill"):
    """Fills true gap in series."""
    col = s.copy()
    first_idx = col.first_valid_index()
    last_idx = col.last_valid_index()
    col.loc[first_idx:last_idx] = col.loc[first_idx:last_idx].fillna(method=method)
    return col

確保索引嚴格升序!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM