首页 > 解决方案 > 如何通过考虑其他数据帧的条件在 python 中生成新的数据帧?

问题描述

我正在python使用pandas一个非常大的数据集(比如 1 亿行)执行数据操作。我有两个数据帧,希望根据提到的条件生成第三个数据帧,场景解释如下:

数据帧 1:
Col_B 和 Col_D 属于int64类型

Col_A   Col_B   Col_C   Col_D
 A       11      B       20
 A       11      C       24
 B       14      R       32
...      ...    ...      ...

数据框2:
Col_Z 是类型float64,其余列是int64

Col_X   Col_Y   Col_P   Col_Q   Col_Z
 10      15      16      21      0.99
 10      15      17      22      0.89
...     ...     ...     ...      ...
...     ...     ...     ...      ...
 11      15      30      35      0.67
...     ...     ...     ...      ...

要应用的条件:为了理解条件,只考虑两个数据帧的第一行:

如果 (Col_B 的值介于 Col_X 和 Col_Y 的值之间) 且 (Col_D 的值介于 Col_P 和 Col_Q 的值之间) 则返回 Col_A、Col_C 和 Col_Z 的对应值,否则返回 NaN

预期输出(数据框 3):

Col_A   Col_C   Col_Z
 A       B       0.99
NaN     NaN      NaN
 B       R       0.67

注意:此输出仅考虑数据帧中是否只有这三行,但实际上数据帧 1 的每个值都必须扫描数据帧 2 中的所有值,直到达到所需条件。

我的代码:

df3 = {}
Col_A = []
Col_C = []
Col_Z = []
for i in df1.iterrows():    
    value = float(df2[(i[1][1] > df2['Col_X'].values) &
      (i[1][1] < df2['Col_Y'].values) &
      (i[1][3] > df2['Col_P'].values) &
      (i[1][3] < df2['Col_Q'].values)]['Col_Z'])

    if bool(value):
        Col_Z.append(value)
        Col_A.append(i[1][0])
        Col_C.append(i[1][2])
    else:
        Col_Z.append(float('NaN'))
        Col_A.append(float('NaN'))
        Col_C.append(float('NaN'))

在满足条件之前,此代码工作正常,只要条件不满足,它就会抛出一个TypeError. 请可以纠正这一点。

另外,我想知道是否有任何替代且有效的方法来执行它。请告诉我。

标签: pythonpandasnumpydata-manipulation

解决方案


新答案

你有两个嵌入循环。第一个总是一个完整的循环。但不是第二个。所以问题是如何提高子局部循环的效率。

在这里,我给你两种方法来执行第二个循环:

  • 第一个将数据集视为一个整体,处理所有数据并选择感兴趣的值
  • 第二个迭代行直到匹配条件。

这个讨论可能会给你一些关于如何执行迭代的见解。

# Import module
import numpy as np

df1 = pd.DataFrame([["A", 11,  "B", 20],
                    ["A", 11,  "C", 24],
                    ["B", 14,  "R", 32]],
                   columns=["Col_A", "Col_B", "Col_C", "Col_D"])
df2 = pd.DataFrame([[10, 15,  16, 21, 0.99],
                    [10, 15,  17, 22, 0.89],
                    [11, 15,  30, 35, 0.67]],
                   columns=["Col_X", "Col_Y", "Col_P", "Col_Q", "Col_Z"])

def getCondition(row, df2):
    # Iterate df2 till a row meets the condition
    for _, row_df2 in df2.iterrows():
        if row_df2.Col_X <= row.Col_B and row.Col_B < row_df2.Col_Y \
            and row_df2.Col_P <= row.Col_D and row.Col_D < row_df2.Col_Q:
            return pd.Series([row.Col_A, row.Col_C, row_df2.Col_Z])
    return np.NaN


def getCondition2(row, df2):
    # Find all rows matching the condition and select the first
    condition = ((df2.Col_X <= row.Col_B) & (row.Col_B < df2.Col_Y)\
        & (df2.Col_P <= row.Col_D) & (row.Col_D < df2.Col_Q))
    if sum(condition) > 0:
        return pd.Series([row.Col_A, row.Col_C, df2.Col_Z[condition].iloc[0]])
    return np.NaN


# Apply the condition
output = df1.apply(getCondition2, args=[df2], axis=1)
print(output)
#      0    1     2
# 0    A    B  0.99
# 1  NaN  NaN   NaN
# 2    B    R  0.67

旧答案

您可以通过将数据集视为一个整体来做到这一点。

  • 首先,为了更方便,我建议您将两个数据集合并为一个数据集。您可以使用merge函数或仅使用concat. 在这里,我使用,concat因为另一个解决方案使用merge. 要清楚那里的表现,你可以看看这个
  • 然后,您可以在整个列上定义您的条件。照顾and成为&.
  • 最后,您可以调用不满足条件时where返回的函数。Nan

  • 为了适合所需的输出,您可以使用iloc或仅调用列名称来过滤列。

这里的代码:

# Import module
import pandas as pd

df1 = pd.DataFrame([["A", 11,  "B", 20],
                    ["A", 11,  "C", 24],
                    ["B", 14,  "R", 19]],
                   columns=["Col_A", "Col_B", "Col_C", "Col_D"])
df2 = pd.DataFrame([[10, 15,  16, 21, 0.99],
                    [10, 15,  17, 22, 0.89],
                    [11, 15,  16, 20, 0.67]],
                   columns=["Col_X", "Col_Y", "Col_P", "Col_Q", "Col_Z"])

# Concat the dataframe
df = pd.concat([df1, df2], axis=1)
print(df)

# Define the conditions
condition_col_b = ((df.Col_X <= df.Col_B) & (df.Col_B < df.Col_Y))
condition_col_d = ((df.Col_P <= df.Col_D) & (df.Col_D < df.Col_Q))

print(condition_col_b & condition_col_d)
# 0     True
# 1    False
# 2     True

# Apply the condition
output = df.where(condition_col_b & condition_col_d)
print(output)
#   Col_A  Col_B Col_C  Col_D  Col_X  Col_Y  Col_P  Col_Q  Col_Z
# 0     A   11.0     B   20.0   10.0   15.0   16.0   21.0   0.99
# 1   NaN    NaN   NaN    NaN    NaN    NaN    NaN    NaN    NaN
# 2     B   14.0     R   19.0   11.0   15.0   16.0   20.0   0.67

# Filter output
print(output[['Col_A', 'Col_C', 'Col_Z']])
#   Col_A Col_C  Col_Z
# 0     A     B   0.99
# 1   NaN   NaN    NaN
# 2     B     R   0.67

推荐阅读