在不删除所有NaN的情况下在python中融合不完整的数据

时间:2018-07-22 04:50:25

标签: python pandas dataframe categorical-data melt

我正在尝试使用pd.melt将3列融为一类。目前,数据框看起来像这样。

for (int i = 0; i < stfArray.Length; i++)
{
    stfArray[i] = new stfArray(Readline spot 1, Readline spot 2, Readline spot3)
}

在某些时候,我用NaN代替了None,但是不确定在融化之前是否有必要。我的目标是要有1个类别列,其中列出了它的车辆类型,只有在所有列都为空的情况下才使用None。

    id1   Plane  Car   Boat
0   123   None   None  None
1   124   Plane  None  None
2   125   None   None  Boat

我想到的代码是这样的:

    id1   Type
0   123   None   
1   124   Plane  
2   125   Boat   

我的问题是,它使数据框中的观察值增加了三倍。我可以过滤掉Type = None的行,但是会删除数据,例如id1 = 123,其中所有原始三列均为None。

df = pd.melt(df, id_vars=['id1'], var_name='Type')

有没有一种有效的方法来融化?还是我需要遍历数据并使用条件语句写入新的数据框?

4 个答案:

答案 0 :(得分:2)

您可以这样做。使用reindex来获取那些丢失的id值。

df1 = df.replace('None',np.nan).set_index('id1')
df1.stack().reset_index(level=1, drop=True).reindex(df1.index)

输出:

id1
123      NaN
124    Plane
125     Boat
dtype: object

答案 1 :(得分:2)

您可以使用回填缺失值,然后按位置选择第一列-通过iloc

df = df.replace('None', np.nan)

df = df.set_index('id1').bfill(axis=1).iloc[:, 0].rename('Type').reset_index()
print (df)
   id1   Type
0  123    NaN
1  124  Plane
2  125   Boat

如果性能可能很重要,则可以在numpy中使用justify函数进行2次更改:

def justify(a, invalid_val=0, axis=1, side='left'):    
    """
    Justifies a 2D array

    Parameters
    ----------
    A : ndarray
        Input array to be justified
    axis : int
        Axis along which justification is to be made
    side : str
        Direction of justification. It could be 'left', 'right', 'up', 'down'
        It should be 'left' or 'right' for axis=1 and 'up' or 'down' for axis=0.

    """

    if invalid_val is np.nan:
        mask = pd.notnull(a) <- change to notnull
    else:
        mask = a!=invalid_val
    justified_mask = np.sort(mask,axis=axis)
    if (side=='up') | (side=='left'):
        justified_mask = np.flip(justified_mask,axis=axis)
    out = np.full(a.shape, invalid_val, dtype=object)  <- change dtype to object
    if axis==1:
        out[justified_mask] = a[mask]
    else:
        out.T[justified_mask.T] = a.T[mask.T]
    return out

numpy中的想法相同-新数据框由assign1d array创建:

arr = df.replace('None', np.nan).values[:, 1:]
out = justify(arr, invalid_val=np.nan)[:, 0]
print (out)
[nan 'Plane' 'Boat']

df = df[['id1']].assign(Type=out)
print (df)
   id1   Type
0  123    NaN
1  124  Plane
2  125   Boat

答案 2 :(得分:1)

无需使用pd.melt,只需使用以下内容即可:

df=df.replace('None',pd.np.nan)
df['final']=df.apply(lambda a: pd.Series(a[1:]).dropna()[0] if len(pd.Series(a[1:]).dropna())!=0 else pd.np.nan,axis=1)
print(df[['id1','final']])

输出:

   id1  final
0  123    NaN
1  124  Plane
2  125   Boat

答案 3 :(得分:1)

您可以通过从转置数据帧中获取相关行,将None转换为空字符串并求和如下所示的值来获得此结果。

输入:

from io import StringIO
df = pd.read_table(StringIO("""    id1   Plane  Car   Boat
0   123   None   None  None
1   124   Plane  None  None
2   125   None   None  Boat"""), delimiter="\s+")
df
Out[229]: 
   id1  Plane   Car  Boat
0  123   None  None  None
1  124  Plane  None  None
2  125   None  None  Boat

代码:

df["Type"] = df.T.iloc[1:].replace({"None":""}).sum().replace({"":"None"})
df.drop(columns=['Plane', 'Car', 'Boat'], inplace=True)

输出:

df
Out[231]: 
   id1   Type
0  123   None
1  124  Plane
2  125   Boat