【问题标题】:How to fill null values in a column in a csv file?如何在 csv 文件的列中填充空值?
【发布时间】:2020-07-30 09:26:39
【问题描述】:

我需要读取一个 csv 文件并根据此人的地址填写“电话和电子邮件”列中的空/空值,然后写入一个新的 csv 文件。例如:如果“Jonas Kahnwald”没有电话号码电子邮件地址,但与上面或下面的人的地址相同,请说“Hannah Kahnwald ",那么我们应该用这些人的详细信息填充空/空值。

我将无法使用 python pandas,因为其余的代码/程序完全基于 python 2.7(不幸的是),所以我只需要编写一个函数或逻辑来单独捕获这些信息。

输入格式/表格如下所示,带有空单元格(csv 文件):

FirstName,LastName,Phone,Email,Address
Hannah,Kahnwald,1457871452,hannkahn@gmail.com,145han street
Micheal,Kahnwald,6231897383,,145han street
Jonas,Kahnwald,,,145han street
Mikkel,Nielsen,4509213887,mikneil@yahoo.com,887neil ave
Magnus,Nielsen,,magnusneil@kyle.co,887neil ave
Ulrich,Nielsen,,,887neil ave
katharina,Nielsen,,,887neil ave
Elisabeth,Doppler,5439001211,elsisop@amaz.com,211elis park
Peter,Doppler,,,211elis park
bartosz,Tiedmannn,6263172828,tiedman@skype.com,828alex street
Alexander,washington,,,321notsame street
claudia,Tiedamann,,,828alex street

输出格式如下:

Hannah,Kahnwald,1457871452,hannkahn@gmail.com,145han street
Micheal,Kahnwald,6231897383,hannkahn@gmail.com,145han street
Jonas,Kahnwald,1457871452,hannkahn@gmail.com,145han street
Mikkel,Nielsen,4509213887,mikneil@yahoo.com,887neil ave
Magnus,Nielsen,4509213887,magnusneil@kyle.co,887neil ave
Ulrich,Nielsen,4509213887,mikneil@yahoo.com,887neil ave
katharina,Nielsen,4509213887,mikneil@yahoo.com,887neil ave
Elisabeth,Doppler,5439001211,elsisop@amaz.com,211elis park
Peter,Doppler,5439001212,elsisop@amaz.com,211elis park
bartosz,Tiedmannn,6263172828,tiedman@skype.com,828alex street
Alexander,washington,,,321notsame street
claudia,Tiedamann,6263172828,tiedman@skype.com,828alex street
import csv,os

def get_info(file path):
    data = []
    with open(file, 'rb') as fin:
        csv_reader =  csv.reader(fin)
        next(reader)
        for each in csv_reader:

            FirstName = each[0]
            LN = each[1]
            Phone =  "some function or logic"
            email = " some function or logic"
            Address = each[4]
            login = ""
            logout = ""

            data.append([FirstName,LN,Phone,email,Address,login,logout])

   f.close()
   return data

【问题讨论】:

  • 您并没有真正展示 csv 文件的实际内容,但您的问题似乎与 csv reader behavior with None and empty string 密切相关。
  • 将“none”替换为空字符串,例如“”或“”(在“和”之间或“和”之间没有任何内容)
  • @martineau 感谢您的编辑。这是我的第二篇文章,我是 python 和 stackoverflow 的初学者,所以我很难以正确的方式定位。我的 CSV 文件的实际内容(以逗号分隔)看起来完全一样。虽然它包含超过 5 列,但上述列是我需要通过用我在正文中提到的逻辑填充 none/null/empty 值来提取的列。我在读取或写入 csv 文件时没有问题。我不能使用 pandas(ffill,bfill) 或 excel。我希望我清楚并回答了您的问题。
  • Roy:不客气——编辑没什么大不了的。请注意,在您的问题中包含样本数据的另一个原因是,如果其他人想要测试他们对您问题的回答,他们不必自己创建自己的样本。由于 csv 文件是文本,所以它应该只是一个剪切和粘贴操作。
  • @martineau 哦,我现在明白了,你的意思是我可以附加我实际工作的 CSV 文件吗?我不知道那个选项是否存在。如果它在那里,我肯定会附上它。

