สร้าง Pandas DataFrame ที่ว่างเปล่าแล้วกรอกข้อมูลหรือไม่


461

ฉันเริ่มต้นจากเอกสาร DataFrame ของแพนด้าที่นี่: http://pandas.pydata.org/pandas-docs/stable/dsintro.html

ฉันต้องการเติม DataFrame ด้วยค่าในการคำนวณอนุกรมเวลาซ้ำ ๆ โดยพื้นฐานแล้วฉันต้องการเริ่มต้น DataFrame ด้วยคอลัมน์ A, B และแถวเวลาประทับทั้งหมด 0 หรือ NaN ทั้งหมด

ฉันจะเพิ่มค่าเริ่มต้นและดูข้อมูลนี้จากการคำนวณแถวใหม่จากแถวก่อนพูดrow[A][t] = row[A][t-1]+1หรืออย่างนั้น

ขณะนี้ฉันกำลังใช้รหัสด้านล่าง แต่ฉันรู้สึกว่ามันน่าเกลียดและต้องมีวิธีการทำเช่นนี้กับ DataFrame โดยตรงหรือเป็นวิธีที่ดีกว่าโดยทั่วไป หมายเหตุ: ฉันใช้ Python 2.7

import datetime as dt
import pandas as pd
import scipy as s

if __name__ == '__main__':
    base = dt.datetime.today().date()
    dates = [ base - dt.timedelta(days=x) for x in range(0,10) ]
    dates.sort()

    valdict = {}
    symbols = ['A','B', 'C']
    for symb in symbols:
        valdict[symb] = pd.Series( s.zeros( len(dates)), dates )

    for thedate in dates:
        if thedate > dates[0]:
            for symb in valdict:
                valdict[symb][thedate] = 1+valdict[symb][thedate - dt.timedelta(days=1)]

    print valdict

6
อย่าเติบโต DataFrame! มันถูกกว่าเสมอที่จะผนวกเข้ากับรายการหลามแล้วแปลงเป็น DataFrame ในตอนท้ายทั้งในแง่ของหน่วยความจำและประสิทธิภาพ
cs95

@ cs95 อะไรคือหน้าที่แตกต่างระหว่าง.appendใน pd และต่อท้ายรายการ? ฉันรู้ว่า.appendใน pandas คัดลอกชุดข้อมูลทั้งหมดไปยังวัตถุใหม่ yth pythons ต่อท้ายทำงานแตกต่างกันหรือไม่?
Lamma

@ Lamma โปรดหารายละเอียดในคำตอบของฉันด้านล่าง เมื่อผนวกเข้ากับ df, DataFrame ใหม่จะถูกสร้างขึ้นในแต่ละครั้งในหน่วยความจำแทนที่จะใช้ที่มีอยู่เดิมซึ่งค่อนข้างเสียเปล่า
cs95

คำตอบ:


330

นี่เป็นคำแนะนำสองสามข้อ:

ใช้date_rangeสำหรับดัชนี:

import datetime
import pandas as pd
import numpy as np

todays_date = datetime.datetime.now().date()
index = pd.date_range(todays_date-datetime.timedelta(10), periods=10, freq='D')

columns = ['A','B', 'C']

หมายเหตุ: เราสามารถสร้าง DataFrame ที่ว่างเปล่าNaNได้ด้วยการเขียน:

df_ = pd.DataFrame(index=index, columns=columns)
df_ = df_.fillna(0) # with 0s rather than NaNs

ในการทำการคำนวณประเภทนี้สำหรับข้อมูลให้ใช้อาร์เรย์แบบ numpy:

data = np.array([np.arange(10)]*3).T

ดังนั้นเราสามารถสร้าง DataFrame:

In [10]: df = pd.DataFrame(data, index=index, columns=columns)

In [11]: df
Out[11]: 
            A  B  C
2012-11-29  0  0  0
2012-11-30  1  1  1
2012-12-01  2  2  2
2012-12-02  3  3  3
2012-12-03  4  4  4
2012-12-04  5  5  5
2012-12-05  6  6  6
2012-12-06  7  7  7
2012-12-07  8  8  8
2012-12-08  9  9  9

2
pd.date_range () ไม่ทำงานสำหรับฉัน ฉันลองกับ DateRange (จากการเติมข้อความอัตโนมัติของ eclipse) แต่นั่นใช้ได้กับสตริงในรูปแบบวันที่ใช่ไหม? วิธีการโดยรวมใช้งานได้ (ฉันเปลี่ยนดัชนีเป็นอย่างอื่น)
Matthias Kauer

