逐行迭代熊猫,并修改特定的“;“细胞”;以python的方式

逐行迭代熊猫,并修改特定的“;“细胞”;以python的方式,python,pandas,dataframe,Python,Pandas,Dataframe,我是python新手,我有一个pandas数据框架,我想逐行迭代(比如其他语言中的2d数组)。 目标是这样的逻辑:(如果df是一个类似2d的数组) 要点是:我想将当前行的内容移动到第1列中的上一行,若当前行第2列为空,而当前行第1列为空 我将如何以python的方式实现这一点?(例如,不使用for循环进行迭代)。我看到了一些关于矢量化的东西,但我真的不知道它是如何工作的 或者将df转换为列表列表或数组更容易?文件很大,所以我想用一种快速的方法,从excel文件中读取,所以我只是使用pandas的

我是python新手,我有一个pandas数据框架,我想逐行迭代(比如其他语言中的2d数组)。 目标是这样的逻辑:(如果df是一个类似2d的数组)

要点是:我想将当前行的内容移动到第1列中的上一行,若当前行第2列为空,而当前行第1列为空

我将如何以python的方式实现这一点?(例如,不使用for循环进行迭代)。我看到了一些关于矢量化的东西,但我真的不知道它是如何工作的

或者将df转换为列表列表或数组更容易?文件很大,所以我想用一种快速的方法,从excel文件中读取,所以我只是使用pandas的read_excel将其导入df。

试试这个(假设第1列是指索引0处的列,第2列是指索引1处的列):

将熊猫作为pd导入
将numpy作为np导入
col1,col2=df.columns[0],df.columns[1]
掩码=(df.loc[:,col1]!=“”)和(df.loc[:,col2]=“”)
mask.iloc[0]=False#不环绕第一行(即使条件适用)
df.loc[mask.shift(-1,fill_value=False),col1]=df.loc[mask,col1]。值
这里的关键点是使用将布尔掩码向后移动一。这只使用pandas/numpy矢量化函数,因此它比使用普通的Python
for
循环进行迭代要好得多

一步一步
  • [获取列的标签:
    col1,col2=df.columns[0],df.columns[1]
    ]

  • 为满足条件的行创建一个布尔掩码,该掩码为
    True
    ,即第一列为非空,第二列为空:

    mask=(df.loc[:,col1]!=“”)和(df.loc[:,col2]=“”)
    mask.iloc[0]=False
    
    在这里,我们手动将掩码的第一个元素设置为
    False
    ,因为即使第一行满足条件,我们也无法对其执行任何操作(没有要将第一列的值复制到的前一行)。(这对于没有环绕的
    Series.shift
    来说不是问题,但当我们在步骤3中使用此掩码来选择要分配的值时,使用
    df.loc[mask,col1]。值
    :如果
    mask.iloc[0]
    True
    ,我们将比目标多一个值。)

  • 将掩码向后移动1,以获得要修改的行的掩码(即紧靠满足条件的行之前的行):

    mask.shift(-1,fill_值=False)
    
    由于我们将掩码向后移动1,最后一个元素不会被定义,因此我们使用
    fill\u value=False
    将其设置为
    False
    ——我们不想修改最后一行

  • 在第1列中,使用我们计算的两个掩码,将满足条件的行的值分配给它们各自的前一行:

    df.loc[mask.shift(-1,fill_value=False),col1]=df.loc[mask,col1]。值
    
    在这里,我们必须使用右侧的
    .values
    来获得原始的numpy值数组,因为如果我们将其作为
    系列
    ,pandas将尝试对齐lhs和rhs的索引(由于我们将行移动了一个,索引将不匹配,因此最终结果将包含
    NaN
    s);相反,我们只想将rhs的第一个元素分配给lhs的第一个插槽,将第二个元素分配给第二个插槽,等等

  • 这与Chaos在评论中概述的方法大致相同

    例子
    >>sample=pd.DataFrame([(“spam”、“)、(“foo”、“bar”)、(“baz”、“)、(“eggs”))
    >>>df=sample.copy()
    >>>df
    0     1
    0垃圾邮件
    1富吧
    2巴兹
    3个鸡蛋
    >>>col1,col2=df.columns[0],df.columns[1]
    >>>掩码=(df.loc[:,col1]!=“”)和(df.loc[:,col2]=“”)
    >>>mask.iloc[0]=False
    >>>df.loc[mask.shift(-1,fill_value=False),col1]=df.loc[mask,col1]。值
    >>>df
    0     1
    0垃圾邮件
    1巴兹酒吧
    2巴兹
    3个鸡蛋
    

    补遗 如果您确实希望将第一行的值换行到最后一行(如果条件适用于第一行)-即,您希望循环移动值-,则可以使用而不是
    系列。shift

    mask=(df.loc[:,col1]!=“”)和(df.loc[:,col2]=“”)
    df.loc[np.roll(掩码,-1),col1]=np.roll(df.loc[mask,col1]。值,-1)
    
    然后,继续上一个示例:

    df=sample.copy() >>>掩码=(df.loc[:,col1]!=“”)和(df.loc[:,col2]=“”) >>>df.loc[np.roll(掩码,-1),col1]=np.roll(df.loc[mask,col1]。值,-1) >>>df 0 1 0垃圾邮件 1巴兹酒吧 2巴兹 3个垃圾鸡蛋
    如果您找不到更具Python风格的方法,以下是正确的代码:

    for i in range(1, len(df)):
        if df.iloc[i, 2]='' and df.iloc[i, 1]!='':
            df.iloc[i-1, 1]=df.iloc[i,1]
            df.iloc[i, 1]=''
    

    看看熊猫的方法。1) 使用shift获取列1的滞后版本(滞后列1)。2) 如果逻辑测试为真(第2列为空,第1列不为空),则用滞后列覆盖第1列。3) 删除lagged_col_1。当您遇到三个连续的行时,您会怎么做:1)所有行在col1中都有一个值,2)所有三行中的col2都为空?您当前的代码将只使用第二行替换第一行,而不使用第三行。这就是你想要的吗?@RichieV不,这确实是针对这些文件的,所以我不需要其他任何东西。他们有时会遇到这个问题,因为导出它们的程序出错(公立医院使用这个程序,所以在导出过程中不容易更改任何内容),所以我只需要一种快速的方法来修复它,因为文件很大,循环似乎很慢。正如我在阿纳坎德回答的评论中所说的那样,这样的速度大约快70倍。。。这几天我读了很多关于熊猫的书,这些东西看起来很神奇!哇,非常详细的回答!非常感谢,我会测试这些文件,然后回来
    for i in range(1, len(df)):
        if df.iloc[i, 2]='' and df.iloc[i, 1]!='':
            df.iloc[i-1, 1]=df.iloc[i,1]
            df.iloc[i, 1]=''