【问题标题】:cleaning big data using python使用python清理大数据
【发布时间】:2018-10-15 11:34:47
【问题描述】:

我必须在 python 中清理输入数据文件。由于拼写错误,数据字段可能包含字符串而不是数字。我想识别所有作为字符串的字段,并使用熊猫用 NaN 填充这些字段。另外,我想记录这些字段的索引。

最粗略的方法之一是遍历每个字段并检查它是否为数字,但是如果数据很大,这会消耗大量时间。

我的 csv 文件包含类似于下表的数据:

Country  Count  Sales
USA         1   65000
UK          3    4000
IND         8       g
SPA         3    9000
NTH         5   80000

.... 假设我的数据中有 60,000 行这样的行。

理想情况下,我想确定行 IND 在 SALES 列下的值无效。有关如何有效地做到这一点的任何建议?

【问题讨论】:

  • 对带有60000 行的文件进行循环真的不会花费很长时间。在我看来,使用这种方法所花费的时间几乎不会被注意到。您能否展示您的尝试以及证明它确实对您的计算机造成很大负载的基准测试?
  • 如果需要更长的时间,请使用多处理模块,但实际上不应该超过几秒钟,当然取决于您需要编辑的行数。

标签: python pandas


【解决方案1】:

read_csv 有一个 na_values 参数:

na_values:类列表或字典,默认None
要识别为 NA/NaN 的附加字符串。如果 dict 通过,特定的每列 NA 值

df = pd.read_csv('city.csv', sep='\s+', na_values=['g'])

In [2]: df
Out[2]:
  Country  Count  Sales
0     USA      1  65000
1      UK      3   4000
2     IND      8    NaN
3     SPA      3   9000
4     NTH      5  80000

使用pandas.isnull,您可以只选择'Sales' 列或'Country' 系列中具有NaN 的行:

In [3]: df[pd.isnull(df['Sales'])]
Out[3]: 
  Country  Count  Sales
2     IND      8    NaN

In [4]: df[pd.isnull(df['Sales'])]['Country']
Out[4]: 
2    IND
Name: Country

如果它已经在 DataFrame 中,您可以使用 apply 将这些数字字符串转换为整数(使用 str.isdigit):

df = pd.DataFrame({'Count': {0: 1, 1: 3, 2: 8, 3: 3, 4: 5}, 'Country': {0: 'USA', 1: 'UK', 2: 'IND', 3: 'SPA', 4: 'NTH'}, 'Sales': {0: '65000', 1: '4000', 2: 'g', 3: '9000', 4: '80000'}})

In [12]: df
Out[12]: 
  Country  Count  Sales
0     USA      1  65000
1      UK      3   4000
2     IND      8      g
3     SPA      3   9000
4     NTH      5  80000

In [13]: df['Sales'] = df['Sales'].apply(lambda x: int(x) 
                                                  if str.isdigit(x)
                                                  else np.nan)

In [14]: df
Out[14]: 
  Country  Count  Sales
0     USA      1  65000
1      UK      3   4000
2     IND      8    NaN
3     SPA      3   9000
4     NTH      5  80000

【讨论】:

  • 不错。你为什么注释掉 read_csv 代码?它似乎有效。
  • @Monir 未评论,并评论了 to_dict()。虽然,apply 是我答案的重要部分(奇怪的是,似乎没有其他答案使用它)。
【解决方案2】:
import os
import numpy as np
import pandas as PD

filename = os.path.expanduser('~/tmp/data.csv')
df = PD.DataFrame(
        np.genfromtxt(
            filename, delimiter = '\t', names = True, dtype = '|O4,<i4,<f8'))
print(df)

产量

  Country  Count  Sales
0     USA      1  65000
1      UK      3   4000
2     IND      8    NaN
3     SPA      3   9000
4     NTH      5  80000

要找到销售额为NaN 的国家/地区,您可以计算

print(y['Country'][np.isnan(y['Sales'])])

产生pandas.Series:

