我正在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
。请可以对此进行纠正。
另外,我想知道是否有其他有效的替代方法来执行它。请告诉我。
答案 0 :(得分:2)
新答案:
您有两个嵌入式循环。第一个总是完整循环。但不是第二个。因此,问题在于如何提高子局部循环的效率。
在这里,我为您提供两种执行第二个循环的方法:
此discussion可能会给您一些有关如何执行迭代的见识。
# 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
。要了解其中的表现,您可以查看this。and
的{{1}}运算符。最后,您可以调用where
函数,该函数在不满足条件时返回&
。
要适合所需的输出,可以使用iloc
或仅调用列名来过滤列。
代码在这里:
Nan
答案 1 :(得分:0)
经过几次试验,我能够解决自己的代码。这是-已纠正的一个:
df3 = {}
Col_A = []
Col_C = []
Col_Z = []
for i in df1.iterrows():
value = 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 value.empty:
Col_Z.append(float('NaN'))
Col_A.append(float('NaN'))
Col_C.append(float('NaN'))
else:
Col_Z.append(value)
Col_A.append(i[1][0])
Col_C.append(i[1][2])
df3['A'] = Col_A
df3['C'] = Col_C
df3['Z'] = Col_Z
df3 = pd.DataFrame(df3)
但是,由于for
循环遍历所有行,因此该方法可能不适用于大型数据集,例如100-200百万。
希望找到一些更有效的方法!