根据pandas中的另一个值更改一个值

Par*_*gue 81 python pandas

我正在尝试将我的Stata代码重新编程为Python以提高速度,我指出了PANDAS的方向.但是,我很难绕过如何处理数据.

假设我想迭代列标题'ID'中的所有值.如果该ID与特定数字匹配,那么我想更改两个对应的值FirstName和LastName.

在Stata中它看起来像这样:

replace FirstName = "Matt" if ID==103
replace LastName =  "Jones" if ID==103
Run Code Online (Sandbox Code Playgroud)

因此,这将FirstName中与ID == 103的值对应的所有值替换为Matt.

在PANDAS,我正在尝试这样的事情

df = read_csv("test.csv")
for i in df['ID']:
    if i ==103:
          ...
Run Code Online (Sandbox Code Playgroud)

不知道从哪里开始.有任何想法吗?

ely*_*ely 140

一种选择是使用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"
Run Code Online (Sandbox Code Playgroud)

如评论中所述,您还可以一次性对两个列进行分配:

df.loc[df.ID == 103, ['FirstName', 'LastName']] = 'Matt', 'Jones'
Run Code Online (Sandbox Code Playgroud)

请注意,您需要pandas0.11或更新版本来使用loc覆盖分配操作.


另一种方法是使用所谓的链式赋值.这种行为不太稳定,因此不被认为是最好的解决方案(在文档中明确表示不鼓励),但了解以下内容很有用:

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

  • 如何添加这种味道:`df.loc [df.ID == 103,['FirstName','LastName']] ='马特','琼斯' (15认同)
  • 因特网值得认真研究.无论如何,EMS,我很高兴知道该选项存在. (11认同)
  • 我不同意.我不明白为什么你坚持迂腐地试图断言链式作业不是一种可行的方法.我承认它不被认为是首选方式.你还想要什么?这样做是荒谬的,这不是一种*方式.事实上,在我的系统中(版本0.8),这是*正确的方法*.如果你打算担任这个职位,我对你的选票不感兴趣.请尽快通过downvote表示您的观点,但我已经反映了您的观点并且不同意它. (8认同)
  • -1"另一种方法是使用所谓的链式赋值." 不,没有.知道链式赋值不可靠只是*有用.这不是一个可靠的,非最佳的解决方案,[情况要糟糕得多](http://pandas.pydata.org/pandas-docs/dev/indexing.html#indexing-view-versus-copy).您甚至已经承认[Stack Overflow上的其他地方](http://stackoverflow.com/a/19125721/564538).请尽量避免给出链式分配是可行选项的错觉.您提供的前两种方法已经足够,并且是执行此操作的首选方法. (2认同)

Rut*_*ies 28

您可以使用map它,它可以映射来自dictonairy甚至自定义函数的值.

假设这是你的df:

    ID First_Name Last_Name
0  103          a         b
1  104          c         d
Run Code Online (Sandbox Code Playgroud)

创建dicts:

fnames = {103: "Matt", 104: "Mr"}
lnames = {103: "Jones", 104: "X"}
Run Code Online (Sandbox Code Playgroud)

并映射:

df['First_Name'] = df['ID'].map(fnames)
df['Last_Name'] = df['ID'].map(lnames)
Run Code Online (Sandbox Code Playgroud)

结果将是:

    ID First_Name Last_Name
0  103       Matt     Jones
1  104         Mr         X
Run Code Online (Sandbox Code Playgroud)

或使用自定义功能:

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

  • 如果你的dict中不存在这些值,这不会产生KeyError吗? (2认同)

Bil*_*ell 10

这个问题可能仍然经常被访问,因此值得为卡西斯先生的回答提供附录.可以对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         
Run Code Online (Sandbox Code Playgroud)

同样的事情可以通过以下方式更简单地完成.对getdict对象的方法使用'default'参数使得不必对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         
Run Code Online (Sandbox Code Playgroud)


mpr*_*iya 9

df['FirstName']=df['ID'].apply(lambda x: 'Matt' if x==103 else '')
df['LastName']=df['ID'].apply(lambda x: 'Jones' if x==103 else '')
Run Code Online (Sandbox Code Playgroud)

  • 社区鼓励对问题添加解释,而不是发布纯粹的代码答案(请参阅[此处](https://meta.stackoverflow.com/questions/300837/what-c​​omment-should-i-add-to-code-only-answers ))。 (2认同)

ccp*_*zza 8

原始问题涉及一个特定的狭义用例.对于那些需要更多通用答案的人,这里有一些例子:

使用其他列中的数据创建新列

鉴于以下数据框:

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
Run Code Online (Sandbox Code Playgroud)

下面我们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
Run Code Online (Sandbox Code Playgroud)

我们得到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
Run Code Online (Sandbox Code Playgroud)

使用条件修改多个列

更灵活的方法是调用.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
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,transform_row(r)函数接受一个Series表示给定行的对象(表示为axis=1,默认值axis=0将为Series每列提供一个对象).这简化了处理,因为我们可以使用列名访问行中的实际"原始"值,并且可以看到给定行/列中的其他单元格.