我有一个示例数据框显示如下。 对于每一行,我想首先检查c1,如果它不为null,则检查c2。通过这种方式,找到第一个notnull列并将该值存储到列结果。
ID c1 c2 c3 c4 result
1 a b a
2 cc dd cc
3 ee ff ee
4 gg gg
我现在正在使用这种方式。但我想知道是否有更好的方法。(列名没有任何模式,这只是样本)
df["result"] = np.where(df["c1"].notnull(), df["c1"], None)
df["result"] = np.where(df["result"].notnull(), df["result"], df["c2"])
df["result"] = np.where(df["result"].notnull(), df["result"], df["c3"])
df["result"] = np.where(df["result"].notnull(), df["result"], df["c4"])
df["result"] = np.where(df["result"].notnull(), df["result"], "unknown)
当有很多列时,此方法看起来不太好。
答案 0 :(得分:6)
首先使用回填NaN
,然后按iloc
选择第一列:
df['result'] = df[['c1','c2','c3','c4']].bfill(axis=1).iloc[:, 0].fillna('unknown')
或者:
df['result'] = df.iloc[:, 1:].bfill(axis=1).iloc[:, 0].fillna('unknown')
print (df)
ID c1 c2 c3 c4 result
0 1 a b a NaN a
1 2 NaN cc dd cc cc
2 3 NaN ee ff ee ee
3 4 NaN NaN gg gg gg
<强>性能强>:
df = pd.concat([df] * 1000, ignore_index=True)
In [220]: %timeit df['result'] = df[['c1','c2','c3','c4']].bfill(axis=1).iloc[:, 0].fillna('unknown')
100 loops, best of 3: 2.78 ms per loop
In [221]: %timeit df['result'] = df.iloc[:, 1:].bfill(axis=1).iloc[:, 0].fillna('unknown')
100 loops, best of 3: 2.7 ms per loop
#jpp solution
In [222]: %%timeit
...: cols = df.iloc[:, 1:].T.apply(pd.Series.first_valid_index)
...:
...: df['result'] = [df.loc[i, cols[i]] for i in range(len(df.index))]
...:
1 loop, best of 3: 180 ms per loop
#cᴏʟᴅsᴘᴇᴇᴅ' s solution
In [223]: %timeit df['result'] = df.stack().groupby(level=0).first()
1 loop, best of 3: 606 ms per loop
答案 1 :(得分:2)
<强>设置强>
df = df.set_index('ID') # if necessary
df
c1 c2 c3 c4
ID
1 a b a NaN
2 NaN cc dd cc
3 NaN ee ff ee
4 NaN NaN gg gg
<强>解决方案强>
stack
+ groupby
+ first
stack
隐式删除NaN,因此groupby.first
保证在第一个非空值时为其提供。重新分配结果将显示缺失索引处的任何NaN,您可以fillna
进行后续调用。
df['result'] = df.stack().groupby(level=0).first()
# df['result'] = df['result'].fillna('unknown') # if necessary
df
c1 c2 c3 c4 result
ID
1 a b a NaN a
2 NaN cc dd cc cc
3 NaN ee ff ee ee
4 NaN NaN gg gg gg
(注意,这对于较大的数据帧来说速度很慢,因为你可能会使用@ jezrael的解决方案)
答案 2 :(得分:2)
我正在使用lookup
和来自Jpp的数据
df=df.set_index('ID')
s=df.ne('').idxmax(1)
df['Result']=df.lookup(s.index,s)
df
Out[492]:
c1 c2 c3 c4 Result
ID
1 a b a
2 cc dd cc
3 ee ff ee
4 gg gg
答案 3 :(得分:1)
一种方法是使用pd.DataFrame.lookup
并将pd.Series.first_valid_index
应用于转置数据框:
var icollections = new List<string>();
foreach (PropertyInfo property in
typeof(YourProjectName.ContextObject).Assembly
.GetType("YourProjectName.Entities." + Model.ModelTypeName)
.GetProperties())
{
if (property.PropertyType.IsGenericType
&& property.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
icollections.Add(property.Name);
}
}