如何根据数组列的值删除 pandas 行?
How to drop pandas row based on values of array column?
我在 pandas 中有以下数据框:
id name categoryids shops
5 239 Boulanger [5] 152
3 196 Bouygues Telecom [5] 500
4 122 Darty [5,3] 363
1 311 Electro Dépôt [5] 81
0 2336 Orange [15] 578
2 194 Orange [5] 577
我想删除第 5 行,因为它的名称重复但在 categoryids 列中具有不同的值,但由于值是数组(因为它们可以有更多一个值),我在比较它们时遇到问题。
我的想法是检查此列的模式并丢弃其数组中没有此值的所有行(例如,在本例中,模式为 5,因此应丢弃第 5 列因为这个值不存在于它的数组中),但是我在计算这个值时遇到了问题,因为该列是一个数组,而不是单个值。
关于如何做到这一点有什么想法或建议吗?
我正在使用 python 3.7 和 pandas 的最新版本。
谢谢。
你可以试试:
df = df.drop_duplicates(subset = ['name'])
这将只查看列名中的重复项。您可以通过将其他列名称添加到子集列表来组合列。
使用这样的 DataFrame:
df = pd.DataFrame({'id': [239,196,122,311,2336,194,],
'name': ['Boulanger','Bouygues Telecom','Darty','Electro Dépôt','Orange','Orange',],
'shops': [152, 500, 363, 81, 578, 577,],
'categoryids': [[5],[5],[5,3],[5],[15],[5],]})
你可以这样做:
df.sort_values('categoryids').drop_duplicates('name', keep='first')
对 categoryids
列进行排序,然后删除 name
中的重复项并保留第一个。
编辑:
您可以做的另一件事是检查您在 categoryids
列中查找的值是否存在:
df["exist"] = [int(5 in r) for r in df["categoryids"]]
哪个会给你:
id name shops categoryids exist
0 239 Boulanger 152 [5] 1
1 196 Bouygues Telecom 500 [5] 1
2 122 Darty 363 [5, 3] 1
3 311 Electro Dépôt 81 [5] 1
4 2336 Orange 578 [15] 0
5 194 Orange 577 [5] 1
然后你可以只取现存的:
df[df['exist'] == 1]
然后使用 pd.duplicated()
查找重复项,如@Erfan 所述:
df['dups'] = df['name'].duplicated(keep=False).astype(int)
id name shops categoryids exist dups
0 239 Boulanger 152 [5] 1 0
1 196 Bouygues Telecom 500 [5] 1 0
2 122 Darty 363 [5, 3] 1 0
3 311 Electro Dépôt 81 [5] 1 0
4 2336 Orange 578 [15] 0 1
5 194 Orange 577 [5] 1 1
df[(
(df['dups']!=1) |
(df['exist']!=0)
)].drop(['exist', 'dups'], axis=1).reset_index()
会导致:
index id name shops categoryids
0 0 239 Boulanger 152 [5]
1 1 196 Bouygues Telecom 500 [5]
2 2 122 Darty 363 [5, 3]
3 3 311 Electro Dépôt 81 [5]
4 5 194 Orange 577 [5]
首先我们可以标记 name
列中的哪些行是重复的。
然后我们可以 unnest
您在 categoryids
中的数组,使用 答案中的函数。
最后我们过滤哪些行被不标记为重复或等于mode
:
def unnest(df, tile, explode):
vals = df[explode].sum(1)
rs = [len(r) for r in vals]
a = np.repeat(df[tile].values, rs, axis=0)
b = np.concatenate(vals.values)
d = np.column_stack((a, b))
return pd.DataFrame(d, columns = tile + ['_'.join(explode)])
# Mark duplicate rows
df['dups'] = df.name.duplicated(keep=False).astype(int)
# Unnest categoryids column
df2 = unnest(df, ['id', 'name', 'shops', 'dups'], ['categoryids'])
print(df2)
id name shops dups categoryids
0 239 Boulanger 152 0 5
1 196 Bouygues Telecom 500 0 5
2 122 Darty 363 0 5
3 122 Darty 363 0 3
4 311 Electro Dépôt 81 0 5
5 2336 Orange 578 1 15
6 194 Orange 577 1 5
过滤不等于众数的重复行:
mode = df2['categoryids'].mode()
df2 = df2[~df2['dups'].eq(1) | df2['categoryids'].isin(mode)].drop('dups', axis=1)
print(df2)
id name shops categoryids
0 239 Boulanger 152 5
1 196 Bouygues Telecom 500 5
2 122 Darty 363 5
3 122 Darty 363 3
4 311 Electro Dépôt 81 5
6 194 Orange 577 5
可选
我们可以在 name
上分组以取回数组:
df2 = df2.groupby('name').agg({'id':'first',
'shops':'first',
'categoryids':list}).reset_index()
print(df2)
name id shops categoryids
0 Boulanger 239 152 [5]
1 Bouygues Telecom 196 500 [5]
2 Darty 122 363 [5, 3]
3 Electro Dépôt 311 81 [5]
4 Orange 194 577 [5]
我设法使用@VnC 答案完成了一些修改,因为我认为 categoryids 的数组是实际的整数数组(如上例所示) ,但我发现它们是字符串(不是字符串数组,而是普通字符串):
retailersIds_df = get_dataframe() # external method to get the dataframe, not relevant
retailersIds_df['categoryids'] = retailersIds_df['categoryids'].str.replace('[', '')
retailersIds_df['categoryids'] = retailersIds_df['categoryids'].str.replace(']', '')
retailersIds_df['categoryids'] = retailersIds_df['categoryids'].str.split(',')
# the following lines are used to calculate the mode of all the values contained in the arrays.
ids_aux = []
for row in retailersIds_df.itertuples():
ids_aux = ids_aux + row.categoryids
mydict = Counter(ids_aux)
mode = [key for key, value in mydict.items() if value == max(mydict.values())][0]
# the counter module returns a dict, and the key (the actual value) of the most repeated value is chosen.
#the [0] is for the case where two keys have the same value, and the first is chosen (arbitrarily)
retailersIds_df["exist"] = [int(mode in r) for r in retailersIds_df["categoryids"]]
retailersIds_df = retailersIds_df[retailersIds_df['exist'] == 1]
循环是为了计算模式,虽然可能存在更好的选择(我知道循环不应该在 pandas 数据帧中完成,但我想不出其他选择,考虑到数组可以是任意长度)
我在 pandas 中有以下数据框:
id name categoryids shops
5 239 Boulanger [5] 152
3 196 Bouygues Telecom [5] 500
4 122 Darty [5,3] 363
1 311 Electro Dépôt [5] 81
0 2336 Orange [15] 578
2 194 Orange [5] 577
我想删除第 5 行,因为它的名称重复但在 categoryids 列中具有不同的值,但由于值是数组(因为它们可以有更多一个值),我在比较它们时遇到问题。
我的想法是检查此列的模式并丢弃其数组中没有此值的所有行(例如,在本例中,模式为 5,因此应丢弃第 5 列因为这个值不存在于它的数组中),但是我在计算这个值时遇到了问题,因为该列是一个数组,而不是单个值。
关于如何做到这一点有什么想法或建议吗?
我正在使用 python 3.7 和 pandas 的最新版本。
谢谢。
你可以试试:
df = df.drop_duplicates(subset = ['name'])
这将只查看列名中的重复项。您可以通过将其他列名称添加到子集列表来组合列。
使用这样的 DataFrame:
df = pd.DataFrame({'id': [239,196,122,311,2336,194,],
'name': ['Boulanger','Bouygues Telecom','Darty','Electro Dépôt','Orange','Orange',],
'shops': [152, 500, 363, 81, 578, 577,],
'categoryids': [[5],[5],[5,3],[5],[15],[5],]})
你可以这样做:
df.sort_values('categoryids').drop_duplicates('name', keep='first')
对 categoryids
列进行排序,然后删除 name
中的重复项并保留第一个。
编辑:
您可以做的另一件事是检查您在 categoryids
列中查找的值是否存在:
df["exist"] = [int(5 in r) for r in df["categoryids"]]
哪个会给你:
id name shops categoryids exist
0 239 Boulanger 152 [5] 1
1 196 Bouygues Telecom 500 [5] 1
2 122 Darty 363 [5, 3] 1
3 311 Electro Dépôt 81 [5] 1
4 2336 Orange 578 [15] 0
5 194 Orange 577 [5] 1
然后你可以只取现存的:
df[df['exist'] == 1]
然后使用 pd.duplicated()
查找重复项,如@Erfan 所述:
df['dups'] = df['name'].duplicated(keep=False).astype(int)
id name shops categoryids exist dups
0 239 Boulanger 152 [5] 1 0
1 196 Bouygues Telecom 500 [5] 1 0
2 122 Darty 363 [5, 3] 1 0
3 311 Electro Dépôt 81 [5] 1 0
4 2336 Orange 578 [15] 0 1
5 194 Orange 577 [5] 1 1
df[(
(df['dups']!=1) |
(df['exist']!=0)
)].drop(['exist', 'dups'], axis=1).reset_index()
会导致:
index id name shops categoryids
0 0 239 Boulanger 152 [5]
1 1 196 Bouygues Telecom 500 [5]
2 2 122 Darty 363 [5, 3]
3 3 311 Electro Dépôt 81 [5]
4 5 194 Orange 577 [5]
首先我们可以标记 name
列中的哪些行是重复的。
然后我们可以 unnest
您在 categoryids
中的数组,使用
最后我们过滤哪些行被不标记为重复或等于mode
:
def unnest(df, tile, explode):
vals = df[explode].sum(1)
rs = [len(r) for r in vals]
a = np.repeat(df[tile].values, rs, axis=0)
b = np.concatenate(vals.values)
d = np.column_stack((a, b))
return pd.DataFrame(d, columns = tile + ['_'.join(explode)])
# Mark duplicate rows
df['dups'] = df.name.duplicated(keep=False).astype(int)
# Unnest categoryids column
df2 = unnest(df, ['id', 'name', 'shops', 'dups'], ['categoryids'])
print(df2)
id name shops dups categoryids
0 239 Boulanger 152 0 5
1 196 Bouygues Telecom 500 0 5
2 122 Darty 363 0 5
3 122 Darty 363 0 3
4 311 Electro Dépôt 81 0 5
5 2336 Orange 578 1 15
6 194 Orange 577 1 5
过滤不等于众数的重复行:
mode = df2['categoryids'].mode()
df2 = df2[~df2['dups'].eq(1) | df2['categoryids'].isin(mode)].drop('dups', axis=1)
print(df2)
id name shops categoryids
0 239 Boulanger 152 5
1 196 Bouygues Telecom 500 5
2 122 Darty 363 5
3 122 Darty 363 3
4 311 Electro Dépôt 81 5
6 194 Orange 577 5
可选
我们可以在 name
上分组以取回数组:
df2 = df2.groupby('name').agg({'id':'first',
'shops':'first',
'categoryids':list}).reset_index()
print(df2)
name id shops categoryids
0 Boulanger 239 152 [5]
1 Bouygues Telecom 196 500 [5]
2 Darty 122 363 [5, 3]
3 Electro Dépôt 311 81 [5]
4 Orange 194 577 [5]
我设法使用@VnC 答案完成了一些修改,因为我认为 categoryids 的数组是实际的整数数组(如上例所示) ,但我发现它们是字符串(不是字符串数组,而是普通字符串):
retailersIds_df = get_dataframe() # external method to get the dataframe, not relevant
retailersIds_df['categoryids'] = retailersIds_df['categoryids'].str.replace('[', '')
retailersIds_df['categoryids'] = retailersIds_df['categoryids'].str.replace(']', '')
retailersIds_df['categoryids'] = retailersIds_df['categoryids'].str.split(',')
# the following lines are used to calculate the mode of all the values contained in the arrays.
ids_aux = []
for row in retailersIds_df.itertuples():
ids_aux = ids_aux + row.categoryids
mydict = Counter(ids_aux)
mode = [key for key, value in mydict.items() if value == max(mydict.values())][0]
# the counter module returns a dict, and the key (the actual value) of the most repeated value is chosen.
#the [0] is for the case where two keys have the same value, and the first is chosen (arbitrarily)
retailersIds_df["exist"] = [int(mode in r) for r in retailersIds_df["categoryids"]]
retailersIds_df = retailersIds_df[retailersIds_df['exist'] == 1]
循环是为了计算模式,虽然可能存在更好的选择(我知道循环不应该在 pandas 数据帧中完成,但我想不出其他选择,考虑到数组可以是任意长度)