代码之家  ›  专栏  ›  技术社区  ›  ababuji

Pandas/Pythonic方法按X列分组,在每个组中,根据Z列中的值返回Y列中的值

  •  0
  • ababuji  · 技术社区  · 6 年前

    可复制示例:

    df = pd.DataFrame([[1, '2015-12-15', 10],
                       [1, '2015-12-16', 13], 
                       [1, '2015-12-17', 16], 
                       [2, '2015-12-15', 19],
                       [2, '2015-12-11', 22], 
                       [2, '2015-12-18', 25],
                       [3, '2015-12-14', 28], 
                       [3, '2015-12-12', 31], 
                       [3, '2015-12-15', 34]])
    
    df.columns = ['X', 'Y', 'Z']
    print(df.dtypes)
    print()
    print(df)
    

    可复制示例的输出和每个列的数据类型:

    X     int64
    Y    object
    Z     int64
    dtype: object
    
       X           Y   Z
    0  1  2015-12-15  10
    1  1  2015-12-16  13
    2  1  2015-12-17  16
    3  2  2015-12-15  19
    4  2  2015-12-11  22
    5  2  2015-12-18  25
    6  3  2015-12-14  28
    7  3  2015-12-12  31
    8  3  2015-12-15  34
    

    预期产量:

       X           Y   Z
    0  1  2015-12-15  10
    1  1  2015-12-15  10
    2  2  2015-12-11  22
    3  2  2015-12-15  19
    4  3  2015-12-12  31
    5  3  2015-12-15  34
    

    解释输出是什么:

    对于列中的每个组 X 分组后 ,我想要一行的值在列中 Z 其中列中的值 Y 因为那一组是 min(all dates/object in column Y) 同样地 组,另一行的值在列“Z”中,其中值在列中 是的 因为那一组是 some custom date that definitely exists for all groups which will be hardcoded . 所以每组都有两排。

    在我的输出中,对于组 1 ,列中的值 Z轴 10 ,因为列中的值 Z轴 与 列中所有日期的最小值 是的 对于组 , 12-15-2015 . 对于同一组 ,此组的第二行 ,列中的值 Z轴 对于自定义日期 2015年12月15日 也是 . 对于组 2 , min(all dates/objects in column Y) 2015-12-11 ,列中的相应值 Z轴 对于组 列中有值 是的 , 2015年12月11日 22 . 以及定制日期 2015年12月15日 ,它是 19 .

    以下是我为完成此任务而编写的一些线性时间搜索/延迟代码:

    uniqueXs = list(dict(Counter(df['X'].tolist())).keys()) #Get every unique item in column X is a list. 
    df_list = [] #Empty list that will have rows of my final DataFrame
    
    for x in uniqueXs: #Iterate through each unique value in column X
    
        idfiltered_dataframe = df.loc[df['X'] == x] #Filter DataFrame based on the current value in column X 
                                                    #(iterating through list of all values)
    
        min_date = min(idfiltered_dataframe['Y']) #Min of column Y
        custom_date = '2015-12-15' #Every group WILL have this custom date.
    
        mindatefiltered_dataframe = idfiltered_dataframe.loc[idfiltered_dataframe['Y'] == min_date] #Within group, filter rows where column Y has minimum date
        customdatefiltered_dataframe = idfiltered_dataframe.loc[idfiltered_dataframe['Y'] == custom_date]  #Within group, filter rows where column Y has a custom date
    
        for row_1 in mindatefiltered_dataframe.index: #Iterate through mindatefiltered DataFrame and create list of each row value required
    
            row_list = [mindatefiltered_dataframe.at[row_1, 'X'], mindatefiltered_dataframe.at[row_1, 'Y'], mindatefiltered_dataframe.at[row_1, 'Z']]
            df_list.append(row_list) #Append to a master list
    
        for row_2 in customdatefiltered_dataframe.index: #Iterate through customdatefiltered DataFrame and create list of each row value required
    
            row_list = [customdatefiltered_dataframe.at[row_2, 'X'], customdatefiltered_dataframe.at[row_2, 'Y'], customdatefiltered_dataframe.at[row_2, 'Z']]
            df_list.append(row_list) #Append to a master list
    
    
    
    print(pd.DataFrame(df_list)) #Create DataFrame out of the master list
    

    我的印象是有一些巧妙的方法,你只是 df.groupby.. 得到预期的输出,我希望有人能给我提供这样的代码。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Vivek Kalyanarangan    6 年前

    使用-

    date_fill = dt.datetime.strptime('2015-12-15', '%Y-%m-%d')
    df['Y'] = pd.to_datetime(df['Y'], format='%Y-%m-%d')
    
    df_g = df.loc[df.groupby(['X'])['Y'].idxmin()]
    df2 = df[df['Y']==date_fill]
    target_map = pd.Series(df2['Z'].tolist(),index=df2['X']).to_dict()
    df_g.index = range(1, 2*len(df_g)+1, 2)
    df_g = df_g.reindex(index=range(2*len(df_g)))
    df_g['Y'] = df_g['Y'].fillna(date_fill)
    df_g = df_g.bfill()
    df_g.loc[df_g['Y']==date_fill, 'Z'] = df_g[df_g['Y']==date_fill]['X'].map(target_map)
    df_g = df_g.bfill()
    print(df_g)
    

    输出

         X          Y     Z
    0  1.0 2015-12-15  10.0
    1  1.0 2015-12-15  10.0
    2  2.0 2015-12-15  19.0
    3  2.0 2015-12-11  22.0
    4  3.0 2015-12-15  34.0
    5  3.0 2015-12-12  31.0
    

    解释

    1. 输入所需的自定义日期 date_fill
    2. df.groupby(['X'])['Y'].idxmin() 按行 min 属于 Y
    3. target_map 是为了保存 Z 以后的值
    4. 下一个 df_g 扩大到 na 值每个替换列
    5. df_g = df_g.bfill() 两次来,以防您输入日期 日期填充 这不存在于 df . 那样的话 目标地图 不会填充,你最终会得到 不适用 价值观。

    我相信这是可以优化一些,但思考过程应该有助于你继续。

        2
  •  2
  •   user3483203    6 年前

    IIUC公司

    g1=df.groupby('X').Y.value_counts().count(level=1).eq(df.X.nunique()) # get group1 , all date should show in three groups , we using value_counts
    df.Y=pd.to_datetime(df.Y) # change to date format in order to sort
    g2=df.sort_values('Y').groupby('X').head(1) # get the min date row . 
    
    pd.concat([df.loc[df.Y.isin(g1[g1].index)],g2]).sort_index() # combine all together 
    Out[280]: 
       X          Y   Z
    0  1 2015-12-15  10
    0  1 2015-12-15  10
    3  2 2015-12-15  19
    4  2 2015-12-11  22
    7  3 2015-12-12  31
    8  3 2015-12-15  34