2    IND
Name: Country

【讨论】:

  • 我认为在较大的数据帧上预测 dtype 可能是不可能的/不合理的,特别是如果列数比这个玩具示例中的多...
【解决方案3】:

尝试将 'sales' 字符串转换为 int,如果格式正确,则继续,如果不是,它将引发 ValueError,我们将其捕获并替换为占位符。

bad_lines = []

with open(fname,'rb') as f:
    header = f.readline()
    for j,l in enumerate(f):
        country,count,sales = l.split()
        try:
            sales_count = int(sales)
        except ValueError:
            sales_count = 'NaN'
            bad_lines.append(j)
        # shove in to your data structure
        print country,count,sales_count

您可能需要编辑分割该行的行(因为您的示例复制为空格,而不是制表符)。用您想要对数据执行的操作替换打印行。您可能还需要用 pandas NaN 替换“NaN”。

【讨论】:

  • int(sales) 应该提供与int(sales.strip()) 相同的内容(int 不关心空格)
  • 另外,你也可以country,count,sales = l.split() 或者country,count,sales = l.split(None,2)
  • @mgilson 太棒了,python 比我想象的更聪明(再次)
【解决方案4】:
filename = open('file.csv')
filename.readline()

for line in filename:
    currentline = line.split(',')
    try:
        int(currentline[2][:-1])
    except:
        print currentline[0], currentline[2][:-1]

IND g

【讨论】:

    【解决方案5】:

    我建议使用正则表达式:

    import re
    
    ss = '''Country  Count  Sales
    USA   ,      3  , 65000
    UK    ,      3  ,  4000
    IND   ,      8  ,     g
    SPA   ,     ju  ,  9000
    NTH   ,      5  , 80000
    XSZ   ,    rob  ,    k3'''
    
    with open('fofo.txt','w') as f:
        f.write(ss)
    
    print ss
    print
    
    delimiter = ','
    
    regx = re.compile('(.+?(?:{0}))'
                      '(( *\d+?)| *.+?)'
                      '( *(?:{0}))'
                      '(( *\d+?)| *.+?)'
                      '( *\r?\n?)$'.format(delimiter))
    
    def READ(filepath, regx = regx):
        with open(filepath,'rb+') as f:
            yield f.readline()
            for line in f:
                if None in regx.match(line).group(3,6):
                    g2,g3,g5,g6 = regx.match(line).group(2,3,5,6)
                    tr = ('%%%ds' % len(g2) % 'NaN' if g3 is None else g3,
                          '%%%ds' % len(g5) % 'NaN' if g6 is None else g6)
                    modified_line = regx.sub(('\g<1>%s\g<4>%s\g<7>' % tr),line)
                    print ('------------------------------------------------\n'
                           '%r with aberration\n'
                           '%r modified line'
                           % (line,modified_line))
                    yield modified_line
                else:
                    yield line
    
    with open('modified.txt','wb') as g:
        g.writelines(x for x in READ('fofo.txt'))
    

    结果

    Country  Count  Sales
    USA   ,      3  , 65000
    UK    ,      3  ,  4000
    IND   ,      8  ,     g
    SPA   ,     ju  ,  9000
    NTH   ,      5  , 80000
    XSZ   ,    rob  ,    k3
    
    ------------------------------------------------
    'IND   ,      8  ,     g\r\n' with aberration
    'IND   ,      8  ,   NaN\r\n' modified line
    ------------------------------------------------
    'SPA   ,     ju  ,  9000\r\n' with aberration
    'SPA   ,    NaN  ,  9000\r\n' modified line
    ------------------------------------------------
    'XSZ   ,    rob  ,    k3' with aberration
    'XSZ   ,    NaN  ,   NaN' modified line
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-03
      • 2020-07-10
      • 1970-01-01
      • 2012-08-23
      • 2018-10-28
      • 2020-03-13
      • 2021-09-04
      • 2018-03-26
      相关资源
      最近更新 更多