#python #python-3.x #pandas #dataframe #iteration
Вопрос:
Например, если имя ‘Mark’ повторяется и если значение ‘Age’ или ‘Gender’ отличается по сравнению с другими строками, которые содержат ‘Mark’, то такие столбцы должны быть удалены.
Код для создания фрейма данных:
df = pd.DataFrame({'Name' : ['Mark', 'Mark', 'Mark', 'Mark', 'Mark', 'Nick', 'Nick', 'John', 'Sunny', 'Sunny'],
'Age' : ['22', '22', '25', '25', '17', '20', '20', '17', '23', '23'],
'Gender' : ['F', 'F', 'F', 'F', 'F', 'F', 'F', 'M', 'M', 'M']})
Фрейм данных приведен ниже:
Name Age Gender
0 Mark 22 F
1 Mark 22 F
2 Mark 25 F
3 Mark 25 F
4 Mark 17 F
5 Nick 20 F
6 Nick 20 F
7 John 17 M
8 Sunny 23 M
9 Sunny 23 M
Ожидаемый результат:
Name Age Gender
0 Nick 20 F
1 Nick 20 F
2 John 17 M
3 Sunny 23 M
4 Sunny 23 M
Например, в 1-й и 2-й строках имя — Марк, возраст — 22, а пол — F. В то время как в 3-й строке имя — Mark, возраст — 25, а пол — F, мы видим, что возраст имеет несколько значений, тогда нам нужно удалить строки, содержащие Mark
Комментарии:
1. Какие проблемы у вас возникают при выполнении этого самостоятельно? На самом деле это не проблема программирования
2. Я не согласен, @Laif. Это можно сделать с
pandas
помощью группировки и унификации, но это не очевидно.3. @TimRoberts Это вполне возможно, я говорю, что вопрос, похоже, касается математического метода или инструмента для выполнения операций, а не проблемы, с которой OP сталкивается с их программой.
Ответ №1:
Хорошо, это сложно, поэтому я объясню каждую строку.
import pandas as pd
df = pd.DataFrame({'Name' : ['Mark', 'Mark', 'Mark', 'Mark', 'Mark', 'Nick', 'Nick', 'John', 'Sunny', 'Sunny'],
'Age' : ['22', '22', '25', '25', '17', '20', '20', '17', '23', '23'],
'Gender' : ['F', 'F', 'F', 'F', 'F', 'F', 'F', 'M', 'M', 'M']})
print(df)
# First, drop all the rows that are exact duplicates of each other.
df1 = df.drop_duplicates()
print(df1)
# If any rows that remain have a duplicate name, those need to go.
df2 = df1.duplicated('Name')
print(df2)
# Go build a DF with just the names that were duplicated.
df3 = df1[df2]['Name']
print(df3)
# Find all the rows in the original df that have a name in this list,
# invert that set, and the result is what we want.
df4 = df[~df.Name.isin(df3)]
print(df4)
Несколько из этих операций можно объединить, чтобы сделать однострочный, но я думаю, что это делает его более понятным. Я добавил пустые строки для разделения фреймов данных в выходных данных.
Вывод:
Name Age Gender
0 Mark 22 F
1 Mark 22 F
2 Mark 25 F
3 Mark 25 F
4 Mark 17 F
5 Nick 20 F
6 Nick 20 F
7 John 17 M
8 Sunny 23 M
9 Sunny 23 M
Name Age Gender
0 Mark 22 F
2 Mark 25 F
4 Mark 17 F
5 Nick 20 F
7 John 17 M
8 Sunny 23 M
0 False
2 True
4 True
5 False
7 False
8 False
dtype: bool
2 Mark
4 Mark
Name: Name, dtype: object
Name Age Gender
5 Nick 20 F
6 Nick 20 F
7 John 17 M
8 Sunny 23 M
9 Sunny 23 M
Комментарии:
1. Спасибо, Тим!! Это работает.
Ответ №2:
Однострочный ответ:
df[df.Name.isin((s:=df.drop_duplicates().groupby(['Name']).size().eq(1)).index[s])]
результаты в:
Name Age Gender
5 Nick 20 F
6 Nick 20 F
7 John 17 M
8 Sunny 23 M
9 Sunny 23 M
Возможно, стоит отметить: оператор walrus по-прежнему выделяет память для переменной, s
которую сборщик мусора Python в конечном итоге удалит. Если вам понадобится Series
представление, имеет ли какой Name
-либо из них разные строки, как показано ниже, тогда стоило бы явно назначить его.
>>> s
Name
John True
Mark False
Nick True
Sunny True
dtype: bool
в любом другом месте ваших вычислений, вероятно, стоит явно присвоить его переменной, на которую вы поддерживаете ссылку.
Объяснение:
# from the OG df
df[
# boolean mask if the name is in
df.Name.isin(
# walrus-operator to temporarily hold result
# drop the duplicate rows (duplicates name age gender)
(s:=df.drop_duplicates()
# group on Name
.groupby(['Name'])
# after dropping duplicates, there's only one record
# i.e. no different age/gender records for same name
.size().eq(1))
# mask on names where no-duplicates is true, drop names where false
).index[s]
# pass as series to `df.Name.isin`
)
]
Комментарии:
1. Когда я попытался запустить этот код df[df.Name.isin(s:=(df.drop_duplicates().groupby([‘Name’]).size().eq(1)).index[s])], он возвращал ошибку типа name ‘s’не определено
2. @NithinReddy какую версию Python вы используете? Оператор walrus (
s:=...
) является новым для Python 3.83. Я использую python 3.8.5, но его возвращаемые ‘s’ не определены
4. Есть ли альтернатива?
5. исправлено @NithinReddy; не
(
в том месте.