【问题标题】:How Loop Through Index Based on Lists of Start and End Values While Assigning New Values to New Column在为新列分配新值时如何根据开始和结束值列表循环索引
【发布时间】:2020-06-13 21:02:37
【问题描述】:

短版:我需要遍历条件数据框以使用一列开始值、结束值和分配值来分配值。第二个数据框拥有我需要在列中分配“分配值”的值。

以下是我正在尝试做的简化版本。我正在使用从导入的 CSV 创建的两个单独的数据框。一个导入的 CSV 文件拥有开始、结束和分配类别。第二个包含我需要分配的实际值,我也需要分配类别的值列表。总的来说,我知道问这个问题似乎很奇怪,但这就是我获取数据的方式,并且在给定的大量列表中手动处理 Excel 和单独类别的标签需要更多时间。

为了方便起见,我创建了与索引号匹配的值名称,但在我的真实文件中,这些名称与索引号不匹配。

这是包含我的开始、结束和分配值的标准数据框

Start     End     Category
1          15       Dog
16         19       Rabbit
20         23       Bat

这就是我想要处理的当前数据框的样子

    Items      
    Item 1        
    Item 2        
    Item 3        
    Item 4        
    Item 5        
    .
    .
    .
    Item 16       
    Item 17       
    Item 18       
    Item 19       
    Item 20       
    Item 21       
    Item 22   

这就是我希望数据框变成的样子

Items       New Column
Item 1        Dog
Item 2        Dog
Item 3        Dog
Item 4        Dog
Item 5        Dog
.
.
.
Item 16       Rabbit
Item 17       Rabbit
Item 18       Rabbit
Item 19       Rabbit
Item 20       Bat
Item 21       Bat
Item 22       Bat

【问题讨论】:

    标签: python loops dataframe


    【解决方案1】:

    解决问题的一种方法是对New Column 应用新值,同时在StartEnd 每行值创建的范围内过滤您的第一个数据框,如下例所示:

    import pandas as pd
    
    
    def assign_value(row, df):
        index = int(row['Items'].replace('Item ', ''))
        # Check if index is in the df start ranges
        _df = df.loc[[index in elm for elm in df['Range'].values]]
        if not _df.empty:
            return _df.iloc[0]['Category']
        return None
    
    
    start_rows = [(1, 15, 'Dog'), (16, 19, 'Rabbit'), (20, 23, 'Bat')]
    df_start = pd.DataFrame(start_rows, columns=['Start', 'End', 'Category'])
    # Create a new column with a range from start to end + 1
    df_start['Range'] = df_start.apply(lambda row: range(row['Start'], row['End'] + 1), axis=1)
    df = pd.DataFrame([f'Item {elm}' for elm in range(1, 23)], columns=['Items'])
    df['New Column'] = df.apply(lambda row: assign_value(row, df_start), axis=1)
    print(df)
    

    输出:

          Items New Column
    0    Item 1        Dog
    1    Item 2        Dog
    2    Item 3        Dog
    3    Item 4        Dog
    4    Item 5        Dog
    5    Item 6        Dog
    6    Item 7        Dog
    7    Item 8        Dog
    8    Item 9        Dog
    9   Item 10        Dog
    10  Item 11        Dog
    11  Item 12        Dog
    12  Item 13        Dog
    13  Item 14        Dog
    14  Item 15        Dog
    15  Item 16     Rabbit
    16  Item 17     Rabbit
    17  Item 18     Rabbit
    18  Item 19     Rabbit
    19  Item 20        Bat
    20  Item 21        Bat
    21  Item 22        Bat
    

    或者你可以简单地(如果你的起始数据框很小)你可以使用这个分配函数:

    def assign_value(row, df):
        for _, elm in df.iterrows():
            index = int(row['Items'].replace('Item ', ''))
            if index in range(elm['Start'], elm['End'] + 1):
                return elm['Category']
        return None
    

    【讨论】:

      【解决方案2】:

      在标准数据框上,创建一个列,其中每个单元格都是一个大小为end - start 的列表(列表的内容无关紧要)。然后explode 数据框并将(现已分解的)类别列分配给您的第二个数据框。

      criteria_df['count'] = criteria_df['Start'].combine(criteria_df['End'], lambda x,y: list(range(x,y + 1)))
      criteria_df = criteria_df.explode('count')
      second_df['New Column'] = criteria_df['Category']
      

      或者如果你不喜欢 lambda:

      def generate_list(start_index, end_index):
          return list(range(start_index, end_index + 1))
      
      criteria_df['count'] = criteria_df['Start'].combine(criteria_df['End'], generate_list)
      criteria_df = criteria_df.explode('count')
      second_df['New Column'] = criteria_df['Category']
      

      此方法假定您的范围已排序并且范围之间没有间隙。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-19
        • 1970-01-01
        • 2020-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多