#python #dataframe
#python #фрейм данных
Вопрос:
У меня есть фрейм данных, и я хочу создать новый столбец на основе других строк фрейма данных. Мой фрейм данных выглядит так
MitarbeiterID ProjektID Jahr Monat Week mean freq last
0 583 83224 2020 1 2 3.875 4 0
1 373 17364 2020 1 3 5.00 0 4
2 923 19234 2020 1 4 5.00 3 3
3 643 17364 2020 1 3 4.00 2 2
Теперь я хочу проверить, равна ли частота строки нулю, тогда я проверю, есть ли другая строка с тем же идентификатором проекта и годом недели, где частота не равна 0. Если это правда, я хочу новый столбец «other», который имеет значение 1 и 0 else.
Итак, вывод должен быть
MitarbeiterID ProjektID Jahr Monat Week mean freq last other
0 583 83224 2020 1 2 3.875 4 0 0
1 373 17364 2020 1 3 5.00 0 4 1
2 923 19234 2020 1 4 5.00 3 3 0
3 643 17364 2020 1 3 4.00 2 2 0
На этот раз у меня нет подхода, кто-нибудь может помочь?
Спасибо!
Комментарии:
1. Почему
other
в строке3
0, а не 1?2. @Timus Я не уверен, что OP мог бы уточнить, но мне кажется, что это продиктовано столбцом freq, так как в строке 3 freq не равен 0, я думаю, OP хочет пометить other как 1, где freq равно 0??
3. @Timus Да, потому что частота в строке 3 равна 3, а не 0
Ответ №1:
Следующее решение проверяет, выполняются ли требуемые условия.
import io
import pandas as pd
Данные
df = pd.read_csv(io.StringIO("""
MitarbeiterID ProjektID Jahr Monat Week mean freq last
0 583 83224 2020 1 2 3.875 4 0
1 373 17364 2020 1 3 5.00 0 4
2 923 19234 2020 1 4 5.00 3 3
3 643 17364 2020 1 3 4.00 2 2
"""), sep="ss ", engine="python")
Создайте столбец other
со всеми нулевыми значениями.
df['other'] = 0
Если ProjektID, Jahr, Week дублируются, и любое из значений Freq больше нуля, то дублирующиеся строки (keep=False, чтобы также захватить исходную дублированную строку) и где Freq равно нулю, будут иметь значение Other, заполненное 1. Измените any()
на all()
, если вам нужно, чтобы все значения были больше нуля.
if (df.loc[df[['ProjektID','Jahr', 'Week']].duplicated(), 'freq'] > 0).any(): df.loc[(df[['ProjektID','Jahr', 'Week']].duplicated(keep=False)) amp; (df['freq'] == 0), ['other']] = 1
else: print("Other stays zero")
Вывод:
Ответ №2:
Я думаю, что лучший способ решить эту проблему — не использовать pandas слишком часто 🙂 преобразование объектов в наборы и кортежи должно сделать это достаточно быстро.
Идея состоит в том, чтобы составить словарь всех троек (ProjektID, Jahr, Week)
, которые появляются в наборе freq != 0
данных, а затем проверить все строки с freq == 0
помощью, принадлежит ли их тройка этому словарю или нет. В коде я создаю фиктивный набор данных с помощью:
x = pd.DataFrame(np.random.randint(0, 2, (8, 4)), columns=['id', 'year', 'week', 'freq'])
который в моем случае случайным образом дал:
>>> x
id year week freq
0 1 0 0 0
1 0 0 0 1
2 0 1 0 1
3 0 0 1 0
4 0 1 0 0
5 1 0 0 1
6 0 0 1 1
7 0 1 1 0
Теперь нам нужны тройки только там, где freq != 0
, поэтому мы используем
x1 = x.loc[x['freq'] != 0]
triplets = {tuple(row) for row in x1[['id', 'year', 'week']].values}
Обратите внимание, что я использую x1.values
, который является не фреймом данных pandas, а скорее массивом numpy; так что каждая строка в нем теперь может быть преобразована в кортеж. Это необходимо, потому что строки фрейма данных или даже numpy-массив или списки являются изменяемыми объектами и в противном случае не могут быть хэшированы в словаре. Использование набора вместо, например, списка (который не имеет этого ограничения) предназначено для повышения эффективности.
Далее мы определяем логическую переменную, которая имеет значение True, если триплет (идентификатор, год, неделя) принадлежит к вышеуказанному набору:
belongs = x[['id', 'year', 'week']].apply(lambda x: tuple(x) in triplets, axis=1)
Мы в основном закончили, это еще один нужный вам столбец, за исключением того, что также необходимо принудительно использовать freq == 0:
x['other'] = np.logical_and(belongs, x['freq'] == 0).astype(int)
(в конечном .astype(int)
итоге он должен иметь значения 0 и 1, как вы просили, вместо False и True). Конечный результат в моем случае:
>>> x
id year week freq other
0 1 0 0 0 1
1 0 0 0 1 0
2 0 1 0 1 0
3 0 0 1 0 1
4 0 1 0 0 1
5 1 0 0 1 0
6 0 0 1 1 0
7 0 1 1 0 0
Комментарии:
1. Спасибо! Я думаю, что есть что-то, что исключает само себя. Я только что получил нули в своем столбце other, поэтому никогда не бывает freq = 0 и belongs=True . Я пробовал другие случаи, которые подтверждают это. Но я не понимаю..
Ответ №3:
Похоже, я опоздал…:
df.set_index(['ProjektID', 'Jahr', 'Week'], drop=True, inplace=True)
df['other'] = 0
df.other.mask(df.freq == 0,
df.freq[df.freq == 0].index.isin(df.freq[df.freq != 0].index),
inplace=True)
df.other = df.other.astype('int')
df.reset_index(drop=False, inplace=True)
Комментарии:
1. В SO никогда не бывает слишком поздно. Хорошее решение!