根据特定标准修改多行

时间:2015-07-01 21:04:41

标签: python csv pandas

我有一个csv文件,如下所示:

ID         Class      Status    Species
1          Sands        D        Carex
1          Sands        C        Eupesu
1          Sands        C        Poapra
2          Limy         D        Carcra
2          Limy         C        Eupesu
2          Limy         C        Poapra
3          Limy         D        Poapra
3          Limy         C        Eupesu
3          Limy         C        Poapra

StatusDSpecies为Carex或Carcra时,我想将Class更改为Wet以获取特定ID中的所有值。我想要的输出是:

ID         Class     Status    Species
1          Wet         D        Carex
1          Wet         C        Eupesu
1          Wet         C        Poapra
2          Wet         D        Carcra
2          Wet         C        Eupesu
2          Wet         C        Poapra
3          Limy        D        Poapra
3          Limy        C        Eupesu
3          Limy        C        Poapra

3 个答案:

答案 0 :(得分:3)

import pandas as pd
df = pd.read_table('data', sep='\s+')
mask = ((df['Status'] == 'D') 
        & df['Species'].isin(['Carex','Carcra']))
mask = mask.groupby(df['ID']).transform('any')
df.loc[mask, 'Class'] = 'Wet'
print(df)

产量

   ID Class Status Species
0   1   Wet      D   Carex
1   1   Wet      C  Eupesu
2   1   Wet      C  Poapra
3   2   Wet      D  Carcra
4   2   Wet      C  Eupesu
5   2   Wet      C  Poapra
6   3  Limy      D  Poapra
7   3  Limy      C  Eupesu
8   3  Limy      C  Poapra

作业

df['mask'] = ((df['Status'] == 'D') 
        & df['Species'].isin(['Carex','Carcra']))

使df看起来像这样:

In [166]: df
Out[166]: 
   ID  Class Status Species   mask
0   1  Sands      D   Carex   True
1   1  Sands      C  Eupesu  False
2   1  Sands      C  Poapra  False
3   2   Limy      D  Carcra   True
4   2   Limy      C  Eupesu  False
5   2   Limy      C  Poapra  False
6   3   Limy      D  Poapra  False
7   3   Limy      C  Eupesu  False
8   3   Limy      C  Poapra  False

现在,(感谢DSM):

mask = ((df['Status'] == 'D') 
        & df['Species'].isin(['Carex','Carcra']))
mask = mask.groupby(df['ID']).transform('any')

mask分组df['ID'],如果原始True中的任何值为True,则将mask分配给该组的所有行,和False否则。

In [168]: mask
Out[168]: 
0     True
1     True
2     True
3     True
4     True
5     True
6    False
7    False
8    False
dtype: bool

df.loc可用于从df中选择行和列。 df.loc[mask]选择mask为True的行:

In [169]: df.loc[mask]
Out[169]: 
   ID  Class Status Species   mask
0   1  Sands      D   Carex   True
1   1  Sands      C  Eupesu  False
2   1  Sands      C  Poapra  False
3   2   Limy      D  Carcra   True
4   2   Limy      C  Eupesu  False
5   2   Limy      C  Poapra  False

df.loc[mask, 'Class']进一步选择列Class

In [170]: df.loc[mask, 'Class']
Out[170]: 
0    Sands
1    Sands
2    Sands
3     Limy
4     Limy
5     Limy
Name: Class, dtype: object

df.loc[mask]['Class'] = value可能无法修改df,因为df.loc[mask]会返回副本。 (df[mask]['Class'] = value)也是如此。使用[...]两次被称为"链式索引"如果我们避免链式索引,就可以避免这个问题。

因此,不要使用[...]两次,而是使用df.loc[mask, 'Class'] = 'Wet'

In [172]: df
Out[172]: 
   ID Class Status Species
0   1   Wet      D   Carex
1   1   Wet      C  Eupesu
2   1   Wet      C  Poapra
3   2   Wet      D  Carcra
4   2   Wet      C  Eupesu
5   2   Wet      C  Poapra
6   3  Limy      D  Poapra
7   3  Limy      C  Eupesu
8   3  Limy      C  Poapra

答案 1 :(得分:0)

您标记了pandas,因此我假设您可以将其作为数据框导入。

如果是这样,我认为您正在寻找类似的东西:

df[(df.Status=='D') & (df.Species=='CareX' | df.Species=='Carcra') & (df.ID== 1)]['Class'] = 'Wet'

答案 2 :(得分:0)

嗯,这个答案可能效率低下,因为它会将文件中的所有行都记录下来。为了仅编辑文件的那一部分,我稍后会查看并编辑此答案。但是现在,如果你有一个不超过的文件,我不知道,50mb ?,只需使用它。

lines = []
theID = 1
for line in open("file.csv", "r"):
    row = line.split(",")
    if row[2] == "D":
        if row[3] == "Carex" or row[3] == "Carcra":
            if theID == row[0]:
                row[1] = "Wet"
    lines.append(",".join(row))

open("file.csv", "w").writelines(lines)

请在运行之前请备份您的实际文件,因为它可能会弄乱整个事情。 (未测试)