簡體   English   中英

將2 .CSV與未知數量的列和名稱進行比較

[英]Compare 2 .CSV with unknown number of columns and names

並提前感謝任何建議。 這是第一次發布的海報,所以我會盡力提供所有必需的信息。 我也是Python的初學者,一直在做一些在線教程,以及StackOverflow的一些復制/粘貼編碼,它是FrankenCoding ......所以我可能接近這個錯誤...

我需要比較兩個CSV文件,這些文件的列數會有變化,只有2列匹配(例如,一個文件中的email_address,另一個文件中的EMAIL)。 這兩個文件都有標題,但這些標題的名稱可能會更改。 文件大小可能從幾千行到+2,000,000,可能有100多列(但更可能有一些)。

輸出到第三個'results.csv'文件,包含所有信息。 它可以是合並(所有唯一條目),減法(刪除一個或另一個中存在的條目)或交叉(兩者中都存在的所有條目)。

我在這里搜索過,發現了很多很好的信息,但是我看到的所有信息在文件中都有固定數量的列。 我嘗試過dict和dictreader,我知道答案就在那里,但是現在,我有點困惑。 但由於我幾天沒有取得任何進展,而且我只能在這方面投入太多時間,所以我希望能夠朝着正確的方向努力。

理想情況下,我想學習如何自己動手,這意味着要了解數據是如何“四處移動”的。

提取下面的CSV文件,我沒有添加更多列然后(我認為)必要,我現在擁有的數據集將匹配Originalid / UID或emailaddress / email,但情況可能並非總是如此。

Original.csv

"originalid","emailaddress",""
"12345678","Bob@mail.com",""
"23456789","NORMA@EMAIL.COM",""
"34567890","HENRY@some-mail.com",""
"45678901","Analisa@sports.com",""
"56789012","greta@mail.org",""
"67890123","STEVEN@EMAIL.ORG",""

Compare.CSV

"email","","DATEOFINVALIDATION_WITH_TIME","OPTOUTDATE_WITH_TIME","EMAIL_USERS"
"Bob@mail.com",,,"true"
"NORMA@EMAIL.COM",,,"true"
"HENRY@some-mail.com",,,"true"
"Henrietta@AWESOME.CA",,,"true"
"NORMAN@sports.CA",,,"true"
"albertina@justemail.CA",,,"true"

results.csv中的數據應該是Original.CSV + Compare.csv中所有列的所有列,但不是匹配的列(電子郵件):

"originalid","emailaddress","","DATEOFINVALIDATION_WITH_TIME","OPTOUTDATE_WITH_TIME","EMAIL_USERS"
"12345678","Bob@mail.com","",,,"true"
"23456789","NORMA@EMAIL.COM","",,,"true"
"34567890","HENRY@some-mail.com","",,,"true"

以下是我現在的結果:

email,,DATEOFINVALIDATION_WITH_TIME,OPTOUTDATE_WITH_TIME,EMAIL_USERS
Bob@mail.com,,,true,"['12345678', 'Bob@mail.com', '']"
NORMA@EMAIL.COM,,,true,"['23456789', 'NORMA@EMAIL.COM', '']"
HENRY@some-mail.com,,,true,"['34567890', 'HENRY@some-mail.com', '']"

這就是我在使用代碼的地方,print語句將文件中的匹配數據返回到屏幕而不是文件,所以我在那里缺少一些東西。
*****我沒有從original.csv文件中獲取標題,數據正在進入。

import csv

def get_column_from_file(filename, column_name):
    f = open(filename, 'r')
    reader = csv.reader(f)
    headers = next(reader, None)
    i = 0
    max = (len(headers))
    while i < max:
        if headers[i] == column_name:
            column_header = i
 #       print(headers[i])
        i = i + 1
    return(column_header)

file_to_check = "Original.csv"
file_console = "Compare.csv"

column_to_read = get_column_from_file(file_console, 'email')
column_to_compare = get_column_from_file(file_to_check, 'emailaddress')

with open(file_console, 'r') as master:
    master_indices = dict((r[1], r) for i, r in enumerate(csv.reader(master)))

with open('Compare.csv', 'r') as hosts:
    with open('results.csv', 'w', newline='') as results:
        reader = csv.reader(hosts)
        writer = csv.writer(results)

        writer.writerow(next(reader, []))

        for row in reader:
            index = master_indices.get(row[0])
            if index is not None:
                print (row +[master_indices.get(row[0])])
                writer.writerow(row +[master_indices.get(row[0])])

謝謝你的時間!

