2017-12-12 103 views
5

से सबसे हाल ही अवलोकन और तारीख हो रही निम्नलिखित खिलौना DataFrame लें:कई स्तंभ

data = np.arange(35, dtype=np.float32).reshape(7, 5) 
data = pd.concat((
    pd.DataFrame(list('abcdefg'), columns=['field1']), 
    pd.DataFrame(data, columns=['field2', '2014', '2015', '2016', '2017'])), 
    axis=1) 

data.iloc[1:4, 4:] = np.nan 
data.iloc[4, 3:] = np.nan 

print(data) 
    field1 field2 2014 2015 2016 2017 
0  a  0.0 1.0 2.0 3.0 4.0 
1  b  5.0 6.0 7.0 NaN NaN 
2  c 10.0 11.0 12.0 NaN NaN 
3  d 15.0 16.0 17.0 NaN NaN 
4  e 20.0 21.0 NaN NaN NaN 
5  f 25.0 26.0 27.0 28.0 29.0 
6  g 30.0 31.0 32.0 33.0 34.0 

मैं दो क्षेत्रों के साथ "साल" कॉलम (2014-2017) को बदलने के लिए करना चाहते हैं: सबसे हाल की गैर - अवलोकन अवलोकन, और उस अवलोकन के इसी वर्ष। मान लें field1 एक अनूठी कुंजी है। (मैं, किसी भी GroupBy ऑप्स करने के लिए नहीं देख रहा हूँ रिकॉर्ड प्रति सिर्फ 1 पंक्ति।) Ie:

field1 field2 obs date 
0  a  0.0 4.0 2017 
1  b  5.0 7.0 2015 
2  c 10.0 12.0 2015 
3  d 15.0 17.0 2015 
4  e 20.0 21.0 2014 
5  f 25.0 29.0 2017 
6  g 30.0 34.0 2017 

मैं इतनी दूर मिल गया है:

pd.melt(data, id_vars=['field1', 'field2'], 
     value_vars=['2014', '2015', '2016', '2017'])\ 
    .dropna(subset=['value']) 

    field1 field2 variable value 
0  a  0.0  2014 1.0 
1  b  5.0  2014 6.0 
2  c 10.0  2014 11.0 
3  d 15.0  2014 16.0 
4  e 20.0  2014 21.0 
5  f 25.0  2014 26.0 
6  g 30.0  2014 31.0 
# ... 

लेकिन यह कैसे वापस पिवट करने के लिए संघर्ष कर रहा हूँ के साथ वांछित प्रारूप के लिए।

उत्तर

4

शायद:

d2 = data.melt(id_vars=["field1", "field2"], var_name="date", value_name="obs").dropna(subset=["obs"]) 
d2["date"] = d2["date"].astype(int) 
df = d2.loc[d2.groupby(["field1", "field2"])["date"].idxmax()] 

जो मुझे

field1 field2 date obs 
21  a  0.0 2017 4.0 
8  b  5.0 2015 7.0 
9  c 10.0 2015 12.0 
10  d 15.0 2015 17.0 
4  e 20.0 2014 21.0 
26  f 25.0 2017 29.0 
27  g 30.0 2017 34.0 
2

last_valid_index + agg('last')

A=data.iloc[:,2:].apply(lambda x : x.last_valid_index(),1) 
B=data.groupby(['value'] * data.shape[1], 1).agg('last') 
data['date']=A 
data['obs']=B 

data 
Out[1326]: 
    field1 field2 2014 2015 2016 2017 date obs 
0  a  0.0 1.0 2.0 3.0 4.0 2017 4.0 
1  b  5.0 6.0 7.0 NaN NaN 2015 7.0 
2  c 10.0 11.0 12.0 NaN NaN 2015 12.0 
3  d 15.0 16.0 17.0 NaN NaN 2015 17.0 
4  e 20.0 21.0 NaN NaN NaN 2014 21.0 
5  f 25.0 26.0 27.0 28.0 29.0 2017 29.0 
6  g 30.0 31.0 32.0 33.0 34.0 2017 34.0 

