【问题标题】:csv column values going to new line causing errors loading in pandascsv列值进入新行导致熊猫加载错误
【发布时间】:2020-02-19 00:07:24
【问题描述】:

我有一个 csv 的问题,它在一列中有一个拆分到一个新的行。我可以手动编辑 .csv 来解决这个问题,但有大约 200 个文件。

数据集包含更多列并且可以包含空值,但是最后一列始终有一个值。该问题也每次仅发生在同一列中。所以我想找出最后一个值为 null 的时间,然后尝试用 .shift() 填充这些值,但希望有一种更简单的方法。

在 vscode 中查看

orderid,fruit,count,person  
3523,apple,84,peter  
2522,green  
grape, 99, mary   
1299, watermelon, 93, paul

pandas read_csv

orderid fruit       count   person
3523    apple       84      peter
2522    green       NaN     NaN
grape   99          mary    NaN
1299    watermelon  93      paul

想要的列

orderid fruit       count   person
3523    apple       84      peter
2522    green grape 99      mary
1299    watermelon  93      paul

【问题讨论】:

  • *edit、vscode 和 notepad++ 显示相似的结果。
  • 你是怎么得到这个 CSV 的?如果您使用 python open()write() 创建它,那么您应该使用模块 csv,它应该将 green grape" " 一起写入文件中创建正确的 csv 数据。然后 pandas 会正确读取它。
  • 可悲的是他们下载的那样......我没有创建它们。
  • 我添加了一个部分,以便从所有 csv 文件轻松创建 DataFrame。

标签: python pandas csv text-processing


【解决方案1】:

修复您的文件:

  • 使用m = re.findall('(?<=[a-zA-Z])\s+\\n[a-zA-Z]', text) 查找,green \ngrape 等案例
    • 该模式将找到alpha \nalpha 并忽略alpha \nnumeric
    • m 将是所有匹配项的列表(例如 [' \ng']
    • .replace(' \ng', ' g'),结果为 ,green grape
  • 找到所有带有pathlib 的文件
    • .rglob 查看所有子目录。如果所有文件都在一个目录中,请使用.glob
    • pathlib 将路径视为对象而不是字符串。因此,pathlib 对象有很多方法。
    • .stem 返回文件名
    • .suffix 返回文件扩展名(例如.csv
  • 这不会覆盖您现有的文件。它将创建一个新文件,在名称中添加_fixed
import re
from pathlib import Path

# list of all the files
files = list(Path(r'c:\some_path').rglob('*.csv'))

# iterate through each file
for file in files:

    # create new filename name_fixed
    new_file = file.with_name(f'{file.stem}_fixed{file.suffix}')

    # read all the text in as a string
    text = file.read_text()

    # find and fix the sections that need fixing
    m = re.findall('(?<=[a-zA-Z])\s+\\n[a-zA-Z]', text)
    for match in m:
        text = text.replace(match, f' {match[-1:]}')
    text_list = text.split('\n')
    text_list = [x.strip() for x in text_list]

    # write the new file
    with new_file.open('w', newline='') as f:
        w = csv.writer(f, delimiter=',')
        w.writerows([x.split(',') for x in text_list])

示例:

.csv中包含以下内容:

orderid,fruit,count,person  
3523,apple,84,peter  
2522,green  
grape, 99, mary   
1299, watermelon, 93, paul
3523,apple,84,peter  
2522,green  
banana, 99, mary   
1299, watermelon, 93, paul
3523,apple,84,peter  
2522,green  
apple, 99, mary   
1299, watermelon, 93, paul

新文件:

orderid,fruit,count,person
3523,apple,84,peter
2522,green grape, 99, mary
1299, watermelon, 93, paul
3523,apple,84,peter
2522,green banana, 99, mary
1299, watermelon, 93, paul
3523,apple,84,peter
2522,green apple, 99, mary
1299, watermelon, 93, paul

创建数据框:

import pandas as pd

new_files = list(Path(f'c:\some_path').glob('*_fixed.csv'))
df = pd.concat([pd.read_csv(f) for f in new_files])

【讨论】:

    【解决方案2】:

    解决方案

    这是另一个解决方案:

    A.这里的逻辑是首先找到以 4 位数字开头的行。

    B.一旦确定了行,任何行(除了最上面的行:标题行)

    • 没有以 4 位数字开头和
    • 没有三个分隔','

    将附加到上一行。

    C.最后,任何空白都将在一行的末尾被删除,所有的行都放在一起形成一个字符串,如果用户愿意,可以将其写入 .csv 文件。

    D.我们使用io.StringIO 作为数据框加载这个字符串。

    示例 1

    import pandas as pd
    from io import StringIO
    import re
    
    def get_clean_data(lines):
        target_lines = [re.findall('^\d{4}', line) for line in lines]
        target_lines_dict = dict((i, val[0]) if (len(val)>0) else (i, None) for i,val in enumerate(target_lines))
    
        correct_lines = list()
        line_index = 0
        for i,line in enumerate(lines):
            if i==0:
                correct_lines.append(line.strip())
            if i>0:
                if target_lines_dict[i] is not None:
                    correct_lines.append(line.strip())
                    line_index +=1
                else:
                    correct_lines[line_index] += ' ' + line.strip()                
        correct_lines = [re.sub(',\s*', ', ', line)+'\n' for line in correct_lines]
        ss = ''.join(correct_lines)
        return ss
    
    # Dummy Data
    s = """
    orderid,fruit,count,person  
    3523,apple,84,peter  
    2522,green  
    grape, 99, mary   
    1299, watermelon, 93, paul
    """
    lines = s.strip().split('\n')
    
    # In case of a csv file, use readlines:
    # with open('csv_file.csv', 'r') as f:
    #     lines = f.readlines()
    
    # Get cleaned data
    ss = get_clean_data(lines)
    
    # Make Dataframe
    df = pd.read_csv(StringIO(ss), sep=',')
    print(df)
    

    输出

       orderid         fruit   count  person
    0     3523         apple      84   peter
    1     2522   green grape      99    mary
    2     1299    watermelon      93    paul
    

    示例 2

    现在让我们使用以下虚拟数据。

    s = """
    orderid,fruit,count,person  
    3523,apple,84,peter  
    2522,green  
    grape, 99, mary   
    1299, watermelon, 93, paul
    3523,apple,84,peter  
    2522,green  
    banana, 99, mary   
    1299, watermelon, 93, paul
    3523,apple,84,peter  
    2522,green  
    apple, 99, mary   
    1299, watermelon, 93, paul
    """
    

    输出

       orderid          fruit   count  person
    0     3523          apple      84   peter
    1     2522    green grape      99    mary
    2     1299     watermelon      93    paul
    3     3523          apple      84   peter
    4     2522   green banana      99    mary
    5     1299     watermelon      93    paul
    6     3523          apple      84   peter
    7     2522    green apple      99    mary
    8     1299     watermelon      93    paul
    

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 2023-04-01
      • 2020-09-25
      • 2015-06-10
      • 2021-04-30
      • 2021-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多