2
date_range เป็นฟังก์ชั่นจากโรงงานสำหรับการสร้างดัชนีวันที่และเป็นคุณสมบัติใหม่ใน 0.8.0ฉันขอแนะนำให้อัพเกรดเป็นเวอร์ชั่นล่าสุดที่เสถียร (0.9.1) มีการแก้ไขข้อบกพร่องและคุณสมบัติใหม่มากมาย :)
Andy Hayden

26
จากประสบการณ์ของฉันการสร้าง data frame ที่มีขนาดที่จำเป็นซึ่งเต็มไปด้วย NaNs แล้วการเติมด้วยค่าจะช้ากว่าการสร้าง data frame ที่มีขนาดindexx 0( columns = []) และแนบหนึ่งคอลัมน์ในแต่ละรอบของลูป ฉันหมายถึงdf[col_name] = pandas.Series([...])การวนซ้ำวนซ้ำผ่านชื่อคอลัมน์ ในกรณีก่อนหน้านี้ไม่เพียง แต่การจัดสรรหน่วยความจำต้องใช้เวลา แต่การแทนที่ NaN ด้วยค่าใหม่นั้นช้ามาก
deeenes

5
@deeenes แน่นอน คำตอบนี้ควรทำให้ชัดเจนยิ่งขึ้น - คุณไม่ค่อยต้องการสร้าง Dataframe ที่ว่างเปล่าของ NaN
Andy Hayden

1
ตามคำตอบนี้stackoverflow.com/a/30267881/2302569คุณต้องกำหนดผลลัพธ์ของ Fillna หรือผ่าน Param inplace = True
JayJay

169

หากคุณต้องการสร้างกรอบข้อมูลเปล่าและกรอกข้อมูลด้วยเฟรมข้อมูลขาเข้าในภายหลังให้ลองทำดังนี้

newDF = pd.DataFrame() #creates a new dataframe that's empty
newDF = newDF.append(oldDF, ignore_index = True) # ignoring index is optional
# try printing some data from newDF
print newDF.head() #again optional 

ในตัวอย่างนี้ฉันใช้pandas doc นี้เพื่อสร้าง data frame ใหม่จากนั้นใช้ผนวกเพื่อเขียนไปยัง newDF ด้วยข้อมูลจาก oldDF

หากฉันต้องต่อท้ายข้อมูลใหม่ใน newDF นี้จาก OldDF มากกว่าหนึ่งฉันจะใช้สำหรับวนรอบเพื่อวนซ้ำ pandas.DataFrame.append ()


14
โปรดทราบว่าappend(และในทำนองเดียวกันconcat) คัดลอกชุดข้อมูลแบบเต็มไปยังวัตถุใหม่ทุกครั้งดังนั้นการวนซ้ำและการผนวกสามารถและจะทำให้ประสิทธิภาพการทำงานที่สำคัญ สำหรับข้อมูลเพิ่มเติมอ้างถึง: pandas.pydata.org/pandas-docs/stable/merging.html
MoustafaAAtta

4
@MoustafaAAtta ทางเลือกอื่นในการผนวกข้อมูลซ้ำ ๆ ลงใน DataFrame คืออะไร?
MysteryGuy

2
@MoustafaAAtta คำตอบของ Fred ในโพสต์นี้: stackoverflow.com/questions/10715965/ดีกว่าในมุมมองนี้หรือไม่?
MysteryGuy

@MoustafaAAtta คุณสามารถต่อท้ายเพียงแค่แถวไปยัง dataframe มันจะยังคงสร้างวัตถุใหม่ แต่สำหรับชุดข้อมูลขนาดเล็กอาจมีประโยชน์ pandas.pydata.org/pandas-docs/stable/user_guide/…
geekidharsh

135

วิธีที่เหมาะสม™ในการสร้าง DataFrame

TLDR; (เพียงอ่านข้อความที่เป็นตัวหนา)

คำตอบส่วนใหญ่ที่นี่จะบอกคุณถึงวิธีการสร้าง DataFrame ที่ว่างเปล่าและกรอกข้อมูล แต่ไม่มีใครจะบอกคุณว่ามันเป็นสิ่งที่ไม่ดีที่จะทำ

นี่คือคำแนะนำของฉัน: รอจนกว่าคุณจะแน่ใจว่าคุณมีข้อมูลทั้งหมดที่คุณต้องการใช้งาน ใช้รายการเพื่อรวบรวมข้อมูลของคุณจากนั้นเริ่มต้น DataFrame เมื่อคุณพร้อม

data = []
for a, b, c in some_function_that_yields_data():
    data.append([a, b, c])

df = pd.DataFrame(data, columns=['A', 'B', 'C'])

