Изменение одного значения на основе другого значения в панд


Я пытаюсь перепрограммировать свой код Stata в Python для улучшения скорости, и мне указали в направлении панд. Тем не менее, мне трудно обернуть голову вокруг того, как обрабатывать данные.

допустим, я хочу перебрать все значения в заголовке столбца 'ID."Если этот идентификатор соответствует определенному номеру, то я хочу изменить два соответствующих значения FirstName и LastName.

в Stata это выглядит так:

replace FirstName = "Matt" if ID==103
replace LastName =  "Jones" if ID==103

Так это заменяет все значения в FirstName, которые соответствуют значениям ID == 103 на Matt.

в панд, я пытаюсь что-то вроде этого

df = read_csv("test.csv")
for i in df['ID']:
    if i ==103:
          ...

Не уверен, куда идти отсюда. Есть идеи?

4 52

4 ответа:

один из вариантов-использовать функции нарезки и индексирования Python для логической оценки мест, где ваше условие удерживает и перезаписывает данные там.

предполагая, что вы можете загрузить свои данные непосредственно в pandas С pandas.read_csv тогда следующий код может быть полезен для вас.

import pandas
df = pandas.read_csv("test.csv")
df.loc[df.ID == 103, 'FirstName'] = "Matt"
df.loc[df.ID == 103, 'LastName'] = "Jones"

как уже упоминалось в комментариях, вы также можете сделать назначение для обоих столбцов в одном кадре:

df.loc[df.ID == 103, ['FirstName', 'LastName']] = 'Matt', 'Jones'

обратите внимание, что вам понадобится pandas версия 0.11 или новее используйте loc для операций назначения перезаписи.


другой способ сделать это-использовать то, что называется цепным назначением. Поведение этого менее стабильно и поэтому не считается лучшим решением (это явно обескуражен в документах), но полезно знать о:

import pandas
df = pandas.read_csv("test.csv")
df['FirstName'][df.ID == 103] = "Matt"
df['LastName'][df.ID == 103] = "Jones"

можно использовать map, он может отображать валы из диктофона или даже пользовательской функции.

предположим, что это ваш df:

    ID First_Name Last_Name
0  103          a         b
1  104          c         d

создать предсказывает:

fnames = {103: "Matt", 104: "Mr"}
lnames = {103: "Jones", 104: "X"}

и карты

df['First_Name'] = df['ID'].map(fnames)
df['Last_Name'] = df['ID'].map(lnames)

результат будет такой:

    ID First_Name Last_Name
0  103       Matt     Jones
1  104         Mr         X

или использовать пользовательскую функцию:

names = {103: ("Matt", "Jones"), 104: ("Mr", "X")}
df['First_Name'] = df['ID'].map(lambda x: names[x][0])

этот вопрос все еще может быть посещен достаточно часто, что стоит предложить добавление к ответу г-на Кассиса. Элемент dict встроенный класс может быть подклассом, так что по умолчанию возвращается для "отсутствующих" ключей. Этот механизм хорошо работает для панд. но видите ниже.

таким образом можно избежать ключевых ошибок.

>>> import pandas as pd
>>> data = { 'ID': [ 101, 201, 301, 401 ] }
>>> df = pd.DataFrame(data)
>>> class SurnameMap(dict):
...     def __missing__(self, key):
...         return ''
...     
>>> surnamemap = SurnameMap()
>>> surnamemap[101] = 'Mohanty'
>>> surnamemap[301] = 'Drake'
>>> df['Surname'] = df['ID'].apply(lambda x: surnamemap[x])
>>> df
    ID  Surname
0  101  Mohanty
1  201         
2  301    Drake
3  401         

то же самое можно сделать более просто следующим образом. Использование аргумента по умолчанию для get метод объект dict делает ненужным подкласс dict.

>>> import pandas as pd
>>> data = { 'ID': [ 101, 201, 301, 401 ] }
>>> df = pd.DataFrame(data)
>>> surnamemap = {}
>>> surnamemap[101] = 'Mohanty'
>>> surnamemap[301] = 'Drake'
>>> df['Surname'] = df['ID'].apply(lambda x: surnamemap.get(x, ''))
>>> df
    ID  Surname
0  101  Mohanty
1  201         
2  301    Drake
3  401         

исходный вопрос относится к конкретному узкому варианту использования. Для тех, кому нужны более общие ответы вот несколько примеров:

создание нового столбца с использованием данных из других столбцов

учитывая фрейм данных ниже:

import pandas as pd
import numpy as np

df = pd.DataFrame([['dog', 'hound', 5],
                   ['cat', 'ragdoll', 1]],
                  columns=['animal', 'type', 'age'])

In[1]:
Out[1]:
  animal     type  age
----------------------
0    dog    hound    5
1    cat  ragdoll    1

ниже мы добавляем новые description столбец как объединение других столбцов с помощью + операция, которая переопределяется для серии. Необычное форматирование строк, f-строки и т. д. не будут работать здесь с + применяется к скалярам, а не к "примитивным" значениям:

df['description'] = 'A ' + df.age.astype(str) + ' years old ' \
                    + df.type + ' ' + df.animal

In [2]: df
Out[2]:
  animal     type  age                description
-------------------------------------------------
0    dog    hound    5    A 5 years old hound dog
1    cat  ragdoll    1  A 1 years old ragdoll cat

мы 1 years для кота (вместо 1 year) который мы будем фиксировать ниже с помощью условных обозначений.

изменение существующего столбца с условными обозначениями

здесь мы заменяем оригинал animal столбец со значениями других столбцов, и с помощью np.where для установки условной подстроки на основе значения age:

# append 's' to 'age' if it's greater than 1
df.animal = df.animal + ", " + df.type + ", " + \
    df.age.astype(str) + " year" + np.where(df.age > 1, 's', '')

In [3]: df
Out[3]:
                 animal     type  age
-------------------------------------
0   dog, hound, 5 years    hound    5
1  cat, ragdoll, 1 year  ragdoll    1

изменение нескольких столбцы с условными обозначениями

более гибкий подход заключается в вызове .apply() на весь фрейм данных, а не на один столбец:

def transform_row(r):
    r.animal = 'wild ' + r.type
    r.type = r.animal + ' creature'
    r.age = "{} year{}".format(r.age, r.age > 1 and 's' or '')
    return r

df.apply(transform_row, axis=1)

In[4]:
Out[4]:
         animal            type      age
----------------------------------------
0    wild hound    dog creature  5 years
1  wild ragdoll    cat creature   1 year

в коде выше