标签: python python-2.7 csv parsing


【解决方案1】:

这是一个显着更新的版本,它尝试从文件中的其他条目中填充缺失的数据,但前提是它们具有相同的 Address 字段。为了使搜索更快,它构建了一个名为attr_dict 的内部使用字典,其中包含具有特定地址的所有记录。它还在内部使用namedtuples 以​​使代码更具可读性。

请注意,在检索丢失的信息时,它将使用 first 条目中的数据,该条目存储在此内部字典中,地址为 Address。另外,我认为您提供的样本数据并不包含所有可能的情况,因此需要进行额外的测试。

import csv
from collections import namedtuple


def get_info(file_path):

    # Read data from file and convert to list of namedtuples, also create address
    # dictionary to use to fill in missing information from others at same address.
    with open(file_path, 'rb') as fin:
        csv_reader =  csv.reader(fin, skipinitialspace=True)

        header = next(csv_reader)
        Record = namedtuple('Record', header)

        newheader = header + ['Login', 'Logout'] # Add names of new columns.
        NewRecord = namedtuple('NewRecord', newheader)

        addr_dict = {}
        data = [newheader]

        for rec in (Record._make(row) for row in csv_reader):
            if rec.Email or rec.Phone:  # Worth saving?
                addr_dict.setdefault(rec.Address, []).append(rec)  # Remember it.

            login, logout = "",  ""  # Values for new columns.
            data.append(NewRecord._make(rec + (login, logout)))

    # Try to fill in missing data from any other records with same Address.
    for i, row in enumerate(data[1:], 1):
        if not (row.Phone and row.Email):  # Info missing?
            # Try to copy it from others at same address.
            updated = False
            for other in addr_dict.get(row.Address, []):
                if not row.Phone and other.Phone:
                    row = row._replace(Phone=other.Phone)
                    updated = True
                if not row.Email and other.Email:
                    row = row._replace(Email=other.Email)
                    updated = True
                if row.Phone and row.Email:  # Info now filled in?
                    break

            if updated:
                data[i] = row

    return data


INPUT_FILE = 'null_cols.csv'
OUTPUT_FILE = 'fill_cols.csv'

data = get_info(INPUT_FILE)

with open(OUTPUT_FILE, 'wb') as fout:
    writer = csv.DictWriter(fout, data[0])  # First elem has column names.
    writer.writeheader()
    for row in data[1:]:
        writer.writerow(row._asdict())

print('Done')

Excel 中的结果屏幕截图:

【讨论】:

  • 很抱歉,我仍然无法弄清楚如何添加示例输入数据,我也找不到附加 csv 文件的选项。非常感谢您的回答,肯定有帮助。我想我主要不是很清楚,反正我们不会填写 Alexander Washington 的电话和电子邮件吗?因为他的地址与其中任何一个都不匹配。我应该填写此人的 null/空电话/电子邮件值,前提是它与任何其他人的地址匹配。
  • “与上面或下面的人相同的地址”是指文件中所有内容的上方或下方吗?它可能需要将整个文件读入内存来处理它。
  • 这是两种情况,1)与行上或行下的人相同的地址 2)或整个文件中的匹配地址。我有属于这两个类别的 csv 文件,但如果可能的话,我需要基于第二种情况的脚本,因为它涵盖了所有内容。 (我更改了输入和输出文件格式,有帮助吗?)
  • 您所做的编辑实际上在某种程度上受到了伤害,因为您用输入和输出的样本替换了问题中的内容,而不仅仅是添加原始样本按我的要求输入。但是,您对这两种情况的解释确实澄清了一些事情。由于无法提前知道正在处理哪些文件,因此需要始终检查整个文件。这并不像我想的那样糟糕,因为您的代码已经做到了。此外,我更新后的代码中的代码更进一步,并构建了一个辅助字典以更快地搜索匹配项。
  • 很抱歉回复晚了,也很抱歉我的编辑没有帮助。我想我需要时间来理解这些事情。您的代码运行良好。这很棒。虽然我还在理解它的过程中。再次感谢你!它帮助我挑战自我并了解更多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-23
  • 2019-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-27
相关资源
最近更新 更多