pandas 如果for循环中的条件扰乱了panda Dataframe

nbnkbykc  于 2022-11-05  发布在  其他
关注(0)|答案(1)|浏览(166)

bounty将在6天后过期。回答此问题可获得+50的声望奖励。Thavas Antonio希望吸引更多人关注此问题。

我正在尝试根据if条件在for循环中改变 Dataframe 。

import pandas as pd

# read the read.csv file

def write_csv(email, info):
    df1 = pd.read_csv('/Users/thavas/Downloads/write.csv')
    #iterate over df1 and look for email
    for index, row in df1.iterrows():
        print(index)
        if row['Email 1'] == email:
            #change the value of column 8 to "hello"
            df1.loc[index,'Email 2'] = "hello"
        df1.to_csv('/Users/thavas/Downloads/out.csv')

def read_csv():
    #iterate over rows in dataframe
    df = pd.read_csv('/Users/thavas/Downloads/read.csv')
    for index,rows in df.iterrows():
        email = rows['Email']
        #if email available
        if email != 'nan':
            #get column 8,9,10,11 of rows
            info = rows[8:17]
            write_csv(email, info)

        else:
            print("Users", rows['Contact'], "has no email")

read_csv()

然而,我遇到了一个错误,在使用if语句时,没有数据被添加到csv文件中。
通过调试,我意识到通过在if语句中加入print语句,我可以得到很多输出,所以加入if语句不是问题。
此外,在取出所有的if语句后,我看到输出到我的csv文件中。可能出了什么问题?

UPDATE我注意到只有最后一个循环的数据被读取并更新到我的输出文件。

这是什么意思呢?

ajsxfq5m

ajsxfq5m1#

为了便于解释,我简化了问题,在read.csv中只使用了三列(eidnameemail),而write.csv中有(email1email2)。
我们的目标是创建out.csv,它是write.csv的副本,其中email 2字段填充了read.csv中存在的所有电子邮件。
下面的代码符合您的大部分逻辑,我将用它来强调一些问题。

import pandas as pd

# printing just so you can see the structure explained above

rdf = pd.read_csv('./read.csv')
wdf = pd.read_csv('./write.csv')

print("read.csv")
print(rdf)

print("write.csv")
print(wdf)

def write_csv(email):
    df1 = pd.read_csv('./write.csv')
    #iterate over df1 and look for email
    for index, row in df1.iterrows():
        if row['email1'] == email:
            #change the value of column 8 to "hello"
            df1.loc[index,'email2'] = "hello"
        df1.to_csv('./out.csv')           # <---- Reference 2
        #              ^ Reference 3

def read_csv():
    #iterate over rows in dataframe
    df = pd.read_csv('./read.csv')
    for index,rows in df.iterrows():
        email = rows['email']
        #if email available
        if email != 'nan': # <-- Reference 1
            write_csv(email) # <-- Reference 4

read_csv()

和输出

(stackoverflow) /tmp $ python test.py

read.csv
   eid    name                   email
0    1     Tom   tom@stackoverflow.com
1    2   Alice
2    3     Bob   bob@stackoverflow.com
3    4     Tim

write.csv
                  email1           email2
0  tom@stackoverflow.com   email2-unknown
1  bob@stackoverflow.com   email2-unknown

(stackoverflow) /tmp $ cat out.csv
,email1,email2
0,tom@stackoverflow.com, email2-unknown
1,bob@stackoverflow.com, email2-unknown

参考1:
这真的取决于你的csv文件和你希望在那里找到什么。如果空邮件在你的文件中实际上是用“nan”表示的,那么这似乎没问题。但是,在我的例子中,文件实际上没有任何关于丢失邮件的内容('')。所以Pandas把它们写成NaN。但是,你不能直接把它和'nan'进行比较。
可能的解决方案

  1. if str(email) == 'nan'作为字符串(nan)是'nan'
  2. if isinstance(email, float) and np.isnan(email)这里的np.isnan是numpy的一个函数,但它只对浮点数有效。给它一个字符串会导致错误。
    1.在开始时将整列转换为字符串,然后遍历行。pd.read_csv('./read.csv').astype({'email':'str'})。然后,您可以像以前一样比较email == 'nan'
    1.仅迭代非nan值。例如,for index, rows in df[~df.email.isna()].iterrows(),其中df.email.isna()检查某个值是否为NaN,并且~将其取反。因此,您将获得电子邮件不是NaN的所有行。
    这样,就可以保证write_csv会被正确调用。
    参考文献2:
    每次迭代都写out.csv的代价很高。如果write.csv有1000行,那么你将写out.csv 1000次。相反,你只需要在for循环之外写一次out.csv
    参考文献3和4:
    当你从read.csv中找到一个非空的email时,write_csv被调用来处理一个特定的email。例如,让我们取第一行,tom@stackoverflow.com。所以现在write_csv读取write.csv,修改email为tom...的所有示例,然后将其写入out.csv
    除了当它移动到下一个非空电子邮件bob...时,您再次从write.csv读取,它覆盖了out.csvwrite.csv没有您对tom所做的更改。这解释了为什么您只会看到最后一封电子邮件。
    可能的解决方案:
    1.一个快速的解决方法是首先将write.csv复制到out.csv(在调用read_csv之前),然后修改write_csv,使其始终读取out.csv并写入out.csv
    总结一下:
import pandas as pd
import numpy as np

rdf = pd.read_csv('./read.csv')
wdf = pd.read_csv('./write.csv')

print("read.csv")
print(rdf)

print("write.csv")
print(wdf)

def write_csv(email):
    df1 = pd.read_csv('./out.csv') # read from out
    #iterate over df1 and look for email
    for index, row in df1.iterrows():
        if row['email1'] == email:
            #change the value of column 8 to "hello"
            df1.loc[index,'email2'] = "hello"

    # outside for loop
    # write to out, so next call with different email also persists
    df1.to_csv('./out.csv') 

def read_csv():
    #iterate over rows in dataframe
    df = pd.read_csv('./read.csv')
    # iterate over rows with non-nan emails
    for index,rows in df[~df.email.isna()].iterrows():
        # I've removed the info part with other columns but you get the idea...
        email = rows['email']
        write_csv(email)

import shutil
shutil.copyfile('./write.csv', './out.csv') # first copy to out
read_csv()

上面的代码将为您提供一个有效的解决方案,但仍然效率低下,因为您要为每一封存在的电子邮件编写out.csv
相反,考虑通过合并/连接read.csvwrite.csv的 Dataframe 来创建out.csv。这里有一些mergejoin文档的链接。也许还可以看看panda连接和合并的堆栈溢出问题的一些示例。

相关问题