В моем DataFrame я хочу обрезать значение определенного столбца от 0 до 100. Например, учитывая следующее:

  a  b
0 10 90
1 20 150
2 30 -30

Я хочу получить:

  a  b   c
0 10 90  90
1 20 150 100
2 30 -30 0

Я знаю, что в Pandas определенные арифметические операции работают через столбцы. Например, я мог бы удвоить каждое число в столбце b следующим образом:

>>>df["c"] = df["b"] * 2
>>>df
  a  b   c
0 10 90  180
1 20 150 300
2 30 -30 -60

Однако это не работает для встроенных функций, таких как min и max:

>>>df["c"] = min(100, max(0, df["b"]))
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Есть ли какой-нибудь способ добиться того, чего я хочу эффективно?

7
stevendesu 30 Авг 2017 в 20:30

3 ответа

Лучший ответ

Вы можете использовать Series.clip:

df['c'] = df['b'].clip(0,100)
print (df)
    a    b    c
0  10   90   90
1  20  150  100
2  30  -30    0
9
jezrael 30 Авг 2017 в 17:33

Вы можете использовать функцию Pandas min по оси. Затем объедините это с мин / макс

https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.min.html

Например

df.max(axis=1)

Но похоже, что вы хотите обрезать значения вместо мин / макс.

3
Dat Chu 30 Авг 2017 в 17:33

numpy вид. Не так элегантно, как clip.

Вариант 1

df.assign(c=np.minimum(np.maximum(df.b.values, 0), 100))

    a    b    c
0  10   90   90
1  20  150  100
2  30  -30    0

Вариант 2

b = df.b.values
df.assign(c=np.where(b > 100, 100, np.where(b < 0, 0, b)))

    a    b    c
0  10   90   90
1  20  150  100
2  30  -30    0

< Сильный > Timing
Код ниже

res.div(res.min(1), 0)

            pir1  pir2       jez1
10     30.895514   1.0  75.210427
30     28.611177   1.0  49.913498
100    20.658307   1.0  50.823106
300    19.842134   1.0  39.162901
1000   14.078159   1.0  25.148937
3000    8.767133   1.0  15.066847
10000   4.377849   1.0   8.849138
30000   2.634263   1.0   4.653956

enter image description here

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    columns=['pir1', 'pir2', 'jez1'],
    dtype=float
)

jez1 = lambda d: d.assign(c=df.b.clip(0, 1))
pir1 = lambda d: d.assign(c=np.minimum(np.maximum(d.b.values, 0), 100))
pir2 = lambda d: (lambda b: np.where(b > 100, 100, np.where(b < 0, 0, b)))(d.b.values)

for i in res.index:
    d = pd.concat([df] * i, ignore_index=True)
    for j in res.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=10)

res.plot(loglog=True)
0
piRSquared 30 Авг 2017 в 18:20