在不丢弃所有 NaN 的情况下融化 python 中的不完整数据
Melting incomplete data in python without dropping all NaN
我正在尝试使用 pd.melt 将 3 列合并为一个分类列。目前,数据框看起来像这样。
id1 Plane Car Boat
0 123 None None None
1 124 Plane None None
2 125 None None Boat
有时,我将 None 替换为 NaN,但我不确定在熔化之前是否有必要这样做。我的目标是拥有 1 个类别列,其中列出了车辆的类型,仅当所有列都为空时才使用 None。
id1 Type
0 123 None
1 124 Plane
2 125 Boat
我想出的代码是这样的:
df = pd.melt(df, id_vars=['id1'], var_name='Type')
我遇到的问题是它使我的数据框中的观察结果增加了三倍。我可以过滤掉 Type = None 的行,但这会删除 id1 = 123 等数据,其中所有三个原始列都是 None.
id1 Type
0 123 None
1 123 None
2 123 None
3 124 Plane
4 124 None
5 124 None
有没有一种有效的方法可以用 melt 做到这一点?或者我是否需要遍历数据并写入带有条件的新数据框?
你和这样做。使用 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
不用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
您可以使用回填缺失值和 tehn select 第一列的位置 - by 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
中的 函数并进行 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 中的相同想法 - 新 Dataframe 由 assign
由 1d 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
您可以通过从转置数据帧中获取相关行,将 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
我正在尝试使用 pd.melt 将 3 列合并为一个分类列。目前,数据框看起来像这样。
id1 Plane Car Boat
0 123 None None None
1 124 Plane None None
2 125 None None Boat
有时,我将 None 替换为 NaN,但我不确定在熔化之前是否有必要这样做。我的目标是拥有 1 个类别列,其中列出了车辆的类型,仅当所有列都为空时才使用 None。
id1 Type
0 123 None
1 124 Plane
2 125 Boat
我想出的代码是这样的:
df = pd.melt(df, id_vars=['id1'], var_name='Type')
我遇到的问题是它使我的数据框中的观察结果增加了三倍。我可以过滤掉 Type = None 的行,但这会删除 id1 = 123 等数据,其中所有三个原始列都是 None.
id1 Type
0 123 None
1 123 None
2 123 None
3 124 Plane
4 124 None
5 124 None
有没有一种有效的方法可以用 melt 做到这一点?或者我是否需要遍历数据并写入带有条件的新数据框?
你和这样做。使用 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
不用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
您可以使用回填缺失值和 tehn select 第一列的位置 - by 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
中的
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 中的相同想法 - 新 Dataframe 由 assign
由 1d 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
您可以通过从转置数据帧中获取相关行,将 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