#python #pandas
#python #pandas #фрейм данных
Вопрос:
У меня есть два фрейма данных df1
и df2
. df1
содержит информацию о возрасте людей, в то время как df2
содержит информацию о поле людей. Не все пользователи находятся в df1
ни в df2
df1
Name Age
0 Tom 34
1 Sara 18
2 Eva 44
3 Jack 27
4 Laura 30
df2
Name Sex
0 Tom M
1 Paul M
2 Eva F
3 Jack M
4 Michelle F
Я хочу иметь информацию о поле людей в df1
и настройках NaN
, если у меня нет этой информации в df2
. Я пытался это сделать, df1 = pd.merge(df1, df2, on = 'Name', how = 'outer')
но я сохраняю информацию некоторых людей в df2
, которая мне не нужна.
df1
Name Age Sex
0 Tom 34 M
1 Sara 18 NaN
2 Eva 44 F
3 Jack 27 M
4 Laura 30 NaN
Ответ №1:
Sample
:
df1 = pd.DataFrame({'Name': ['Tom', 'Sara', 'Eva', 'Jack', 'Laura'],
'Age': [34, 18, 44, 27, 30]})
#print (df1)
df3 = df1.copy()
df2 = pd.DataFrame({'Name': ['Tom', 'Paul', 'Eva', 'Jack', 'Michelle'],
'Sex': ['M', 'M', 'F', 'M', 'F']})
#print (df2)
Используйте map
by Series
, созданный set_index
:
df1['Sex'] = df1['Name'].map(df2.set_index('Name')['Sex'])
print (df1)
Name Age Sex
0 Tom 34 M
1 Sara 18 NaN
2 Eva 44 F
3 Jack 27 M
4 Laura 30 NaN
Альтернативное решение с merge
соединением по левому краю:
df = df3.merge(df2[['Name','Sex']], on='Name', how='left')
print (df)
Name Age Sex
0 Tom 34 M
1 Sara 18 NaN
2 Eva 44 F
3 Jack 27 M
4 Laura 30 NaN
Если требуется сопоставление по нескольким столбцам (например, Year
и Code
), необходимо merge
соединить слева:
df1 = pd.DataFrame({'Name': ['Tom', 'Sara', 'Eva', 'Jack', 'Laura'],
'Year':[2000,2003,2003,2004,2007],
'Code':[1,2,3,4,4],
'Age': [34, 18, 44, 27, 30]})
print (df1)
Name Year Code Age
0 Tom 2000 1 34
1 Sara 2003 2 18
2 Eva 2003 3 44
3 Jack 2004 4 27
4 Laura 2007 4 30
df2 = pd.DataFrame({'Name': ['Tom', 'Paul', 'Eva', 'Jack', 'Michelle'],
'Sex': ['M', 'M', 'F', 'M', 'F'],
'Year':[2001,2003,2003,2004,2007],
'Code':[1,2,3,5,3],
'Val':[21,34,23,44,67]})
print (df2)
Name Sex Year Code Val
0 Tom M 2001 1 21
1 Paul M 2003 2 34
2 Eva F 2003 3 23
3 Jack M 2004 5 44
4 Michelle F 2007 3 67
#merge by all columns
df = df1.merge(df2, on=['Year','Code'], how='left')
print (df)
Name_x Year Code Age Name_y Sex Val
0 Tom 2000 1 34 NaN NaN NaN
1 Sara 2003 2 18 Paul M 34.0
2 Eva 2003 3 44 Eva F 23.0
3 Jack 2004 4 27 NaN NaN NaN
4 Laura 2007 4 30 NaN NaN NaN
#specified columns - columns for join (Year, Code) need always appended columns (Val)
df = df1.merge(df2[['Year','Code', 'Val']], on=['Year','Code'], how='left')
print (df)
Name Year Code Age Val
0 Tom 2000 1 34 NaN
1 Sara 2003 2 18 34.0
2 Eva 2003 3 44 23.0
3 Jack 2004 4 27 NaN
4 Laura 2007 4 30 NaN
Если выдается ошибка с map
, это означает дублирование по столбцам join, здесь Name
:
df1 = pd.DataFrame({'Name': ['Tom', 'Sara', 'Eva', 'Jack', 'Laura'],
'Age': [34, 18, 44, 27, 30]})
print (df1)
Name Age
0 Tom 34
1 Sara 18
2 Eva 44
3 Jack 27
4 Laura 30
df3, df4 = df1.copy(), df1.copy()
df2 = pd.DataFrame({'Name': ['Tom', 'Tom', 'Eva', 'Jack', 'Michelle'],
'Val': [1,2,3,4,5]})
print (df2)
Name Val
0 Tom 1 <-duplicated name Tom
1 Tom 2 <-duplicated name Tom
2 Eva 3
3 Jack 4
4 Michelle 5
s = df2.set_index('Name')['Val']
df1['New'] = df1['Name'].map(s)
print (df1)
InvalidIndexError: Переиндексация допустима только с объектами индекса с уникальным значением
Решения удаляют дубликаты с помощью DataFrame.drop_duplicates
или используют map by dict
для последнего совпадения:
#default keep first value
s = df2.drop_duplicates('Name').set_index('Name')['Val']
print (s)
Name
Tom 1
Eva 3
Jack 4
Michelle 5
Name: Val, dtype: int64
df1['New'] = df1['Name'].map(s)
print (df1)
Name Age New
0 Tom 34 1.0
1 Sara 18 NaN
2 Eva 44 3.0
3 Jack 27 4.0
4 Laura 30 NaN
#add parameter for keep last value
s = df2.drop_duplicates('Name', keep='last').set_index('Name')['Val']
print (s)
Name
Tom 2
Eva 3
Jack 4
Michelle 5
Name: Val, dtype: int64
df3['New'] = df3['Name'].map(s)
print (df3)
Name Age New
0 Tom 34 2.0
1 Sara 18 NaN
2 Eva 44 3.0
3 Jack 27 4.0
4 Laura 30 NaN
#map by dictionary
d = dict(zip(df2['Name'], df2['Val']))
print (d)
{'Tom': 2, 'Eva': 3, 'Jack': 4, 'Michelle': 5}
df4['New'] = df4['Name'].map(d)
print (df4)
Name Age New
0 Tom 34 2.0
1 Sara 18 NaN
2 Eva 44 3.0
3 Jack 27 4.0
4 Laura 30 NaN
Комментарии:
1. здравствуйте, как использовать
df1['Sex'] = df1['Name'].map(df2.set_index('Name')['Sex'])
, когда во втором фрейме данных разное количество строк? я использую его в своем наборе данных и получаю результаты только для первой строки, спасибо2. @sygneto — Это должно работать, значения совпадают? Что возвращает
print (df1['Sex'].unique())
vsprint (df2['Sex'].unique())
?3. у меня есть все уникальные значения, но в моем случае этот столбец
df1['sex']
уже существует и имеет в каждой строке значение = 0, как вы думаете, есть способ его заменить? или, может быть, удалить этот столбец перед отображением?4. @sygneto — Мне нелегко увидеть проблему, потому что я не могу видеть ваши данные. 🙁
5. я думаю, причина в том, что, поскольку у меня уже есть столбец [‘sex’] в обоих фреймах данных, как я могу заменить его или добавить?
Ответ №2:
Вы также можете использовать join
метод:
df1.set_index("Name").join(df2.set_index("Name"), how="left")
редактировать: добавлено set_index("Name")
Ответ №3:
О переиндексации пока не упоминалось, но она очень быстрая и при желании может автоматически заполнять недостающие значения.
DataFrame.reindex
Используйте общий ключ ( Name
) в качестве индекса фрейма данных сопоставления ( df2
):
-
Если
df2
индекс уже естьName
, простоreindex
напрямую:df2['Sex'].reindex(df1['Name'])
-
В противном случае
set_index
заранее:df2.set_index('Name')['Sex'].reindex(df1['Name'])
Обратите внимание, что при назначении в существующий фрейм данных переиндексированный индекс будет смещен, поэтому присваивайте только значения массива:
df1['Sex'] = df2.set_index('Name')['Sex'].reindex(df1['Name']).array
# Name Age Sex
# 0 Tom 34 M
# 1 Sara 18 NaN
# 2 Eva 44 F
# 3 Jack 27 M
# 4 Laura 30 NaN
Также я заметил распространенное предположение, что переиндексация выполняется медленно, но на самом деле это быстро (est):
Для заполнения недостающих значений
reindex
поддерживает автоматическое заполнение пропущенных значений:
fill_value
: статическая заменаmethod
: алгоритмическая замена (ffill
,bfill
илиnearest
) с заданным монотонным индексом
Например, для заполнения пустых Sex
значений с помощью Предпочитаю не говорить (PNS):
df2.set_index('Name')['Sex'].reindex(df1['Name'], fill_value='PNS')
# Name Age Sex
# 0 Tom 34 M
# 1 Sara 18 PNS
# 2 Eva 44 F
# 3 Jack 27 M
# 4 Laura 30 PNS
Переиндексация с помощью fill_value
выполняется быстрее, чем объединение в цепочку fillna
:
Для обработки дубликатов
Сопоставляющий фрейм данных ( df2
) не может иметь повторяющихся ключей, поэтому, drop_duplicates
если применимо:
df2.drop_duplicates('Name').set_index('Name')['Sex'].reindex(df1['Name'])
Данные синхронизации:
'''
Note: This is python code in a js snippet, so "run code snippet" will not work.
The snippet is just to avoid cluttering the main post with supplemental code.
'''
df1 = pd.DataFrame({'Name': np.arange(n), 'Age': np.random.randint(100, size=n)}).sample(frac=1).reset_index(drop=True)
df2 = pd.DataFrame({'Name': np.arange(n) int(n * 0.5), 'Sex': np.random.choice(list('MF'), size=n)}).sample(frac=1).reset_index(drop=True)
def reindex_(df1, df2):
df1['Sex'] = df2.set_index('Name')['Sex'].reindex(df1['Name']).array
return df1
def map_(df1, df2):
df1['Sex'] = df1['Name'].map(df2.set_index('Name')['Sex'])
return df1
def dict_(df1, df2):
df1['Sex'] = df1['Name'].map(dict(zip(df2['Name'], df2['Sex'])))
return df1
def merge_(df1, df2):
return df1.merge(df2[['Name', 'Sex']], left_on='Name', right_on='Name', how='left')
def join_(df1, df2):
return df1.set_index('Name').join(df2.set_index('Name'), how='left').reset_index()
reindex_fill_value_ = lambda df1, df2: df2.set_index('Name')['Sex'].reindex(df1['Name'], fill_value='PNTS')
reindex_fillna_ = lambda df1, df2: df2.set_index('Name')['Sex'].reindex(df1['Name']).fillna('PNTS')
map_fillna_ = lambda df1, df2: df1['Name'].map(df2.set_index('Name')['Sex']).fillna('PNTS')
Ответ №4:
Простое дополнение к ответу @jezrael для создания словаря из фрейма данных.
Это может быть полезно..
Python:
df1 = pd.DataFrame({'Name': ['Tom', 'Sara', 'Eva', 'Jack', 'Laura'],
'Age': [34, 18, 44, 27, 30]})
df2 = pd.DataFrame({'Name': ['Tom', 'Paul', 'Eva', 'Paul', 'Jack', 'Michelle', 'Tom'],
'Something': ['M', 'M', 'F', 'M', 'A', 'F', 'B']})
df1_dict = pd.Series(df1.Age.values, index=df1.Name).to_dict()
df2['Age'] = df2['Name'].map(df1_dict)
print(df2)
Вывод:
Name Something Age
0 Tom M 34.0
1 Paul M NaN
2 Eva F 44.0
3 Paul M NaN
4 Jack A 27.0
5 Michelle F NaN
6 Tom B 34.0