根据特定列中的值更改pandas数据框中的值

问题描述 投票:1回答:2

如何将第一个数据帧转换为下面的数据帧?根据前三列匹配的不同场景,我想更改其余列中的值。

import pandas as pd

df = pd.DataFrame([['foo', 'foo', 'bar', 'a', 'b', 'c', 'd'], ['bar', 'foo', 'bar', 'a', 'b', 'c', 'd'], 
                   ['spa', 'foo', 'bar', 'a', 'b', 'c', 'd']], columns=['col1', 'col2', 'col3', 's1', 's2', 's3', 's4'])

  col1 col2 col3 s1 s2 s3 s4
0  foo  foo  bar  a  b  c  d
1  bar  foo  bar  a  b  c  d
2  spa  foo  bar  a  b  c  d

如果col1 = col2,我想将所有的a更改为2,将所有b和c更改为1,将所有d更改为0.这是我的示例df中的第1行。

如果col1 = col3,我想将所有的a更改为0,将所有b和c更改为1,将所有d更改为2.这是我的示例df中的第2行。

如果col1!= col2 / col3,我想删除该行并将1加到计数器中,所以我总共删除了一行。这是我的示例df中的第3行。

所以我的最终数据框看起来像这样,counter = 1:

df = pd.DataFrame([['foo', 'foo', 'bar', '2', '1', '1', '0'], ['bar', 'foo', 'bar', '0', '1', '1', '2']], 
                   columns=['col1', 'col2', 'col3', 's1', 's2', 's3', 's4'])

  col1 col2 col3 s1 s2 s3 s4
0  foo  foo  bar  2  1  1  0
1  bar  foo  bar  0  1  1  2

我正在阅读使用df.iterrows很慢,所以必须有一种方法可以在整个df上同时执行此操作,但我最初的想法是:

for row in df.iterrows:
    if (row["col1"] == row["col2"]):
        df.replace(to_replace=['a'], value='2', inplace=True)
        df.replace(to_replace=['b', 'c'], value='1', inplace=True)
        df.replace(to_replace=['d'], value='0', inplace=True)
    elif (row["col1"] == row["col3"]):
        df.replace(to_replace=['a'], value='0', inplace=True)
        df.replace(to_replace=['b', 'c'], value='1', inplace=True)
        df.replace(to_replace=['d'], value='2', inplace=True)
    else:
        (delete row, add 1 to counter)

原来的df是巨大的,所以速度对我来说很重要。我希望能够在没有iterrows的情况下对整个数据帧进行转换。即使它不可能,我也可以使用帮助来获取iterrows的语法。

python-3.x pandas dataframe
2个回答
0
投票

您可以先通过boolean indexing删除行:

m1 = df["col1"] == df["col2"]
m2 = df["col1"] == df["col3"]
m = m1 | m2

通过summ1m2~获取删除的行数:

counter = (~m).sum()
print (counter)
1
df = df[m].copy()
print (df)
  col1 col2 col3 s1 s2 s3 s4
0  foo  foo  bar  a  b  c  d
1  bar  foo  bar  a  b  c  d

然后replacedictionary条件:

d1 = {'a':2,'b':1,'c':1,'d':0}
d2 = {'a':0,'b':1,'c':1,'d':2}

m1 = df["col1"] == df["col2"]
#replace all columns without col1-col3
cols = df.columns.difference(['col1','col2','col3'])
df.loc[m1, cols] = df.loc[m1, cols].replace(d1)
df.loc[~m1, cols] = df.loc[~m1, cols].replace(d2)
print (df)
  col1 col2 col3 s1 s2 s3 s4
0  foo  foo  bar  2  1  1  0
1  bar  foo  bar  0  1  1  2

时序:

In [138]: %timeit (jez(df))
872 ms ± 6.94 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [139]: %timeit (hb(df))
1.33 s ± 9.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

建立:

np.random.seed(456) 

a = ['foo','bar', 'spa']
b = list('abcd')

N = 100000
df1 = pd.DataFrame(np.random.choice(a, size=(N, 3))).rename(columns=lambda x: 'col{}'.format(x+1))
df2 = pd.DataFrame(np.random.choice(b, size=(N, 20))).rename(columns=lambda x: 's{}'.format(x+1))
df = df1.join(df2)
#print (df.head())

def jez(df):
    m1 = df["col1"] == df["col2"]
    m2 = df["col1"] == df["col3"]
    m = m1 | m2
    counter = (~m).sum()
    df = df[m].copy()

    d1 = {'a':2,'b':1,'c':1,'d':0}
    d2 = {'a':0,'b':1,'c':1,'d':2}

    m1 = df["col1"] == df["col2"]
    cols = df.columns.difference(['col1','col2','col3'])
    df.loc[m1, cols] = df.loc[m1, cols].replace(d1)
    df.loc[~m1, cols] = df.loc[~m1, cols].replace(d2)
    return df

def hb(df):
    counter = 0
    df[df.col1 == df.col2] = df[df.col1 == df.col2].replace(['a', 'b', 'c', 'd'], [2,1,1,0])
    df[df.col1 == df.col3] = df[df.col1 == df.col3].replace(['a', 'b', 'c', 'd'], [0,1,1,2])
    index_drop =df[((df.col1 != df.col3) & (df.col1 != df.col2))].index
    counter = counter + len(index_drop)
    df = df.drop(index_drop)
    return df

0
投票

您可以使用:

import pandas as pd
df = pd.DataFrame([['foo', 'foo', 'bar', 'a', 'b', 'c', 'd'], ['bar', 'foo', 'bar', 'a', 'b', 'c', 'd'], 
               ['spa', 'foo', 'bar', 'a', 'b', 'c', 'd']], columns=['col1', 'col2', 'col3', 's1', 's2', 's3', 's4'])
counter = 0

#
df[df.col1 == df.col2] = df[df.col1 == df.col2].replace(['a', 'b', 'c', 'd'], [2,1,1,0])
df[df.col1 == df.col3] = df[df.col1 == df.col3].replace(['a', 'b', 'c', 'd'], [0,1,1,2])
index_drop =df[((df.col1 != df.col3) & (df.col1 != df.col2))].index
counter = counter + len(index_drop)
df = df.drop(index_drop)

print(df)
print(counter)

输出:

    col1    col2    col3    s1  s2  s3  s4
0   foo     foo      bar    2   1   1   0
1   bar     foo      bar    0   1   1   2

1  # counter
© www.soinside.com 2019 - 2024. All rights reserved.