如何基于Pandas布尔行生成含规则字符串的新列?
问题描述
我有一个包含多列布尔值/整数(1/0)的Pandas DataFrame,需要生成新结果列,其字符串按规则构建:统计连续True值的组数、是否中断、起止列及True值总数。
示例DataFrame如下:
column_1 column_2 column_3 column_4 column_5 column_6 column_7 column_8 column_9 column_10 0 0 1 0 1 1 1 1 0 0 1 1 0 1 1 0 1 1 1 0 0 1 2 1 1 0 0 0 1 1 0 0 1 3 1 1 1 0 0 0 0 1 1 1 4 1 1 1 0 0 1 0 0 1 1 5 1 1 1 0 0 0 1 1 0 1 6 0 1 1 1 1 1 1 0 1 0
结果字符串分为四个片段,以/分隔:
- 首段:
i表示存在中断(连续True值组之间有0分隔),c表示无中断;数字为连续True值≥2的组数。 - 第二段:各组连续True值的长度,多组用
-分隔。 - 第三段:各组连续True值的起止列编号(列名后缀数字),多组用
_分隔,组内起止用-连接。 - 第四段:该行所有True值(1)的总数。
示例:
- 第1行
[0 1 1 0 1 1 1 0 0 1]的结果字符串为i2/2-3/c2-c3_c5-c7/6 - 第6行
[0 1 1 1 1 1 1 0 1 0]的结果字符串为c1/6/c2-c7/7
初始代码如下:
import pandas as pd import numpy as np def create_custom_result(df: pd.DataFrame) -> pd.Series: return df def create_dataframe() -> pd.DataFrame: df = pd.DataFrame() # empty df for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: # create random bool/int values df[f'column_{i}'] = np.random.randint(2, size=50) df["column_result"] = '' # add result column return df if __name__=="__main__": df = create_dataframe() custom_results = create_custom_result(df=df)
尝试过逐行遍历,但不知如何构建结果字符串;查找的资料多为列的连续值处理,而非行横向处理,希望得到该需求的实现方案。
解决方案
核心思路是对每一行横向遍历,识别连续的1序列,记录每组的长度、起止列号,再按规则拼接结果字符串。以下是实现代码:
import pandas as pd import numpy as np def create_custom_result(df: pd.DataFrame) -> pd.Series: # 提取列名对应的数字编号(column_1对应1) col_numbers = [int(col.split('_')[1]) for col in df.columns] def process_row(row): groups = [] # 存储连续1的组:(起始列号, 结束列号) current_start = None # 遍历行内每个值和对应列号 for val, col_num in zip(row, col_numbers): if val == 1: if current_start is None: current_start = col_num else: if current_start is not None: # 结束一个连续组 groups.append((current_start, col_num - 1)) current_start = None # 处理行末尾未结束的连续组 if current_start is not None: groups.append((current_start, col_numbers[-1])) # 筛选出长度≥2的有效组 valid_groups = [g for g in groups if g[1] - g[0] + 1 >= 2] valid_count = len(valid_groups) # 判断是否中断:有效组数量>1 或 总1数>有效组总长度(存在单独的1) total_ones = row.sum() valid_total = sum(end - start + 1 for start, end in valid_groups) has_interrupt = valid_count > 1 or (total_ones > valid_total) # 构建各片段 segment1 = f'{"i" if has_interrupt else "c"}{valid_count}' segment2 = '-'.join([str(end - start + 1) for start, end in valid_groups]) if valid_groups else '' segment3 = '_'.join([f'c{start}-c{end}' for start, end in valid_groups]) if valid_groups else '' segment4 = str(total_ones) # 拼接结果字符串 return '/'.join([segment1, segment2, segment3, segment4]) # 逐行处理生成结果序列 return df.apply(process_row, axis=1) def create_dataframe() -> pd.DataFrame: df = pd.DataFrame() # empty df for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: # create random bool/int values df[f'column_{i}'] = np.random.randint(2, size=50) df["column_result"] = '' # add result column return df if __name__=="__main__": # 用示例数据测试 sample_data = [ [0,1,0,1,1,1,1,0,0,1], [0,1,1,0,1,1,1,0,0,1], [1,1,0,0,0,1,1,0,0,1], [1,1,1,0,0,0,0,1,1,1], [1,1,1,0,0,1,0,0,1,1], [1,1,1,0,0,0,1,1,0,1], [0,1,1,1,1,1,1,0,1,0] ] df = pd.DataFrame(sample_data, columns=[f'column_{i}' for i in range(1,11)]) df["column_result"] = create_custom_result(df) print(df[["column_result"]])
代码说明
- 列编号提取:从列名中提取数字后缀,方便后续记录连续组的起止列号。
- 行处理逻辑:
- 遍历行内每个值,识别连续的1序列,记录每个组的起止列号。
- 筛选出长度≥2的有效组,统计其数量。
- 通过有效组数量和总1数的关系判断是否存在中断。
- 分别构建四个结果片段,最终用
/拼接成完整字符串。
- 批量处理:用
apply函数将行处理逻辑应用到DataFrame的每一行,生成结果列。
测试示例数据时,会输出符合要求的结果,比如第1行返回i2/2-3/c2-c3_c5-c7/6,第6行返回c1/6/c2-c7/7。
内容的提问来源于stack exchange,提问作者Wicked Gummy Bear
相关产品推荐
相关产品推荐