現在看起來你只使用一次編寫器作為標題:

writer.writerow(next(reader, []))

弗朗西斯科指出,取消注釋最后一行可能會解決您的問題。 您可以通過刪除行開頭的“#”來完成此操作。

我喜歡你自己想要這樣做,並認識到需要“理解數據是如何移動的”。 這正是你應該如何思考這個問題:專注於數據的移動而不是結果。 有些人可能不同意我,但我認為這是一個很好的理念,因為它將使未來的重用更容易。

您沒有嘗試構建一個組合了兩個CSV的工具,您嘗試根據公共參考(電子郵件地址)組織數據(恰好來自CSV)並將結果輸出為CSV。 因為您正在討論潛在的大型數據集(+2,000,000 [行],可能有100多列),所以認識到注意漸近運行時非常重要。 如果您不知道這是什么,我建議您閱讀Big-O表示法和漸近算法分析。 沒有這個你可能沒問題。

首先,您要確定每個CSV中的哪個是您的密鑰。 你已經在'Original.csv'中為'Compare.csv'和'emailaddress'做了'email'。 現在,自己構建一個函數,根據密鑰從CSV生成字典。

def get_dict_from_csv(path_to_csv, key):
    with open(path_to_csv, 'r') as f:
        reader = csv.reader(f)
        headers, *rest = reader  # requires python3
    key_index = headers.index(key)  # find index of key
    # dictionary comprehensions are your friend, just think about what you want the dict to look like
    d = {row[key_index]: row[:key_index] + row[key_index+1:]  # +1 to skip the email entry
         for row in rest}
    headers.remove(key)
    d['HEADERS'] = headers  # add headers so you know what the information in the dict is
    return d

現在,您可以在兩個CSV上調用此功能。

file_console_dict = get_dict_from_csv('Compare.csv', 'email')
file_to_check_dict = get_dict_from_csv('Original.csv', 'emailaddress')

現在你有兩個關鍵字相同的信息。 現在我們需要一個函數將它們組合成一個字典。

def combine_dicts(*dicts):
    d, *rest = dicts  # requires python3
    # iteratively pull other dicts into the first one, d
    for r in rest:
        original_headers = d['HEADERS'][:]
        new_headers = r['HEADERS'][:]
        # copy headers
        d['HEADERS'].extend(new_headers)
        # find missing keys
        s = set(d.keys()) - set(r.keys())  # keys present in d but not in r
        for k in s:
            d[k].extend(['', ] * len(new_headers))
        del r['HEADERS']  # we don't want to copy this a second time in the loop below
        for k, v in r.items():
            # use setdefault in case the key didn't exist in the first dict
            d.setdefault(k, ['', ] * len(original_headers)).extend(v)
    return d

現在你有一個dict,它包含你想要的所有信息,你需要做的就是將它寫回CSV。

def write_dict_to_csv(output_file, d, include_key=False):
    with open(output_file, 'w', newline='') as results:
        writer = csv.writer(results)
        # email isn't in your HEADERS, so you'll need to add it
        if include_key:
            headers = ['email',] + d['HEADERS']
        else:
            headers = d['HEADERS']
        writer.writerow(headers)
        # now remove it from the dict so we can iterate over it without including it twice
        del d['HEADERS']
        for k, v in d.items():
            if include_key:
                row = [k,] + v
            else:
                row = v
            writer.writerow(row)

這應該是它。 打電話給所有這些只是

file_console_dict = get_dict_from_csv('Compare.csv', 'email')
file_to_check_dict = get_dict_from_csv('Original.csv', 'emailaddress')
results_dict = combine_dicts(file_to_check_dict, file_console_dict)
write_dict_to_csv('results.csv', results_dict)

你可以很容易地看到它如何擴展到任意多個詞典。

您說您不希望電子郵件出現在最終的CSV中。 這對我來說是違反直覺的,所以我在write_dict_to_csv()中做了一個選項,以防你改變主意。

當我運行以上所有內容時,我得到了

email,originalid,,,DATEOFINVALIDATION_WITH_TIME,OPTOUTDATE_WITH_TIME,EMAIL_USERS
Bob@mail.com,12345678,,,,true
NORMA@EMAIL.COM,23456789,,,,true
HENRY@some-mail.com,34567890,,,,true
Analisa@sports.com,45678901,,,,,
greta@mail.org,56789012,,,,,
STEVEN@EMAIL.ORG,67890123,,,,,
Henrietta@AWESOME.CA,,,,,true
NORMAN@sports.CA,,,,,true
albertina@justemail.CA,,,,,true

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM