Как разбить строку pandas на несколько строк и обработать некоторые из их значений?

Я пытаюсь написать функцию, которая разбивает строку pandas на несколько строк и обновляет некоторые значения в определенном столбце.

Проблема будет выглядеть так;

   Id  Values
 0  A    2000
 1  B     600 

и ожидаемые результаты после разделения только тех Идентификаторы с Стоимость, превышающим 800, на меньшие количества. Это было бы;

  Id  Values
0  A     800
1  A     800
2  A     400
3  B     600 

Логика разделения значений не так актуальна. Например;

2000 = 800 + 800 + 400
2000 = 700 + 700 + 600

любые идеи о том, как решить эту проблему?

Вы пробовали групповое применение?

Nils Werner 28.05.2019 20:34

исходный фрейм данных имеет одиночные записи идентификаторов (не повторяющиеся значения). Я не вижу, как groupby.apply может мне помочь в этом случае :-/

Louiz Zanjroz 28.05.2019 20:44
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
132
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это быстрое решение должно дать требуемые результаты, код еще нуждается в оптимизации

max_val = 800

def split_x (x):
  lst=[]
  while x > max_val:
    x=x-max_val
    lst.append(max_val)
  if x != 0:
    lst.append(x)
  return lst

data = {'id':['A', 'B'],
        'value':[2000,600]}
df = pd.DataFrame(data)
df_new=pd.DataFrame({'id':[],'value':[]})

for i in range(len(df)):

  d=df.loc[i]['value']
  id=df.loc[i]['id']
  s=split_x(d)
  for i in range(len(s)):
    print (i,s[i])
    df_new=df_new.append({'id':id,'value':s[i]},ignore_index=True)

>>> df_new
  id  value
0  A  800.0
1  A  800.0
2  A  400.0
3  B  600.0
d=df.loc[i]['value'] обязательно должно быть d=df.loc[i, 'value']?
Dan 28.05.2019 22:28

@Dan оба результата одинаковы

Feras 28.05.2019 23:19

да, но один из них - канонические панды, другой - просто следствие того, что ваш первый фрагмент также возвращает фрейм данных. Используйте запятую.

Dan 29.05.2019 10:37
Ответ принят как подходящий

Определите функцию, которая будет применяться к каждой строке:

def fn2(val, maxVal):
    tbl = []
    v1 = val // maxVal
    v2 = val % maxVal
    if v1:
        tbl.extend([maxVal] * v1)
    if v2:
        tbl.append(v2)
    return pd.Series(tbl)

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

И фактическая обработка может быть выполнена в одном (хотя и связанном) инструкция:

df.set_index('Id').Values.apply(fn2, maxVal=800).stack()\
    .rename('Values').astype(int)\
    .reset_index(level=1, drop=True).reset_index()

Обратите внимание, что перед куча некоторые значения равны NaN, поэтому тип был изменен до плавать. Чтобы изменить его обратно на инт, я добавил тип (целое число).

Для ваших выборочных данных результат:

  Id Values
0  A    800
1  A    800
2  A    400
3  B    600

Изменить после вашего комментария

Если у вас есть единственный другой столбец, вы можете "разделить" Значения на куски почти как вы предложили:

df.set_index(['Id', 'AnotherCol']).Values.apply(fn2, maxVal=800)\
    .stack().rename('Values').astype(int)\
    .reset_index(level=2, drop=True).reset_index()

Отличие от вашего предложения в том, что уровень индекса, который нужно сбросить, равен 2. (не 0).

Но если у вас есть более таких «дополнительных» столбцов, более естественным кажется:

  • Рассчитайте Ряд "разделенного Значения" (я назвал его вальс), с индексом, взятым из исходного столбца Id.
  • Удалите «исходный» столбец Значения из дф.
  • Объедините его с вальс. Ключи слияния:
    • для дф - Id,
    • для вальс - индекс.

Итак, код:

vals = df.set_index(['Id']).Values.apply(fn2, maxVal=800)\
    .stack().rename('Values').astype(int)\
    .reset_index(level=1, drop=True)
pd.merge(df.drop(columns=['Values']), vals,
    left_on='Id', right_index=True)

Если вы недовольны повторяющимися значениями индекса, добавьте .reset_index(drop=True) до последней инструкции.

Спасибо за это отличное решение. В моем исходном df больше столбцов anotherCol, поэтому я могу предположить, что продолжение инструкции по цепочке будет таким: df.set_index(['Id','anotherCol']).Values.apply(fn2,maxVal=80‌​0).stack().rename('V‌​alues').astype(int).‌​reset_index(level=0, drop=True).reset_index().drop(['level_1'], axis=1) @Valdi_Bo, вы бы сделали это по-другому?

Louiz Zanjroz 29.05.2019 14:09

просто воспроизвел вашу альтернативу, это было очень полезно увидеть. Я узнал одну или две вещи из этого... Спасибо. На вашем последнем шаге мне пришлось преобразовать series в df перед слиянием: pd.merge(df.drop(columns=['Values']), vals.to_frame(), left_on='Id', right_index=True)

Louiz Zanjroz 30.05.2019 14:47

Другие вопросы по теме