มันถูกกว่าเสมอที่จะผนวกเข้ากับรายการและสร้าง DataFrame ในครั้งเดียวมากกว่าที่จะสร้าง DataFrame ที่ว่างเปล่า (หรือหนึ่งใน NaNs) และผนวกกับมันซ้ำแล้วซ้ำอีก รายการยังใช้หน่วยความจำน้อยลงและเป็นโครงสร้างข้อมูลที่เบากว่ามากในการทำงานผนวกและลบ (ถ้าจำเป็น)

ข้อได้เปรียบอื่น ๆ ของวิธีนี้dtypesจะถูกอนุมานโดยอัตโนมัติ (แทนที่จะกำหนดobjectกับพวกเขาทั้งหมด)

ข้อได้เปรียบสุดท้ายคือa RangeIndexถูกสร้างขึ้นโดยอัตโนมัติสำหรับข้อมูลของคุณดังนั้นจึงเป็นสิ่งที่กังวลน้อยกว่า (ดูที่วิธีการที่ไม่ดีappendและlocด้านล่างคุณจะเห็นองค์ประกอบทั้งสองที่จำเป็นต้องจัดการกับดัชนีอย่างเหมาะสม)


สิ่งที่คุณไม่ควรทำ

appendหรือconcatภายในวง

นี่คือความผิดพลาดที่ใหญ่ที่สุดที่ฉันเคยเห็นจากผู้เริ่มต้น:

df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
    df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
    # or similarly,
    # df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)

หน่วยความจำเป็นอีกครั้งที่จัดสรรสำหรับทุกappendหรือconcatการดำเนินการที่คุณมี คู่นี้มีห่วงและคุณมีการดำเนินงานที่ซับซ้อนสมการกำลังสอง จากdf.appendหน้าเอกสาร :

การต่อแถวเข้ากับ DataFrame ซ้ำ ๆ อาจทำให้การคำนวณเข้มข้นกว่าการต่อข้อมูลเดียว ทางออกที่ดีกว่าคือการผนวกแถวเหล่านั้นเข้ากับรายการแล้วเชื่อมต่อรายการกับ DataFrame ดั้งเดิมทั้งหมดพร้อมกัน

ข้อผิดพลาดอื่น ๆ ที่เกี่ยวข้องกับdf.appendคือผู้ใช้มักจะลืมผนวกไม่ใช่ฟังก์ชั่นในสถานที่ดังนั้นผลจะต้องได้รับมอบหมายกลับ คุณต้องกังวลเกี่ยวกับโรคไข้เลือดออกด้วย:

df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)

df.dtypes
A     object   # yuck!
B    float64
C     object
dtype: object

การจัดการกับคอลัมน์ของวัตถุนั้นไม่ใช่สิ่งที่ดีนักเนื่องจากนุ่นไม่สามารถทำให้การดำเนินการในคอลัมน์เหล่านั้นเป็นเวกเตอร์ได้ คุณจะต้องทำสิ่งนี้เพื่อแก้ไข:

df.infer_objects().dtypes
A      int64
B    float64
C     object
dtype: object

loc ภายในวง

ฉันเคยเห็นเคยlocใช้ผนวก DataFrame ที่ถูกสร้างขึ้นที่ว่างเปล่า:

df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
    df.loc[len(df)] = [a, b, c]

ก่อนที่คุณยังไม่ได้ก่อนการจัดสรรจำนวนหน่วยความจำที่คุณต้องการในแต่ละครั้งเพื่อให้หน่วยความจำใหม่เติบโตขึ้นทุกครั้งที่คุณสร้างแถวใหม่ มันก็แย่เหมือนกันappendมากและน่าเกลียดยิ่งกว่าเดิม

DataFrame ว่างเปล่าของ NaNs

จากนั้นมีการสร้าง DataFrame ของ NaN และคำเตือนทั้งหมดที่เกี่ยวข้อง

df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
     A    B    C
0  NaN  NaN  NaN
1  NaN  NaN  NaN
2  NaN  NaN  NaN
3  NaN  NaN  NaN
4  NaN  NaN  NaN

มันสร้าง DataFrame ของคอลัมน์วัตถุเช่นอื่น ๆ

df.dtypes
A    object  # you DON'T want this
B    object
C    object
dtype: object

การผนวกยังคงมีปัญหาทั้งหมดตามวิธีการด้านบน

for i, (a, b, c) in enumerate(some_function_that_yields_data()):
    df.iloc[i] = [a, b, c]

หลักฐานอยู่ในพุดดิ้ง

