Вычисления с использованием элементов смешанного типа в столбцах - np.nan, float, string elements - PullRequest
0 голосов
/ 20 февраля 2020

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

A=[20, np.nan, 10, 'give', np.nan, np.nan]
B=[10, np.nan, np.nan, np.nan, 10, 'given']

frame=pd.DataFrame(zip(A,B))
frame.columns=['A', 'B']

Я хочу заполнить разницу B от A. Если я сделаю frame['diff']=frame['A']-frame['B'], это не даст нужного мне результата. Вместо этого я хотел бы получить результат в столбце «требуемая разница».

По сути, если A или B имеет число, то B или A должны быть 0. Если строка находится в A, а B - NaN, тогда он должен написать «положительный» и, наоборот, он должен написать «отрицательный». См. Ниже:

frame
      A      B  diff  desired diff
0    20     10    10            10
1   NaN    NaN   NaN           NaN
2    10    NaN   NaN            10
3  give    NaN   NaN      positive
4   NaN     10   NaN           -10
5   NaN  given   NaN      negative

Просто для записи, я попытался реализовать np.where и np.select и некоторые условия, такие как np.logical_and(frame['A'].apply(lambda x: isinstance(x, float)), frame['B'].isna()), для достижения желаемого результата, но безуспешно.

Заранее спасибо за ваши предложения!

Ответы [ 2 ]

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

Используйте to_numeric с errors='coerce' для проверки без нумерации c и без пропущенных значений и установите новые значения с помощью numpy.select и вычтите значения с помощью Series.sub с параметром fill_value=0:

a = pd.to_numeric(frame['A'], errors='coerce')
m1 = frame['A'].notna()
m2 = a.isna()

b = pd.to_numeric(frame['B'], errors='coerce')
m3 = frame['B'].notna()
m4 = b.isna()

frame['new'] = np.select([m1 & m2, m3 & m4], 
                         ['positive', 'negative'], 
                         default = a.sub(b, fill_value=0))
print (frame)
      A      B       new
0    20     10      10.0
1   NaN    NaN       nan
2    10    NaN      10.0
3  give    NaN  positive
4   NaN     10     -10.0
5   NaN  given  negative
0 голосов
/ 20 февраля 2020

Если вы хотите использовать длинную заявку, которую я бы не рекомендовал:

frame['diff'] = (frame.fillna(0)
                 .apply(lambda x: x.A-x.B if (isinstance(x.A, (int, float)) & isinstance(x.B, (int, float)))
                        else ('positive' if (isinstance(x.A, str) & (x.B == 0)) else 'negative'),
                        axis=1)
                 .replace(0, np.nan))

      A      B      diff
0    20     10        10
1   NaN    NaN       NaN
2    10    NaN        10
3  give    NaN  positive
4   NaN     10       -10
5   NaN  given  negative
...