如何在为新列指定新值时,基于起始值和结束值列表循环索引

2024-04-25 18:48:35 发布

您现在位置:Python中文网/ 问答频道 /正文

简短版本:我需要在criteria数据框中循环,用一列开始值、结束值和赋值来赋值。第二个数据帧拥有我需要在列中为“赋值”赋值的值

下面是我试图做的一个简化版本。我从两个独立的数据帧开始工作,它们是从导入的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

2条回答

在criteria数据框上,创建一列,其中每个单元格都是一个大小为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']

这种方法假设您的范围已排序,并且范围之间没有间隙

解决问题的一种方法是将新值应用于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

相关问题 更多 >