在 Python 中创建一个函数,用于根据多个条件从 pandas 数据帧值创建存储桶

Creating a function in Python for creating buckets from pandas dataframe values based on multiple conditions

我问了,它帮助了我,但现在我的任务更复杂了。

我的数据框有大约 100 列和 14 个尺度的值。

{'Diseasetype': {0: 'Oncology',
 1: 'Oncology',
 2: 'Oncology',
 3: 'Nononcology',
 4: 'Nononcology',
 5: 'Nononcology'},
'Procedures1': {0: 100, 1: 300, 2: 500, 3: 200, 4: 400, 5: 1000},
'Procedures2': {0: 1, 1: 3, 2: 5, 3: 2, 4: 4, 5: 10},
'Procedures100': {0: 1000, 1: 3000, 2: 5000, 3: 2000, 4: 4000, 5: 10000}}

我想将数据帧每一列中的每个值转换为一个桶值。

我目前的解决方案是:

def encoding(col, labels):
    return np.select([col<200, col.between(200,500), col.between(500,1000), col>1000], labels, 0)

onc_labels = [1,2,3,4]
nonc_labels = [11,22,33,44]
msk = df['Therapy_area'] == 'Oncology'

df[cols] = pd.concat((df.loc[msk, cols].apply(encoding, args=(onc_labels,)), df.loc[msk, cols].apply(encoding, args=(nonc_labels,)))).reset_index(drop=True)

它工作得很好,如果数据框的所有列都具有相同的比例,但它们不是。请记住,我有 14 个不同的比例。

我想更新上面的代码(或获得另一个解决方案),这将允许我存储数据。 我不能使用相同范围的值来分桶所有内容。

我的逻辑如下:

如果 Disease == OncologyProcedures1 在此范围内,将值转换为这些桶 (1, 2, 3)

如果 Disease == OncologyProcedures2 在此范围内,将值转换为这些桶 (1, 2, 3)

如果 Disease != OncologyProcedures77 在此范围内,将值转换为这些桶 (4, 5, 6)

秤和水桶示例:

肿瘤学程序 1:< 200 = 1、200-400 = 2、>400 = 3

肿瘤学程序 2:< 2 = 1、2-4 = 2、>4 = 3

肿瘤学程序3:< 2000 = 1,2000-4000 = 2,>4000 = 3

非肿瘤学程序 1:< 200 = 4、200-400 = 5、>400 = 6

非肿瘤学程序 2:< 2 = 4、2-4 = 5、>4 = 6

非肿瘤学程序3:< 2000 = 4、2000-4000 = 5、>4000 = 6

预期输出(很高兴提供更多信息!)

Diseasetype Procedures1 Procedures2 Procedures100
Oncology        1             1           1
Oncology        2             2           2
Oncology        3             3           3
Nononcology     4             4           4
Nononcology     5             5           5
Nononcology     6             6           6

Link with rules:

我使用了一个具有所有比例的帮助文件(来源在答案末尾):

使用 melt 展平您的数据框,然后使用 query 过滤掉您的行,​​最后使用 pivot 重塑您的数据框。您可以独立执行每一行以显示转换:

scales = pd.read_csv('scales.csv').fillna({'Start': -np.inf, 'End': np.inf})
out = (
  df.melt('Diseasetype', var_name='Procedure', ignore_index=False).reset_index()
    .merge(scales, on=['Diseasetype', 'Procedure'], how='left')
    .query("value.between(Start, End)")
    .pivot_table('Label', ['index', 'Diseasetype'], 'Procedure').astype(int)
    .droplevel(0).rename_axis(columns=None).reset_index()
)

输出:

>>> df
   Diseasetype  Procedures1  Procedures100  Procedures2
0     Oncology            1              1            1
1     Oncology            2              2            2
2     Oncology            3              3            3
3  Nononcology            4              4            4
4  Nononcology            5              5            5
5  Nononcology            6              6            6

scales.csv的内容:

Diseasetype,Procedure,Start,End,Label
Oncology,Procedures1,,200,1
Oncology,Procedures1,200,400,2
Oncology,Procedures1,400,,3
Oncology,Procedures2,,2,1
Oncology,Procedures2,2,4,2
Oncology,Procedures2,4,,3
Oncology,Procedures100,,2000,1
Oncology,Procedures100,2000,4000,2
Oncology,Procedures100,4000,,3
Nononcology,Procedures1,,200,4
Nononcology,Procedures1,200,400,5
Nononcology,Procedures1,400,,6
Nononcology,Procedures2,,2,4
Nononcology,Procedures2,2,4,5
Nononcology,Procedures2,4,,6
Nononcology,Procedures100,,2000,4
Nononcology,Procedures100,2000,4000,5
Nononcology,Procedures100,4000,,6