Pandas создать новый столбец со значениями из других столбцов, выбранных на основе значения столбца - PullRequest
2 голосов
/ 20 апреля 2020

У меня есть датафрейм, похожий на этот пример. По некоторым причинам необработанные данные имеют значение, реплицированное по всему.

  Node Node 1 Value Node 2 Value Node 3 Value
0    1            A            B            C
1    2            A            B            C
2    3            A            B            C

Я хочу преобразовать его так, чтобы это выглядело так:

  Node Value
0    1     A
1    2     B
2    3     C

Этот код iterrows работает, как задумано, но это очень медленно для моих данных (48 узлов с ~ 20 000 значений).

Я чувствую, что должен быть более быстрый путь, возможно, с apply, но я не могу понять это.

import pandas as pd

df = pd.DataFrame({"Node": ["1", "2", "3"],
                   "Node 1 Value": ["A","A","A"],
                   "Node 2 Value": ["B","B","B"],
                   "Node 3 Value": ["C","C","C"]})

print(df)

for index, row in df.iterrows():
    df.loc[index, 'Value'] = row["Node {} Value".format(row['Node'])]

print(df[['Node','Value']])

1 Ответ

2 голосов
/ 20 апреля 2020

Используйте DataFrame.lookup, а затем DataFrame.assign:

a = df.lookup(df.index, "Node " + df.Node.astype(str) + " Value")

df = df[['Node']].assign(Value = a)
print (df)
   Node Value
0     1     A
1     2     B
2     3     C

РЕДАКТИРОВАТЬ: Если некоторые значения отсутствуют, вы можете извлечь эти значения с помощью numpy.setdiff1d для словаря со значением по умолчанию, например, np.nan и добавление в DataFrame до lookup:

print (df)
   Node Node 1 Value Node 2 Value Node 3 Value
0     1            A            B            C
1     2            A            B            C
3     5            A            B            C

s = "Node " + df.Node.astype(str) + " Value"
new = dict.fromkeys(np.setdiff1d(s, df.columns), np.nan)
print (new)
{'Node 5 Value': nan}

print (df.assign(**new))
   Node Node 1 Value Node 2 Value Node 3 Value  Node 5 Value
0     1            A            B            C           NaN
1     2            A            B            C           NaN
3     5            A            B            C           NaN

a = df.assign(**new).lookup(df.index, s)
print (a)
['A' 'B' nan]

df = df[['Node']].assign(Value = a)
print (df)
   Node Value
0     1     A
1     2     B
3     5   NaN

Другая идея с определением поиска :

def f(row, col):
    try:
        return df.at[row, col]
    except:
        return np.nan

s = "Node " + df.Node.astype(str) + " Value"
a = [f(row, col) for row, col in zip(df.index, s)]

df = df[['Node']].assign(Value = a)
print (df)
   Node Value
0     1     A
1     2     B
3     5   NaN

И раствор с DataFrame.melt:

s = "Node " + df.Node.astype(str) + " Value"
b = (df.assign(Node = s)
        .reset_index()
        .melt(['index','Node'], value_name='Value')
        .query('Node == variable').set_index('index')['Value'])


df = df[['Node']].join(b)
print (df)
   Node Value
0     1     A
1     2     B
3     5   NaN
...