2016-05-24 3 views
1

В кадре данных я хотел бы сравнить элементы столбца со значением и отсортировать элементы, которые передают сравнение в новый столбец.pandas element-wise compare and create selection

df = pandas.DataFrame([{'A':3,'B':10}, 
         {'A':2, 'B':30}, 
         {'A':1,'B':20}, 
         {'A':2,'B':15}, 
         {'A':2,'B':100}]) 

df['C'] = [x for x in df['B'] if x > 18] 

я не могу узнать, что это зло, и почему я получаю:

ValueError: Length of values does not match length of index

ответ

2

Как упоминал Даррен, все столбцы в DataFrame должны иметь одинаковую длину.

При попытке print [x for x in df['B'] if x > 18] вы получаете только [30, 20, 100] значений. Но у вас есть пять индексов/строк. Вот почему вы получаете ошибку Length of values does not match length of index.

Вы можете изменить свой код следующим образом:

df['C'] = [x if x > 18 else None for x in df['B']] 
print df 

Вы получите:

A B  C 
0 3 10 NaN 
1 2 30 30.0 
2 1 20 20.0 
3 2 15 NaN 
4 2 100 100.0 
2

Я думаю, что вы можете использовать loc с boolean indexing:

print (df) 
    A B 
0 3 10 
1 2 30 
2 1 20 
3 2 15 
4 2 100 

print (df['B'] > 18) 
0 False 
1  True 
2  True 
3 False 
4  True 
Name: B, dtype: bool 

df.loc[df['B'] > 18, 'C'] = df['B'] 
print (df) 
    A B  C 
0 3 10 NaN 
1 2 30 30.0 
2 1 20 20.0 
3 2 15 NaN 
4 2 100 100.0 

Если вам нужно выбрать с помощью условия boolean indexing:

print (df[df['B'] > 18]) 
    A B 
1 2 30 
2 1 20 
4 2 100 

Если нужно что-то более быстрее, используйте where:

df['C'] = df.B.where(df['B'] > 18) 

Timings (len(df)=50k):

In [1367]: %timeit (a(df)) 
The slowest run took 8.34 times longer than the fastest. This could mean that an intermediate result is being cached. 
1000 loops, best of 3: 1.14 ms per loop 

In [1368]: %timeit (b(df1)) 
100 loops, best of 3: 15.5 ms per loop 

In [1369]: %timeit (c(df2)) 
100 loops, best of 3: 2.93 ms per loop 

Код для таймингов:

import pandas as pd 

df = pd.DataFrame([{'A':3,'B':10}, 
         {'A':2, 'B':30}, 
         {'A':1,'B':20}, 
         {'A':2,'B':15}, 
         {'A':2,'B':100}]) 
print (df) 
df = pd.concat([df]*10000).reset_index(drop=True) 
df1 = df.copy() 
df2 = df.copy() 

def a(df): 
    df['C'] = df.B.where(df['B'] > 18) 
    return df 

def b(df1):  
    df['C'] = ([x if x > 18 else None for x in df['B']]) 
    return df 

def c(df2):  
    df.loc[df['B'] > 18, 'C'] = df['B'] 
    return df 

print (a(df)) 
print (b(df1)) 
print (c(df2)) 
+0

добавить новый быстрый метод, пожалуйста, проверьте его. Благодарю. – jezrael

0

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

Итак, ваши два варианта, чтобы начать новый DataFrame для C:

dfC = [x for x in df['B'] if x > 18] 

или но какое-то фиктивное значение в столбце, если x не равно 18+. Например .:

df['C'] = np.where(df['B'] > 18, True, False) 

Или даже:

df['C'] = np.where(df['B'] > 18, 'Yay', 'Nay') 

P.S. Также взгляните на: Pandas conditional creation of a series/dataframe column для других способов сделать это.