首页 > 解决方案 > 如何在分组后合并列并选择熊猫数据框中其他列的第一个有效值?

问题描述

我有一个形式的熊猫数据框:

df

    ID    col_1    col_2    col_3    Date
     1              20       40      1/1/2018
     1     10                        1/2/2018
     1     50                60      1/3/2018
     3     40       10       90      1/1/2018
     4              80       80      1/1/2018

问题是,我需要创建一个新的数据框,其中包含每列的第一个有效值,但还需要从“日期”派生的其他列,这些列对应于这些值在原始数据框中匹配的时间。

换句话说:

新的_df

    ID    first_col_1    Date_col_1    first_col_2    Date_col_2    first_col_3    Date_col_3
    1         10          1/2/2018          20         1/1/2018         40         1/1/2018 
    3         40          1/1/2018          10         1/1/2018         90         1/1/2018 
    4                     1/1/2018          80         1/1/2018         80         1/1/2018

我了解获取每个 ID 每列的第一个有效值就像

df.groupby('ID').first()

但是如何提取每列的相关“日期”信息?

标签: pythonpandasnumpydataframe

解决方案


您不需要循环,但您确实需要在分组操作之前“融化”您的数据框。

所以开始:

from io import StringIO
import pandas
f = StringIO("""\
ID,col_1,col_2,col_3,Date
1,,20,40,1/1/2018
1,10,,,1/2/2018
1,50,,60,1/3/2018
3,40,10,90,1/1/2018
4,,80,80,1/1/2018
""")

df = pandas.read_csv(f)

然后您可以:

print(
    df.melt(id_vars=['ID', 'Date'], value_vars=['col_1', 'col_2', 'col_3'], value_name='first')
      .groupby(by=['ID', 'variable'])
      .first()
      .unstack(level='variable')
)

这给了你:

              Date                     first            
variable     col_1     col_2     col_3 col_1 col_2 col_3
ID                                                      
1         1/1/2018  1/1/2018  1/1/2018  10.0  20.0  40.0
3         1/1/2018  1/1/2018  1/1/2018  40.0  10.0  90.0
4         1/1/2018  1/1/2018  1/1/2018   NaN  80.0  80.0

这些列是多层次的,因此如果您愿意,我们可以对它们进行一些润色:

def flatten_columns(df, sep='_'):
    newcols = [sep.join(_) for _ in df.columns]
    return df.set_axis(newcols, axis='columns', inplace=False)

print(
    df.melt(id_vars=['ID', 'Date'], value_vars=['col_1', 'col_2', 'col_3'], value_name='first')
      .groupby(by=['ID', 'variable'])
      .first()
      .unstack(level='variable')
      .sort_index(level='variable', axis='columns')
      .pipe(flatten_columns)
)

这给了你一些与你的例子不太一样的列顺序,但它和我想的一样接近。

   Date_col_1  first_col_1 Date_col_2  first_col_2 Date_col_3  first_col_3
ID                                                                        
1    1/1/2018         10.0   1/1/2018         20.0   1/1/2018         40.0
3    1/1/2018         40.0   1/1/2018         10.0   1/1/2018         90.0
4    1/1/2018          NaN   1/1/2018         80.0   1/1/2018         80.0

推荐阅读