Python 通过基于具有不同索引的唯一值将值从第一个数据帧更新到第二个数据帧来迭代每一行,否则追加并分配新ID
如果匹配唯一值,则尝试将每一行从df1更新为df2。如果不是,则将该行附加到df2并分配新的ID列 df1(无ID列): df2: 更新的df2的期望输出:Python 通过基于具有不同索引的唯一值将值从第一个数据帧更新到第二个数据帧来迭代每一行,否则追加并分配新ID,python,pandas,function,numpy,dataframe,Python,Pandas,Function,Numpy,Dataframe,如果匹配唯一值,则尝试将每一行从df1更新为df2。如果不是,则将该行附加到df2并分配新的ID列 df1(无ID列): df2: 更新的df2的期望输出: unique_value Status Price ID 0 xyz123 bad 6.67 1000 <-updated 1 xyz123 bad
unique_value Status Price ID
0 xyz123 bad 6.67 1000 <-updated
1 xyz123 bad 6.67 1000 <-updated
2 xyz123 bad 6.67 1000 <-updated
3 xyz123 bad 6.67 1000 <-updated
4 xyz985 bad 1.31 1001
5 abc987 okay 4.56 1002
6 eff987 bad 1.75 1003 <-updated
7 asd541 excellent 8.85 1004
8 efg125 okay 5.77 1005 <-appended
注意,我最初使用pd.factorize
根据df2
的唯一_值分配ID,值从1000
,1001
(依此类推)使用以下代码:df2['ID']=pd.factorize(df2['unique_值'])[0]+1000
我尝试使用这个解决方案(),但是它索引了我的unique_value列,这阻止了我继续迭代另一个数据集
我们可以用什么方法来编写脚本
谢谢 我实施这两部分的策略解释如下
df2
可以通过更新,前提是df1
中的行的形状正确地重新塑造为(1,3)
。pandas
中的广播概念与numpy
中的广播概念相同0
开始计数,可以通过直接调用df2.loc[len(df2),:]=…
轻松追加新行,其中len(df2)
是索引列的下一个未使用的自然数。示例:df2
更有效。如果这不是一个问题,它们当然可以被丢弃
代码:
# additional state variables
# 1. for the ID to be added
current_max_id = df2["ID"].max()
# 2. for matching unique_values, avoiding searching df2["unique_value"] every time
current_value_set = set(df2["unique_value"].values)
# match unique_value's using the state variable instead of `df2`
mask = df1["unique_value"].isin(current_value_set)
for i in range(len(df1)):
# current unique_value from df1
uv1 = df1["unique_value"][i]
# 1. update existing
if mask[i]:
# broadcast df1 into the matched rows in df2 (mind the shape)
df2.loc[df2["unique_value"] == uv1, ["unique_value", "Status", "Price"]] = df1.iloc[i, :].values.reshape((1, 3))
# 2. append new
else:
# update state variables
current_max_id += 1
current_value_set.add(uv1)
# append the row (assumes df2.index=[0,1,2,3,...])
df2.loc[len(df2), :] = [df1.iloc[i, 0], df1.iloc[i, 1], df1.iloc[i, 2], current_max_id]
df2
Out[45]:
unique_value Status Price ID
0 xyz123 bad 6.67 1000.0
1 xyz123 bad 6.67 1000.0
2 xyz123 bad 6.67 1000.0
3 xyz123 bad 6.67 1000.0
4 xyz985 bad 1.31 1001.0
5 abc987 okay 4.56 1002.0
6 eff987 bad 1.75 1003.0
7 asd541 excellent 8.85 1004.0
8 efg125 okay 5.77 1005.0
输出:
# additional state variables
# 1. for the ID to be added
current_max_id = df2["ID"].max()
# 2. for matching unique_values, avoiding searching df2["unique_value"] every time
current_value_set = set(df2["unique_value"].values)
# match unique_value's using the state variable instead of `df2`
mask = df1["unique_value"].isin(current_value_set)
for i in range(len(df1)):
# current unique_value from df1
uv1 = df1["unique_value"][i]
# 1. update existing
if mask[i]:
# broadcast df1 into the matched rows in df2 (mind the shape)
df2.loc[df2["unique_value"] == uv1, ["unique_value", "Status", "Price"]] = df1.iloc[i, :].values.reshape((1, 3))
# 2. append new
else:
# update state variables
current_max_id += 1
current_value_set.add(uv1)
# append the row (assumes df2.index=[0,1,2,3,...])
df2.loc[len(df2), :] = [df1.iloc[i, 0], df1.iloc[i, 1], df1.iloc[i, 2], current_max_id]
df2
Out[45]:
unique_value Status Price ID
0 xyz123 bad 6.67 1000.0
1 xyz123 bad 6.67 1000.0
2 xyz123 bad 6.67 1000.0
3 xyz123 bad 6.67 1000.0
4 xyz985 bad 1.31 1001.0
5 abc987 okay 4.56 1002.0
6 eff987 bad 1.75 1003.0
7 asd541 excellent 8.85 1004.0
8 efg125 okay 5.77 1005.0
使用python 3.7、pandas 1.1.2、OS=debian 10 64位进行测试谢谢@Bill!快速提问,为什么在将df1广播到df2中的匹配行时需要重塑?我猜:如果主数组碰巧具有形状(3,3),并且您提供了形状(3,)的数组。那么你要广播哪个维度呢?作为(3,1)或(1,3)?因此,每当有这样的陷阱时,我自己总是显式地分配单例维度。再次感谢@Bill。知道为什么ID列返回为
浮点值吗?那只是因为我在复制粘贴时忘记了重新格式化输入IDdf2[“ID”]=df2[“ID”]。开始时的astype(int)
解决了这个问题,但您在实际的工作流中不需要它,因为它是由在SO上重新导入文本数据引起的。非常感谢您的帮助@Bill!
df2
Out[45]:
unique_value Status Price ID
0 xyz123 bad 6.67 1000.0
1 xyz123 bad 6.67 1000.0
2 xyz123 bad 6.67 1000.0
3 xyz123 bad 6.67 1000.0
4 xyz985 bad 1.31 1001.0
5 abc987 okay 4.56 1002.0
6 eff987 bad 1.75 1003.0
7 asd541 excellent 8.85 1004.0
8 efg125 okay 5.77 1005.0