【问题标题】:python dataframe income column cleanuppython数据框收入列清理
【发布时间】:2021-03-05 18:59:36
【问题描述】:

这可能是一个简单的解决方案,但我发现很难让这个函数适用于我的数据集。

我有一个工资列,其中包含各种数据。下面的示例数据框:

ID   Income                              desired Output         
1    26000                               26000
2    45K                                 45000
3    -                                   NaN
4    0                                   NaN
5    N/A                                 NaN
6    2000                                2000   
7    30000 - 45000                       37500 (30000+45000/2)   
8    21000 per Annum                     21000                
9    50000 per annum                     50000
10   21000 to 30000                      25500 (21000+30000/2)
11                                       NaN
12   21000 To 50000                      35500 (21000+50000/2)
13   43000/year                          43000
14                                       NaN
15   80000/Year                          80000
16   12.40 p/h                           12896 (12.40 x 20 x 52)
17   12.40 per hour                      12896 (12.40 x 20 x 52)
18   45000.0 (this is a float value)     45000       

@user34974 - 在提供可行的解决方案方面非常有帮助(如下)。但是,该解决方案向我提供了一个错误,因为数据框列也包含浮点值。任何人都可以帮助满足数据框列中可以处理的函数中的浮点值吗?最后更新列中的输出应该是浮点值。

Normrep = ['N/A','per Annum','per annum','/year','/Year','p/h','per hour',35000.0]

def clean_income(value):
    for i in Normrep:
        value = value.replace(i,"")



    if len(value) == 0 or value.isspace() or value == '-': #- cannot be clubbed to array as used else where in data
        return np.nan
    elif value == '0':
        return np.nan

    # now there should not be any extra letters with K hence can be done below step
    if value.endswith('K'):
        value = value.replace('K','000')
    
    # for to and -
    vals = value.split(' to ')
    if len(vals) != 2:
        vals = value.split(' To ')
        if len(vals) != 2:
            vals = value.split(' - ')

    if len(vals) == 2:
        return (float(vals[0]) + float(vals[1]))/2

    try:
        a = float(value)
        return a
    except:
        return np.nan    # Either not proper data or need to still handle some fromat of inputs.


testData = ['26000','45K','-','0','N/A','2000','30000 - 45000','21000 per Annum','','21000 to 30000','21000 To 50000','43000/year', 35000.0]


df = pd.DataFrame(testData)
print(df)

df[0] = df[0].apply(lambda x: clean_income(x))

print(df)

【问题讨论】:

  • 你能发布你想要的输出吗?我认为在某些情况下它会导致 NaN。例如,您是否期望 30000 - 45000 得到两者的平均值?同样对于 21000 to 30000 的值,您是否期望两者的平均值?
  • 好。您能否在您的问题部分发布所需的结果,以便我们查看您要查找的内容。解决方案可能比您拥有的大代码要简单得多。
  • 基本上,我的目标是转换:1) 40K - 40000 2) 0 - NaN 3) 空白 - NaN 4) 21000 到 22000 - 22000 + 21000/2 5) 80000/年 - 80000 6 ) N/A - NaN 7) 10000 每年 - 10000 8) N/A - NaN 9) 90000/年 - 90000 10) 10000 每年 - 10000 11) 30000 - 45000 - 30000+45000/2 12) - - NaN 13) 45000.0 (float) - 45000.0 14) 12.40 p/h - 12.40 * 20 *52 - 12896 15) 12.40 per hour - 12.40 * 20 *52 - 12896 最后,整列应转换为浮点值。
  • 你能把这个贴在主要问题部分吗? cmets 部分中的文本没有适当的缩进。我需要查看普通数据框格式的数据。
  • 谢谢乔。刚刚更新了问题部分。

标签: python pandas data-cleaning


【解决方案1】:

这就是我将如何在没有所有循环的情况下做到这一点。

c = ['ID','Income']
d = [
[1, 26000],  
[2, '45K'],
[3, '-'],
[4, 0],  
[5, 'N/A'],     
[6, 2000],         
[7, '30000 - 45000'],
[8, '21000 per Annum'],
[9, '50000 per annum'],
[10, '21000 to 30000'],
[11, ''],
[12, '21000 To 50000'],
[13, '43000/year'],
[14, ''],
[15, '80000/Year'],
[16, '12.40 p/h'],
[17, '12.40 per hour'],
[18, 45000.00]]

