Есть ли более читаемый способ для каменноугольных колонн в pandas
Мне часто нужен новый столбец, который я могу достичь из других столбцов, и у меня есть определенный список приоритетов предпочтений. Я готов принять первое ненулевое значение.
def coalesce(values):
not_none = (el for el in values if el is not None)
return next(not_none, None)
df = pd.DataFrame([{'third':'B','first':'A','second':'C'},
{'third':'B','first':None,'second':'C'},
{'third':'B','first':None,'second':None},
{'third':None,'first':None,'second':None},
{'third':'B','first':'A','second':None}])
df['combo1'] = df.apply(coalesce, axis=1)
df['combo2'] = df[['second','third','first']].apply(coalesce, axis=1)
print df
Результаты
first second third combo1 combo2
0 A C B A C
1 None C B C C
2 None None B B B
3 None None None None None
4 A None B A B
этот код работает (и результат - это то, что я хочу), но это не очень быстро.
Я хочу выбрать приоритеты, если мне нужно [['second', 'third', 'first']]
Совместите несколько подобно функции с тем же именем из tsql.
Я подозреваю, что я, возможно, пропустил простой способ добиться этого с хорошей производительностью на больших DataFrames (+400 000 строк)
Я знаю, что есть много способов заполнить недостающие данные, которые я часто использую на оси = 0
это то, что заставляет меня думать, что я, возможно, пропустил простой вариант для оси = 1
Можете ли вы предложить что-то приятнее/быстрее... или подтвердите, что это так хорошо, как оно есть.
Ответы
Ответ 1
Вы можете использовать pd.isnull
, чтобы найти нуль - в этом случае None
- значения:
In [169]: pd.isnull(df)
Out[169]:
first second third
0 False False False
1 True False False
2 True True False
3 True True True
4 False True False
а затем используйте np.argmin
, чтобы найти индекс первого непустого значения. Если все значения равны нулю, np.argmin
возвращает 0:
In [186]: np.argmin(pd.isnull(df).values, axis=1)
Out[186]: array([0, 1, 2, 0, 0])
Затем вы можете выбрать желаемые значения из df
, используя NumPy integer-indexing:
In [193]: df.values[np.arange(len(df)), np.argmin(pd.isnull(df).values, axis=1)]
Out[193]: array(['A', 'C', 'B', None, 'A'], dtype=object)
Например,
import pandas as pd
df = pd.DataFrame([{'third':'B','first':'A','second':'C'},
{'third':'B','first':None,'second':'C'},
{'third':'B','first':None,'second':None},
{'third':None,'first':None,'second':None},
{'third':'B','first':'A','second':None}])
mask = pd.isnull(df).values
df['combo1'] = df.values[np.arange(len(df)), np.argmin(mask, axis=1)]
order = np.array([1,2,0])
mask = mask[:, order]
df['combo2'] = df.values[np.arange(len(df)), order[np.argmin(mask, axis=1)]]
дает
first second third combo1 combo2
0 A C B A C
1 None C B C C
2 None None B B B
3 None None None None None
4 A None B A B
Использование argmin вместо df3.apply(coalesce, ...)
значительно быстрее, если в DataFrame много строк:
df2 = pd.concat([df]*1000)
In [230]: %timeit mask = pd.isnull(df2).values; df2.values[np.arange(len(df2)), np.argmin(mask, axis=1)]
1000 loops, best of 3: 617 µs per loop
In [231]: %timeit df2.apply(coalesce, axis=1)
10 loops, best of 3: 84.1 ms per loop
Ответ 2
Pandas эквивалент COALESCE
- это метод fillna()
:
result = column_a.fillna(column_b)
Результатом является столбец, в котором каждое значение берется из column_a
, если этот столбец предоставляет ненулевое значение, в противном случае значение берется из column_b
. Таким образом, ваш combo1
можно создать с помощью
df['first'].fillna(df['second']).fillna(df['third'])
даяние:
0 A
1 C
2 B
3 None
4 A
И ваш combo2
может быть создан с помощью:
(df['second']).fillna(df['third']).fillna(df['first'])
который возвращает новый столбец:
0 C
1 C
2 B
3 None
4 B
Если вам нужна эффективная операция под названием COALESCE
, она может просто объединить столбцы с fillna()
слева направо и затем вернуть результат:
def coalesce(df, column_names):
i = iter(column_names)
column_name = next(i)
answer = df[column_name]
for column_name in i:
answer = answer.fillna(df[column_name])
return answer
print coalesce(df, ['first', 'second', 'third'])
print coalesce(df, ['second', 'third', 'first'])
который дает:
0 A
1 C
2 B
3 None
4 A
0 C
1 C
2 B
3 None
4 B