Добавление двух столбцов в Dask с помощью функции apply

#python #pandas #dask

Вопрос:

У меня есть функция Dask, которая добавляет столбец в существующий фрейм данных Dask, это отлично работает:

 df = pd.DataFrame({
    'height':  [6.21, 5.12, 5.85, 5.78, 5.98],
    'weight': [150, 126, 133, 164, 203]
})

df_dask = dd.from_pandas(df, npartitions=2) 


s = """
obj.weight   100
"""

df_dask['new_weight'] = df_dask.apply(lambda obj: eval(s), meta=dict, axis=1)
 

Теперь я хочу добавить две колонки вместо одной:

 s = """
obj.weight   100, obj.weight   200
"""

df_dask['new_weight','new_weight2'] = df_dask.apply(lambda obj: eval(s), meta=dict, axis=1)
 

Но я понимаю

 NotImplementedError: Item assignment with <class 'tuple'> not supported
 

Означает ли это, что это не поддерживается или я делаю что-то не так? Если не поддерживается, есть ли обходной путь? Что мне нужно, так это вернуть список поплавков.

Ответ №1:

Во-первых, будет полезно убедиться, что решение на pandas основе обеспечивает ожидаемый результат:

 df = pd.DataFrame({
    'height':  [6.21, 5.12, 5.85, 5.78, 5.98],
    'weight': [150, 126, 133, 164, 203]
})

s = """
obj.weight   100, obj.weight   200
"""

df['new_weight'], df['new_weight2'] = zip(*df.apply(lambda obj: eval(s), axis=1))

print(df)
#    height  weight  new_weight  new_weight2
# 0    6.21     150       250.0        350.0
# 1    5.12     126       226.0        326.0
# 2    5.85     133       233.0        333.0
# 3    5.78     164       264.0        364.0
# 4    5.98     203       303.0        403.0
 

Теперь перейдем к dask решению. Поскольку каждый раздел представляет pandas собой фрейм данных, самое простое решение (для преобразований на основе строк)-это обернуть pandas код в функцию и подключить его к map_partitions :

 df = pd.DataFrame({
    'height':  [6.21, 5.12, 5.85, 5.78, 5.98],
    'weight': [150, 126, 133, 164, 203]
})

s = """
obj.weight   100, obj.weight   200
"""

df_dask = dd.from_pandas(df, npartitions=2) 

def new_cols(df):
    df = df.copy()
    df['new_weight'], df['new_weight2'] = zip(*df.apply(lambda obj: eval(s), axis=1))
    return df

df_dask = df_dask.map_partitions(new_cols)

print(df_dask.compute())
#    height  weight  new_weight  new_weight2
# 0    6.21     150       250.0        350.0
# 1    5.12     126       226.0        326.0
# 2    5.85     133       233.0        333.0
# 3    5.78     164       264.0        364.0
# 4    5.98     203       303.0        403.0
 

Приведенный выше шаблон может иметь возможности для повышения эффективности в зависимости от особенностей вашего варианта использования.

Комментарии:

1. Султан, в моем случае apply это не удается, потому meta что не определено. Предполагая, что все возвращаемые типы являются плавающими, что было бы связано meta ? Metadata inference failed in new_cols. You have supplied a custom function and Dask is unable to determine the type of output that that function returns. To resolve this please provide a meta= keyword.

2. К сожалению, мы не можем знать этого, не увидев ваш фактический код. Мета должна быть нулевым или однострочным фреймом данных с той же структурой, что и выходные apply данные . Обратите внимание, что в решении @Sultanorazbaev не используется Dask apply.