import pandas as pd
import numpy as np
df = pd.DataFrame(d,columns=c)

df['Income1'] = df['Income'].astype(str).str.lower()

df['Income1'].replace({'n/a' : '0', '':'0', '-':'0', 0:'0'}, regex=False, inplace=True)

df['Income1'].replace({'k$': '000','to': '+', '-': '+', ' per annum': '', 'p/h' : 'per hour', '/year': ''}, regex=True, inplace=True)

df['Income1'].replace(' per hour', ' * 12 * 52', regex=True, inplace=True)

df.loc[df.astype(str).Income1.str.contains('\+'),'Income1'] = '(' + df['Income1'].astype(str) + ') / 2'

df['Income1'] = df['Income1'].apply(lambda x: eval(x) if (pd.notnull(x)) else x)

df['Income1'] = (df['Income1'].fillna(0)
                 .astype(int)
                 .astype(object)
                 .where(df['Income1'].notnull()))

print (df)

这个输出将是:

    ID           Income Income1
0    1            26000   26000
1    2              45K   45000
2    3                -     NaN
3    4                0     NaN
4    5              N/A     NaN
5    6             2000    2000
6    7    30000 - 45000   37500
7    8  21000 per Annum   21000
8    9  50000 per annum   50000
9   10   21000 to 30000   25500
10  11                      NaN
11  12   21000 To 50000   35500
12  13       43000/year   43000
13  14                      NaN
14  15       80000/Year   80000
15  16        12.40 p/h    7737
16  17   12.40 per hour    7737
17  18            45000   45000

【讨论】:

    【解决方案2】:

    我想重申一下,如果这只是数据的可能组合,那么我已经完成并提供了以下代码。

    即使有任何小的变化,您也需要进行编辑以适应新的变化。让我解释一下我做了什么,对于你想用“”替换的所有字符串,我创建了一个数组 Normrep。因此,如果您要删除更多字符串,则可以添加元素。此外,对于“K”、“p/h”、“每小时”,它们需要专门处理并且需要进行转换。所以,如果你的数据中的字符串可能会改变,那么你需要在这里处理。

    import pandas as pd
    import numpy as np
    
    Normrep = ['N/A', 'per Annum', 'per annum', '/year', '/Year']
    
    
    def clean_income(value):
        if isinstance(value,float):
            return value
        else:
            isHourConversionNeeded = False;
            
            for i in Normrep:
                value = value.replace(i, "")
    
            if len(value) == 0 or value.isspace() or value == '-':  # - cannot be clubbed to array as used else where in data
                return np.nan
            elif value == '0':
                return np.nan
    
            # now there should not be any extra letters with K hence can be done below step
            if value.endswith('K'):
                value = value.replace('K', '000')
            elif value.endswith('p/h') or value.endswith('per hour'):
                isHourConversionNeeded = True
                value = value.replace('p/h',"")
                value = value.replace('per hour',"")
    
            # for to and -
            vals = value.split(' to ')
            if len(vals) != 2:
                vals = value.split(' To ')
                if len(vals) != 2:
                    vals = value.split(' - ')
    
            if len(vals) == 2:
                return (float(vals[0]) + float(vals[1])) / 2
    
            try:
                a = float(value)
                if isHourConversionNeeded:
                    a = a * 20 * 52
                return a
            except:
                return np.nan  # Either not proper data or need to still handle some fromat of inputs.
    
    
    testData = ['26000', '45K', '-', '0', 'N/A', '2000', '30000 - 45000', '21000 per Annum', '', '21000 to 30000',
                '21000 To 50000', '43000/year', 35000.0,'12.40 p/h','12.40 per hour']
    df = pd.DataFrame(testData)
    print(df)
    
    df[0] = df[0].apply(lambda x: clean_income(x))
    
    print(df)
    

    【讨论】:

    • 如果您将value 转换为小写,您可以消除一些选项。此外,您可能需要将浮点数转换为 int,因为 OP 只需要整数。
    • 我最初使用这个解决方案。由于我必须将它应用于包含更多列而不仅仅是收入列的数据框,因此通过一些额外的步骤也可以正常工作。这个和上面的解决方案都非常有帮助!谢谢。
    • 这里不需要循环,这在中等大小的 df 上会很快爆炸。尝试使用 pandas 提供的.str 方法。
    猜你喜欢
    • 2012-08-23
    • 2021-09-04
    • 2018-03-20
    • 2022-10-13
    • 2020-01-04
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多