การกำหนดเวลาวิธีการเหล่านี้เป็นวิธีที่เร็วที่สุดในการดูว่ามีความแตกต่างในแง่ของหน่วยความจำและยูทิลิตี้อย่างไร

ป้อนคำอธิบายรูปภาพที่นี่

รหัสเปรียบเทียบสำหรับการอ้างอิง


6
การต่อท้ายรายการควรเป็นวิธีที่ดีที่สุดสำหรับคำถามประเภทนี้
YOBEN_S

9
สิ่งนี้จำเป็นต้องได้รับการสนับสนุนมากกว่าหนึ่งล้านครั้ง อย่าปลูกดาต้าเฟรมไว้เลย!
Buggy

3
@ user3293236 น่าเสียดายที่คุณต้องเริ่มจากจุดต่ำสุดทุกครั้งที่คุณตอบคำถามเก่า)
cs95

2
นี่คือสิ่งหนึ่งที่ฉันเกลียดที่สุด หลายครั้งที่คุณเห็น𝒓𝒆𝒂𝒍𝒄𝒐𝒓𝒓𝒆𝒄𝒕𝒂𝒏𝒔𝒘𝒆𝒓ที่อยู่ที่ไหนสักแห่งด้วยคะแนนน้อยและไม่เคยยอมรับ ฉันพลาดรหัสด้วย𝚍𝚏 = 𝚙𝚍.𝙳𝚊𝚝𝚊𝙵𝚛𝚊𝚖𝚎 ([]) เพื่อสร้างดาต้าเฟรมแพนด้าที่ว่างเปล่า การตอบคำถามนี้ คำอธิบายที่ยอดเยี่ยม @ cs95!
โจนาธาน

1
นี่คือแท้จริงในเอกสารประกอบ "การต่อแถวเข้ากับ DataFrame ซ้ำแล้วซ้ำอีกจะเป็นการเพิ่มความเข้มข้นของการคำนวณมากกว่า concatenate เดียววิธีที่ดีกว่าคือการผนวกแถวเหล่านั้นเข้ากับรายการ pandas.pydata.org/pandas-docs/version/0.21/generated/...
endolith

132

เริ่มต้นเฟรมที่ว่างเปล่าด้วยชื่อคอลัมน์

import pandas as pd

col_names =  ['A', 'B', 'C']
my_df  = pd.DataFrame(columns = col_names)
my_df

เพิ่มระเบียนใหม่ลงในเฟรม

my_df.loc[len(my_df)] = [2, 4, 5]

คุณอาจต้องการส่งพจนานุกรม:

my_dic = {'A':2, 'B':4, 'C':5}
my_df.loc[len(my_df)] = my_dic 

ผนวกเฟรมอื่นกับเฟรมที่มีอยู่ของคุณ

col_names =  ['A', 'B', 'C']
my_df2  = pd.DataFrame(columns = col_names)
my_df = my_df.append(my_df2)

ข้อควรพิจารณาด้านประสิทธิภาพ

หากคุณกำลังเพิ่มแถวภายในวงพิจารณาปัญหาประสิทธิภาพการทำงาน สำหรับรอบ 1,000 ระเบียนแรก "my_df.loc" ประสิทธิภาพจะดีขึ้น แต่มันจะค่อยๆช้าลงโดยการเพิ่มจำนวนของระเบียนในลูป

หากคุณวางแผนที่จะทำเรทภายในวงใหญ่ (พูดว่าบันทึก 10M‌ หรือมากกว่านั้น) คุณจะดีกว่าถ้าใช้ทั้งสองอย่างนี้ผสมกัน เติม dataframe ด้วย iloc จนกระทั่งขนาดมีขนาดประมาณ 1,000 แล้วต่อท้ายไปที่ dataframe ดั้งเดิมและเทมเปอร์ temp datrrame ให้ว่าง สิ่งนี้จะช่วยเพิ่มประสิทธิภาพของคุณประมาณ 10 ครั้ง


my_df = my_df.append(my_df2)ignore_index=Trueไม่ทำงานสำหรับฉันจนกว่าฉันระบุ
Nasif Imtiaz Ohi

0

สมมติว่า dataframe มี 19 แถว

index=range(0,19)
index

columns=['A']
test = pd.DataFrame(index=index, columns=columns)

การรักษาคอลัมน์ A เป็นค่าคงที่

test['A']=10

การรักษาคอลัมน์ b เป็นตัวแปรที่กำหนดโดยการวนซ้ำ

for x in range(0,19):
    test.loc[[x], 'b'] = pd.Series([x], index = [x])

คุณสามารถแทนที่ x แรกpd.Series([x], index = [x])ด้วยค่าใดก็ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.