देता है assign का उपयोग करके हम उन्हें एक में धक्का कर सकते हैं झटका

data.assign(date=data.iloc[:,2:].apply(lambda x : x.last_valid_index(),1),obs=data.groupby(['value'] * data.shape[1], 1).agg('last')) 
Out[1340]: 
    field1 field2 2014 2015 2016 2017 date obs 
0  a  0.0 1.0 2.0 3.0 4.0 2017 4.0 
1  b  5.0 6.0 7.0 NaN NaN 2015 7.0 
2  c 10.0 11.0 12.0 NaN NaN 2015 12.0 
3  d 15.0 16.0 17.0 NaN NaN 2015 17.0 
4  e 20.0 21.0 NaN NaN NaN 2014 21.0 
5  f 25.0 26.0 27.0 28.0 29.0 2017 29.0 
6  g 30.0 31.0 32.0 33.0 34.0 2017 34.0 
3

क्या निम्नलिखित apporach के बारे में के रूप में रेखा:

In [160]: df 
Out[160]: 
    field1 field2 2014 2015 2016 2017 
0  a  0.0 1.0 2.0 3.0 -10.0 
1  b  5.0 6.0 7.0 NaN NaN 
2  c 10.0 11.0 12.0 NaN NaN 
3  d 15.0 16.0 17.0 NaN NaN 
4  e 20.0 21.0 NaN NaN NaN 
5  f 25.0 26.0 27.0 28.0 29.0 
6  g 30.0 31.0 32.0 33.0 34.0 

In [180]: df.groupby(lambda x: 'obs' if x.isdigit() else x, axis=1) \ 
    ...: .last() \ 
    ...: .assign(date=df.filter(regex='^\d{4}').loc[:, ::-1].notnull().idxmax(1)) 
Out[180]: 
    field1 field2 obs date 
0  a  0.0 -10.0 2017 
1  b  5.0 7.0 2015 
2  c 10.0 12.0 2015 
3  d 15.0 17.0 2015 
4  e 20.0 21.0 2014 
5  f 25.0 29.0 2017 
6  g 30.0 34.0 2017 
+2

देता है मुझे इस बारे में निश्चित नहीं है - IIUC, ओपी सबसे हालिया मान्य मूल्य चाहता है, अधिकतम नहीं। दिए गए डेटासेट में, वे वही हैं, लेकिन अगर (उदाहरण के लिए) 2017 के लिए -10 था, तो मुझे लगता है कि हमें यही वापस करना चाहिए। – DSM

+0

@DSM, स्पष्टीकरण के लिए धन्यवाद! मुझे लगता है कि अगर मैं 'अधिकतम() '' last() 'के साथ' last() 'को प्रतिस्थापित कर दूंगा तो यह चाल चल जाएगा ... – MaxU

+1

लेकिन अब आप अंतिम _obs_ का उपयोग कर रहे हैं लेकिन अधिकतम _date_ (2016, 2017 नहीं)। [स्पष्टीकरण के लिए, मेरा मतलब है "जिस तारीख पर अधिकतम पहुंच गया है", मैं गलत होने के बिंदु पर आलसी हूं।] आपको 'idxlast()' के समतुल्य की आवश्यकता है (जो मौजूद नहीं है, लेकिन YKWIM।) – DSM

1

इसके अलावा sort_values और drop_duplicates का उपयोग करके एक और संभावना:

data.melt(id_vars=["field1", "field2"], var_name="date", 
      value_name="obs")\ 
    .dropna(subset=['obs'])\ 
    .sort_values(['field1', 'date'], ascending=[True, False])\ 
    .drop_duplicates('field1', keep='first') 

जो आप

field1 field2 date obs 
21  a  0.0 2017 4.0 
8  b  5.0 2015 7.0 
9  c 10.0 2015 12.0 
10  d 15.0 2015 17.0 
4  e 20.0 2014 21.0 
26  f 25.0 2017 29.0 
27  g 30.0 2017 34.0 
+0

@bradsolomon, जीवन विकल्पों के साथ हमेशा बेहतर होता है – DJK

संबंधित मुद्दे