2017-02-22 118 views
3

这里的一部分是我输入:大熊猫仅更换一列

import pandas as pd 
import numpy as np 

list1 = [10,79,6,38,4,557,12,220,46,22,45,22] 
list2 = [4,3,23,6,234,47,312,2,426,42,435,23] 

df = pd.DataFrame({'A' : list1, 'B' : list2}, columns = ['A', 'B']) 
df['C'] = np.where (df['A'] > df['B'].shift(-2), 1, np.nan) 
print (df) 

产生这样的输出:

 A B C 
0 10 4 NaN 
1 79 3 1.0 
2  6 23 NaN 
3 38 6 NaN 
4  4 234 NaN 
5 557 47 1.0 
6 12 312 NaN 
7 220 2 1.0 
8 46 426 NaN 
9 22 42 NaN 
10 45 435 NaN 
11 22 23 NaN 

我需要做的是改变列“C”是一个集三个1连续,不重叠。期望的输出是:

 A B C 
0 10 4 NaN 
1 79 3 1.0 
2  6 23 1.0 
3 38 6 1.0 
4  4 234 NaN 
5 557 47 1.0 
6 12 312 1.0 
7 220 2 1.0 
8 46 426 NaN 
9 22 42 NaN 
10 45 435 NaN 
11 22 23 NaN 

因此,第2,3和6行从NaN变为1.0。第7行已经有一个1.0,它被忽略。第8行和第9行需要保留NaN,因为第7行是前一组的最后一个条目。

我不知道是否有更好的方法来创建列'C',在创建时会这样做。

我已经尝试了几个版本的fillna和ffill,他们都没有为我工作。

这似乎很令人费解,但我试图孤立行ID对每个1.0这一行:

print (df.loc[df['C'] == 1]) 

哪个正确输出这样的:尽管我知道,信息

 A B C 
1 79 3 1.0 
5 557 47 1.0 
7 220 2 1.0 

,我不知道如何从那里出发。

非常感谢你为您的帮助提前, 大卫

+0

如果你有一个序列为'1大,NaN,1,1大,NaN,NaN'?你想要结果是什么? – Psidom

+0

谢谢你看psidom - 结果将全部为1的 –

+0

行。那么你的情况应该是索引8和9? – Psidom

回答

4

编辑:

更快的版本(感谢B2002):

ii = df[pd.notnull(df.C)].index 
dd = np.diff(ii) 
jj = [ii[i] for i in range(1,len(ii)) if dd[i-1] > 2] 
jj = [ii[0]] + jj 

for ci in jj: 
    df.C.values[ci:ci+3] = 1.0 

首先让你的所有的出发点,即所有的点是1.0,并且具有索引2的NaN以下通过查看C列中的非空点之间的差异(默认情况下包含第一个索引),然后遍历这些索引并使用loc来更改您的C列的切片:

ii = df[pd.notnull(df.C)].index 
dd = np.diff(ii) 
jj = [ii[i] for i in range(1,len(ii)) if dd[i-1] > 2] 
jj = [ii[0]] + jj 

for ci in jj: 
    df.loc[ci:ci+2,'C'] = 1.0 

结果:

 A B C 
0 10 4 NaN 
1 79 3 1.0 
2  6 23 1.0 
3 38 6 1.0 
4  4 234 NaN 
5 557 47 1.0 
6 12 312 1.0 
7 220 2 1.0 
8 46 426 NaN 
9 22 42 NaN 
10 45 435 NaN 
11 22 23 NaN 
+0

非常好的答案!真的很喜欢numpy差异的指标。 – b2002

+0

经过一段时间之后,如果对df.C的数组进行赋值而不是使用df.loc,结果非常慢,那么对于较大的数据帧,这可以大大加快。 – b2002

+0

克里斯 - 非常感谢。你的解决方案在df –

1
list1 = [10,79,6,38,4,557,12,220,46,22,45,22] 
list2 = [4,3,23,6,234,47,312,2,426,42,435,23] 

df = pd.DataFrame({'A' : list1, 'B' : list2}, columns = ['A', 'B']) 
df['C'] = np.where (df['A'] > df['B'].shift(-2), 1, np.nan) 

     A B C 
0 10 4 NaN 
1 79 3 1.0 
2  6 23 NaN 
3 38 6 NaN 
4  4 234 NaN 
5 557 47 1.0 
6 12 312 NaN 
7 220 2 1.0 
8 46 426 NaN 
9 22 42 NaN 
10 45 435 NaN 
11 22 23 NaN 

使从次序排列:

a = np.array(df.C) 

此功能将测试一个数组的部分匹配的模式,将取代与其他模式匹配的段。以前匹配的段不会被考虑用于未来的匹配(填充数大于1)。

def fill_segments(a, test_patterns, fill_patterns): 
    # replace nans with zeros so fast numpy array_equal will work 
    nan_idx = np.where(np.isnan(a))[0] 
    np.put(a, nan_idx, 0.) 
    col_index = list(np.arange(a.size)) 
    # loop forward through sequence comparing segment patterns 
    for j in np.arange(len(test_patterns)): 
     this_pattern = test_patterns[j] 
     snip = len(this_pattern) 
     rng = col_index[:-snip + 1] 
     for i in rng: 
      seg = a[col_index[i: i + snip]] 
      if np.array_equal(seg, this_pattern): 
       # when a match is found, replace values in array segment 
       # with fill pattern 
       pattern_indexes = col_index[i: i + snip] 
       np.put(a, pattern_indexes, fill_patterns[j]) 
    # convert all fillers to ones 
    np.put(a, np.where(a > 1.)[0], 1.) 
    # convert zeros back to nans 
    np.put(a, np.where(a == 0.)[0], np.nan) 

    return a 

模式进行更换:

p1 = [1., 1., 1.] 
p2 = [1., 0., 1.] 
p3 = [1., 1., 0.] 
p4 = [1., 0., 0.] 

和相应的填充图案:

f1 = [5., 5., 5.] 
f2 = [4., 4., 4.] 
f3 = [3., 3., 3.] 
f4 = [2., 2., 2.] 

使test_patterns和fill_patterns输入

patterns = [p1, p2, p3, p4] 
fills = [f1, f2, f3, f4] 

运行功能:

a = fill_segments(a, patterns, fills) 

分配到列C

df.C = a 

DF:

 A B C 
0 10 4 NaN 
1 79 3 1.0 
2  6 23 1.0 
3 38 6 1.0 
4  4 234 NaN 
5 557 47 1.0 
6 12 312 1.0 
7 220 2 1.0 
8 46 426 NaN 
9 22 42 NaN 
10 45 435 NaN 
11 22 23 NaN 

的模式和填充可能需要调整/加入到根据初始填充输入列的方式和具体的结果顺序规则。

+0

b2002 - 非常感谢您的解决方案。它完美的样品df –

+0

b2002和Khris - 感谢您的解决方案,他们都工作。当我创建上面的例子时,我搞砸了,因为我实际上是想用datetime索引而不是整数索引来使用它。不幸的是,这些解决方案似乎不适用于该dtype。我在这里发布了一个后续问题,如果你关心它的话。谢谢。 –

+0

http://stackoverflow.com/questions/42418035/pandas-replace-only-part-of-a-column-with-datetime-index –