Trying to update each row from df1 to df2 if unique_value is matched, then based on status from df1, update price in price_array in df2; If not, append the row to df2 and assign new ID column.
This is a part 2 question from: Iterate each row by updating values from 1st dataframe to 2nd dataframe based on unique value w/ different index, otherwise append and assign new ID
Note:
active and new: add
suspended and inactive: remove
df1 (NO ID COLUMN):
unique_value Status Price
0 xyz123 active 6.67
1 eff987 suspended 1.75
2 efg125 active 5.77
3 xyz123 new 7.55
4 xyz123 inactive 4.55
5 eff987 new 5.55
df2:
unique_value Price_array ID
0 xyz123 {4.55} 1000
1 xyz985 {1.31} 1001
2 abc987 {4.56} 1002
3 eff987 {1.75} 1003
4 asd541 {8.85} 1004
Desired output for updated df2:
unique_value Price_array ID
0 xyz123 {6.67,7.55} 1000 <- updated (added 6.67, added 7.55, removed 4.55)
1 xyz985 {1.31} 1001
2 abc987 {4.56} 1002
3 eff987 {5.55} 1003 <- updated (removed 1.75, added 5.55)
4 asd541 {8.85} 1004
5 efg125 {5.77} 1005 <- appended and new ID assigned
Here is the code from part 1: Iterate each row by updating values from 1st dataframe to 2nd dataframe based on unique value w/ different index, otherwise append and assign new ID
# 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))
#UPDATE PRICE with PRICE_ARRAY
...see below
# 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]
Is there any way to update the price in df1 to price_array in df2 based on status from df1? I'm thinking something along the line of this ("status" column removed from the broadcast portion of the code):
curr_price=df1.iloc[i,df1.columns.get_loc('Price')]
if df1.iloc[i,df1.columns.get_loc('Status')] in ('inactive', 'suspended'):
df2.loc[df2["unique_value"] == uv1,'Price_array'].discard(curr_price)
else:
df2.loc[df2["unique_value"] == uv1,'Price_array'].add(curr_price)
But got the following error:
ValueError Traceback (most recent call last)
<ipython-input-156-6ff78c7a4a9a> in <module>()
46 if mask[i]:
47 # Broadcast refresh table into the matched rows in historical
---> 48 df2.loc[df2["unique_value"] == uv1, ["unique_value", "Price"]] = df1.iloc[i, :].values.reshape((1,3))
49
/anaconda/envs/pyfull36/lib/python3.6/site-packages/pandas/core/indexing.py in __setitem__(self, key, value)
192 key = com._apply_if_callable(key, self.obj)
193 indexer = self._get_setitem_indexer(key)
--> 194 self._setitem_with_indexer(indexer, value)
195
196 def _has_valid_type(self, k, axis):
/anaconda/envs/pyfull36/lib/python3.6/site-packages/pandas/core/indexing.py in _setitem_with_indexer(self, indexer, value)
581 value = np.array(value, dtype=object)
582 if len(labels) != value.shape[1]:
--> 583 raise ValueError('Must have equal len keys and value '
584 'when setting with an ndarray')
585
ValueError: Must have equal len keys and value when setting with an ndarray