首页 > 解决方案 > 熊猫。基于缺失值和列名的新列

问题描述

假设我们有以下df:

+---+---------+---------+--------+-------+
|   |  2016   |  2017   |  2018  | 2019  |
+---+---------+---------+--------+-------+
| 0 | 26560.0 | 26810.0 | NaN    | NaN   |
| 1 |   570.0 | NaN     | 550.0  | 540.0 |
| 2 |  3770.0 | 3450.0  | 3210.0 | NaN   |
| 3 |  4320.0 | NaN     | NaN    | NaN   |
+---+---------+---------+--------+-------+

我想添加两个额外的列“价值”和“年份”。在 'value' 列中将有最近一年的值,在 'year' 列中应该有最近一年没有缺失值:

+---+---------+---------+--------+-------+---------+------+
|   |  2016   |  2017   |  2018  | 2019  |  value  | year |
+---+---------+---------+--------+-------+---------+------+
| 0 | 26560.0 | 26810.0 | NaN    | NaN   | 26810.0 | 2017 |
| 1 |   570.0 | NaN     | 550.0  | 540.0 |   540.0 | 2019 |
| 2 |  3770.0 | 3450.0  | 3210.0 | NaN   |  3210.0 | 2018 |
| 3 |  4320.0 | NaN     | NaN    | NaN   |  4320.0 | 2016 |
+---+---------+---------+--------+-------+---------+------+

你能帮我解决它吗?谢谢!

标签: pythonpandasdataframe

解决方案


用于DataFrame.assign新列,首先通过按位置选择最后一列向前填充每行的缺失值,然后按位置获取最后一个非缺失值DataFrame.idxmax,但必须通过索引更改列的顺序:

df1 = df.assign(value = df.ffill(axis=1).iloc[:, -1],
                year = df.notna().iloc[:, ::-1].idxmax(axis=1))
print (df1)
      2016     2017    2018   2019    value  year
0  26560.0  26810.0     NaN    NaN  26810.0  2017
1    570.0      NaN   550.0  540.0    540.0  2019
2   3770.0   3450.0  3210.0    NaN   3210.0  2018
3   4320.0      NaN     NaN    NaN   4320.0  2016

上述解决方案仅在至少存在非缺失值时才有效,numpy.where如果不存在 val,则用于缺失值的一般解决方案:

print (df)
      2016     2017    2018   2019
0  26560.0  26810.0     NaN    NaN
1    570.0      NaN   550.0  540.0
2   3770.0   3450.0  3210.0    NaN
3      NaN      NaN     NaN    NaN

mask = df.notna()
df2 = df.assign(value = df.ffill(axis=1).iloc[:, -1],
               year = np.where(mask.any(axis=1), mask.iloc[:, ::-1].idxmax(axis=1), np.nan))
print (df2)
      2016     2017    2018   2019    value  year
0  26560.0  26810.0     NaN    NaN  26810.0  2017
1    570.0      NaN   550.0  540.0    540.0  2019
2   3770.0   3450.0  3210.0    NaN   3210.0  2018
3      NaN      NaN     NaN    NaN      NaN   NaN

如果某些行仅包含缺失值,则另一个想法DataFrame.stack也可以使用:DataFrame.drop_duplicates

df2 = df.join(df.stack()
                .reset_index(name='value')
                .drop_duplicates('level_0', keep='last')
                .rename(columns={'level_1':'year'})
                .set_index('level_0')
                [['value','year']])
print (df2)
      2016     2017    2018   2019    value  year
0  26560.0  26810.0     NaN    NaN  26810.0  2017
1    570.0      NaN   550.0  540.0    540.0  2019
2   3770.0   3450.0  3210.0    NaN   3210.0  2018
3   4320.0      NaN     NaN    NaN   4320.0  2016

df2 = df.join(df.stack()
                .reset_index(name='value')
                .drop_duplicates('level_0', keep='last')
                .rename(columns={'level_1':'year'})
                .set_index('level_0')
                [['value','year']])
print (df2)
      2016     2017    2018   2019    value  year
0  26560.0  26810.0     NaN    NaN  26810.0  2017
1    570.0      NaN   550.0  540.0    540.0  2019
2   3770.0   3450.0  3210.0    NaN   3210.0  2018
3      NaN      NaN     NaN    NaN      NaN   NaN

推荐阅读