如何以右侧第2个下划线为分隔符拆分Pandas DataFrame列?
问题描述
假设手里有这样的DataFrame df:
id value_type_and_model_name 0 1 actual_value 1 2 fitted_value_RUT_ARIMA 2 3 fitted_lower_value_RUT_ARIMA 3 4 fitted_upper_value_RUT_ARIMA 4 5 predicted_value_RUT_ARIMA 5 6 predicted_lower_value_RUT_ARIMA 6 7 predicted_upper_value_RUT_ARIMA 7 8 fitted_value_RUT_ES 8 9 fitted_lower_value_RUT_ES 9 10 fitted_upper_value_RUT_ES 10 11 predicted_value_RUT_ES 11 12 predicted_lower_value_RUT_ES 12 13 predicted_upper_value_RUT_ES 13 14 fitted_value_RUT_SARIMAX 14 15 fitted_lower_value_RUT_SARIMAX 15 16 fitted_upper_value_RUT_SARIMAX 16 17 predicted_value_RUT_SARIMAX 17 18 predicted_lower_value_RUT_SARIMAX 18 19 predicted_upper_value_RUT_SARIMAX
现在要把value_type_and_model_name列里的内容(除了actual_value那行),以右侧第2个下划线为分隔线,拆成value_type和model_name两列,最终要得到这样的结果:
id value_type model_name 0 1 actual_value NaN 1 2 fitted_value RUT_ARIMA 2 3 fitted_lower_value RUT_ARIMA 3 4 fitted_upper_value RUT_ARIMA 4 5 predicted_value RUT_ARIMA 5 6 predicted_lower_value RUT_ARIMA 6 7 predicted_upper_value RUT_ARIMA 7 8 fitted_value RUT_ES 8 9 fitted_lower_value RUT_ES 9 10 fitted_upper_value RUT_ES 10 11 predicted_value RUT_ES 11 12 predicted_lower_value RUT_ES 12 13 predicted_upper_value RUT_ES 13 14 fitted_value RUT_SARIMAX 14 15 fitted_lower_value RUT_SARIMAX 15 16 fitted_upper_value RUT_SARIMAX 16 17 predicted_value RUT_SARIMAX 17 18 predicted_lower_value RUT_SARIMAX 18 19 predicted_upper_value RUT_SARIMAX
试了df['value_type_and_model_name'].str.rsplit('_', n=2, expand=True)没成功,该怎么实现?
解决方案
方法1:基于你原来的rsplit修改
你之前的代码用rsplit('_', n=2)会把字符串从右侧拆2次,比如fitted_value_RUT_ARIMA会被拆成fitted_value、RUT、ARIMA三列。我们只需要把后两列用下划线拼起来,就能得到目标的model_name:
# 先拆分得到三列临时数据 temp_cols = df['value_type_and_model_name'].str.rsplit('_', n=2, expand=True) # 给value_type列赋值:如果是actual_value就保留原内容,否则取拆分后的第一列 df['value_type'] = df['value_type_and_model_name'].where(df['value_type_and_model_name'] == 'actual_value', temp_cols[0]) # 给model_name列赋值:如果是actual_value就设为NaN,否则把拆分后的后两列拼起来 df['model_name'] = temp_cols.apply(lambda row: '_'.join(row[1:]) if row[0] != 'actual_value' else None, axis=1) # 不需要原列的话可以删掉 df.drop('value_type_and_model_name', axis=1, inplace=True)
方法2:用正则表达式(更简洁)
直接写正则匹配规则,一次性把需要的两部分抓出来:
# 正则规则:要么匹配actual_value,要么匹配到倒数第二个下划线前的内容(value_type),以及后面的部分(model_name) pattern = r'^(actual_value)|(.*?)_([^_]+_[^_]+)$' # 提取匹配结果 match_result = df['value_type_and_model_name'].str.extract(pattern) # 赋值列:actual_value的行用第一组结果,其他用第二组;model_name取第三组 df['value_type'] = match_result[0].fillna(match_result[1]) df['model_name'] = match_result[2] # 可选删除原列 df.drop('value_type_and_model_name', axis=1, inplace=True)
方法3:两次rsplit拆分
先从右侧拆1次,把最后一个下划线后面的内容拆出来,再对剩下的部分从右侧拆1次,就能得到分隔点:
# 第一次拆分:把最后一个下划线后面的内容(比如ARIMA)和前面的部分分开 first_split = df['value_type_and_model_name'].str.rsplit('_', n=1, expand=True) # 对非actual_value的行,把前面的部分再从右侧拆1次,得到真正的value_type和中间的部分(比如RUT) second_split = first_split[0].str.rsplit('_', n=1, expand=True) # 赋值value_type列 df['value_type'] = df['value_type_and_model_name'].where(df['value_type_and_model_name'] == 'actual_value', second_split[0]) # 赋值model_name列:把中间部分和第一次拆分的后半部分拼起来 df['model_name'] = first_split.apply(lambda row: f"{second_split.loc[row.name, 1]}_{row[1]}" if row[0] != 'actual_value' else None, axis=1) # 可选删除原列 df.drop('value_type_and_model_name', axis=1, inplace=True)
内容的提问来源于stack exchange,提问作者ah bon
相关产品推荐
相关产品推荐

