python - 如何通过考虑其他数据帧的条件在 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
. 请可以纠正这一点。
另外,我想知道是否有任何替代且有效的方法来执行它。请告诉我。
解决方案
新答案:
你有两个嵌入循环。第一个总是一个完整的循环。但不是第二个。所以问题是如何提高子局部循环的效率。
在这里,我给你两种方法来执行第二个循环:
- 第一个将数据集视为一个整体,处理所有数据并选择感兴趣的值
- 第二个迭代行直到匹配条件。
这个讨论可能会给你一些关于如何执行迭代的见解。
# 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
推荐阅读
- javascript - 如何注销打开的浏览器窗口
- kubernetes - 如何从备份文件中恢复 kubernetes configmap
- animation - 动画未在 a-frame 0.9.2 的事件上重新启动
- python - mac地址的字节数组格式
- ruby-on-rails - 关于 Ruby on Rails 最佳实践,我应该把计算关键指标和分析的方法放在哪里?
- python - 遍历和提取树的节点时出现问题?
- kubernetes - 在 Kubernetes 上运行 Airflow 任务
- php - 在 PHP 中,为什么当我将 var 作为字符串转换为浮点数时,我会失去精度?
- python - 需要帮助确定用户是否使用 Python 回答“是”或“否”
- ruby - 使用 Ruby File.open 写入具有长文件名的外部文件