Python:如果单元格不总是其他列值的后继值,则从单元格中删除值
Python: Removing value from cell if it's not always the successor of other column-values
几天来我一直在与一个问题作斗争。我有一个 15k 文章名称的列表,并将文章名称的前两个词分开,以便能够识别品牌。我的逻辑是,对于每个制造商,检查第二个词 always 是否跟在同一个第一个词后面。如果这是真的,这表明拆分是完整的品牌名称,一切正常。如果不是,则第二个字应删除,因为它表示不仅包含品牌名称,还包含部分产品名称。检查制造商很重要,因为 'split1' 对于不同的制造商来说可能是相同的,表示不同的品牌。
TL;DR: 如果 'split2' 不总是 'split1' 和 'fabricator' 的后继者,则将其设置为 NaN。
这是我的数据框的简化版本:
d = {'fabricator':['coca cola corp.','coca cola corp.','coca cola corp.','haribo ltd','haribo ltd','haribo ltd'],'product name': ['coca cola light', 'coca cola zero', 'fanta', 'haribo gold bears', 'haribo gold bears soft','haribo berries'], 'split1': ['coca', 'coca','fanta', 'haribo', 'haribo','haribo'], 'split2': ['cola', 'cola',np.nan, 'gold','gold', 'berries']}
df = pd.DataFrame(data=d)
print(df)
fabricator product name split1 split2
0 coca cola corp. coca cola light coca cola
1 coca cola corp. coca cola zero coca cola
2 coca cola corp. fanta fanta NaN
3 haribo ltd haribo gold bears haribo gold
4 haribo ltd haribo gold bears soft haribo gold
5 haribo ltd haribo berries haribo berries
这就是最终的样子:
fabricator product name split1 split2
0 coca cola corp. coca cola light coca cola
1 coca cola corp. coca cola zero coca cola
2 coca cola corp. fanta fanta NaN
3 haribo ltd haribo gold bears haribo NaN
4 haribo ltd haribo gold bears soft haribo NaN
5 haribo ltd haribo berries haribo NaN
此代码对于小型 df 可以按预期工作,但对于大型数据集而非“pythonesque”来说非常慢:
for h in df['fabricator']:
for s1 in df['split1']:
if df.loc[(df['fabricator] == f) & (df['split1'] == s1), 'split2'].nunique() > 1:
df.loc[(df['fabricator] == f) & (df[split1'] == s1), 'split2'] = str('')
我尝试将 groupby(['fabricator','split1']) 与 .duplicated() 和 .transform() 结合使用,但没有成功。
任何帮助将非常感激! 谢谢!
这应该可以解决问题(从我第一次发布时开始对其进行了大量编辑):
pair_dict = {}
nanmapset = set()
for split1, split2 in df[['split1', 'split2']].values:
if split1 not in pair_dict:
pair_dict[split1] = split2
elif split2 != pair_dict[split1]:
nanmapset.add((split1, split2))
nanmapset.add((split1, pair_dict[split1]))
df['split2'] = df.apply(lambda row: row['split2'] if (row['split1'], row['split2']) not in nanmapset else np.nan, axis=1)
一种直接的方法是根据 split2
中的值数量为 split1
的每个值创建一个过滤器:
filter_ = df.groupby('split1').agg({'split2':'nunique'}).rename(columns = {'split2':'split2_filter'}).lt(2).reset_index()
filter_
这看起来像:
split1
split2_filter
0
coca
True
1
fanta
True
2
haribo
False
现在您可以简单地将原始数据框与此合并:
df = df.merge(filter_, on='split1')
您的数据框现在有一个要过滤的列:
fabricator
product name
split1
split2
split2_filter
0
coca cola corp.
coca cola light
coca
cola
True
1
coca cola corp.
coca cola zero
coca
cola
True
2
coca cola corp.
fanta
fanta
nan
True
3
haribo ltd
haribo gold bears
haribo
gold
False
4
haribo ltd
haribo gold bears soft
haribo
gold
False
5
haribo ltd
haribo berries
haribo
berries
False
现在您可以像这样简单地进行过滤:
df.loc[~df.split2_filter, 'split2'] = np.nan
你的数据框看起来像:
fabricator
product name
split1
split2
split2_filter
0
coca cola corp.
coca cola light
coca
cola
True
1
coca cola corp.
coca cola zero
coca
cola
True
2
coca cola corp.
fanta
fanta
nan
True
3
haribo ltd
haribo gold bears
haribo
nan
False
4
haribo ltd
haribo gold bears soft
haribo
nan
False
5
haribo ltd
haribo berries
haribo
nan
False
您还可以选择删除过滤列:
df.drop(columns=['split2_filter'])
您的数据框将如下所示:
fabricator
product name
split1
split2
0
coca cola corp.
coca cola light
coca
cola
1
coca cola corp.
coca cola zero
coca
cola
2
coca cola corp.
fanta
fanta
nan
3
haribo ltd
haribo gold bears
haribo
nan
4
haribo ltd
haribo gold bears soft
haribo
nan
5
haribo ltd
haribo berries
haribo
nan
几天来我一直在与一个问题作斗争。我有一个 15k 文章名称的列表,并将文章名称的前两个词分开,以便能够识别品牌。我的逻辑是,对于每个制造商,检查第二个词 always 是否跟在同一个第一个词后面。如果这是真的,这表明拆分是完整的品牌名称,一切正常。如果不是,则第二个字应删除,因为它表示不仅包含品牌名称,还包含部分产品名称。检查制造商很重要,因为 'split1' 对于不同的制造商来说可能是相同的,表示不同的品牌。
TL;DR: 如果 'split2' 不总是 'split1' 和 'fabricator' 的后继者,则将其设置为 NaN。
这是我的数据框的简化版本:
d = {'fabricator':['coca cola corp.','coca cola corp.','coca cola corp.','haribo ltd','haribo ltd','haribo ltd'],'product name': ['coca cola light', 'coca cola zero', 'fanta', 'haribo gold bears', 'haribo gold bears soft','haribo berries'], 'split1': ['coca', 'coca','fanta', 'haribo', 'haribo','haribo'], 'split2': ['cola', 'cola',np.nan, 'gold','gold', 'berries']}
df = pd.DataFrame(data=d)
print(df)
fabricator product name split1 split2
0 coca cola corp. coca cola light coca cola
1 coca cola corp. coca cola zero coca cola
2 coca cola corp. fanta fanta NaN
3 haribo ltd haribo gold bears haribo gold
4 haribo ltd haribo gold bears soft haribo gold
5 haribo ltd haribo berries haribo berries
这就是最终的样子:
fabricator product name split1 split2
0 coca cola corp. coca cola light coca cola
1 coca cola corp. coca cola zero coca cola
2 coca cola corp. fanta fanta NaN
3 haribo ltd haribo gold bears haribo NaN
4 haribo ltd haribo gold bears soft haribo NaN
5 haribo ltd haribo berries haribo NaN
此代码对于小型 df 可以按预期工作,但对于大型数据集而非“pythonesque”来说非常慢:
for h in df['fabricator']:
for s1 in df['split1']:
if df.loc[(df['fabricator] == f) & (df['split1'] == s1), 'split2'].nunique() > 1:
df.loc[(df['fabricator] == f) & (df[split1'] == s1), 'split2'] = str('')
我尝试将 groupby(['fabricator','split1']) 与 .duplicated() 和 .transform() 结合使用,但没有成功。 任何帮助将非常感激! 谢谢!
这应该可以解决问题(从我第一次发布时开始对其进行了大量编辑):
pair_dict = {}
nanmapset = set()
for split1, split2 in df[['split1', 'split2']].values:
if split1 not in pair_dict:
pair_dict[split1] = split2
elif split2 != pair_dict[split1]:
nanmapset.add((split1, split2))
nanmapset.add((split1, pair_dict[split1]))
df['split2'] = df.apply(lambda row: row['split2'] if (row['split1'], row['split2']) not in nanmapset else np.nan, axis=1)
一种直接的方法是根据 split2
中的值数量为 split1
的每个值创建一个过滤器:
filter_ = df.groupby('split1').agg({'split2':'nunique'}).rename(columns = {'split2':'split2_filter'}).lt(2).reset_index()
filter_
这看起来像:
split1 | split2_filter | |
---|---|---|
0 | coca | True |
1 | fanta | True |
2 | haribo | False |
现在您可以简单地将原始数据框与此合并:
df = df.merge(filter_, on='split1')
您的数据框现在有一个要过滤的列:
fabricator | product name | split1 | split2 | split2_filter | |
---|---|---|---|---|---|
0 | coca cola corp. | coca cola light | coca | cola | True |
1 | coca cola corp. | coca cola zero | coca | cola | True |
2 | coca cola corp. | fanta | fanta | nan | True |
3 | haribo ltd | haribo gold bears | haribo | gold | False |
4 | haribo ltd | haribo gold bears soft | haribo | gold | False |
5 | haribo ltd | haribo berries | haribo | berries | False |
现在您可以像这样简单地进行过滤:
df.loc[~df.split2_filter, 'split2'] = np.nan
你的数据框看起来像:
fabricator | product name | split1 | split2 | split2_filter | |
---|---|---|---|---|---|
0 | coca cola corp. | coca cola light | coca | cola | True |
1 | coca cola corp. | coca cola zero | coca | cola | True |
2 | coca cola corp. | fanta | fanta | nan | True |
3 | haribo ltd | haribo gold bears | haribo | nan | False |
4 | haribo ltd | haribo gold bears soft | haribo | nan | False |
5 | haribo ltd | haribo berries | haribo | nan | False |
您还可以选择删除过滤列:
df.drop(columns=['split2_filter'])
您的数据框将如下所示:
fabricator | product name | split1 | split2 | |
---|---|---|---|---|
0 | coca cola corp. | coca cola light | coca | cola |
1 | coca cola corp. | coca cola zero | coca | cola |
2 | coca cola corp. | fanta | fanta | nan |
3 | haribo ltd | haribo gold bears | haribo | nan |
4 | haribo ltd | haribo gold bears soft | haribo | nan |
5 | haribo ltd | haribo berries | haribo | nan |