Changes

Jump to navigation Jump to search
no edit summary
{{Project|Has project output=Data|Has sponsor=McNair ProjectsCenter
|Has title=Patent Data Restructure
|Has owner=Marcela Interiano, Sonia Zhang,
|Has start date=201701
|Has deadline=201705
||Has keywords=Patent,Data|Has project status=ActiveSubsume|Does subsume=Patent Data (Wiki Page), Patent Data Cleanup - June 2016, Patent Data Extraction Scripts (Tool), USPTO Bulk Data Processing,
}}
In order to restructure the current patent dataset, the data requires rigorous cleaning. The primary areas for improvement are:
Column | Type | Modifiers
-----------------+-----------------------+-----------
Reel No | integer | Frame No | integer | Invention Title | character varying(500)| Filing Date | date | Patent No | integer | Application No | integer | Publication No | integer | Match By | integer |
Currently the pto tables contain varying identifiers for one invention title that is involved in a reassignment. The purpose of the table is to have each identifier for an invention title listed in a single row, making it easy to track the invention through various transactions. The Match By column will inform the user which identifier should be used to match to other tables in the patent database.
 
==Data Cleanup Progress==
The tables that currently comprise the assignment data are as follows.
Column | Type | Modifiers
-------------------------+------------------------+-----------
reelno | integer | frameno | integer | last_update_date | date | purge_indicator | character varying(2) | recorded_date | date | correspondent_name | character varying(500) | correspondent_address_1 | character varying(500) | correspondent_address_2 | character varying(500) | correspondent_address_3 | character varying(500) | correspondent_address_4 | character varying(500) | conveyance_text | character varying(500) |
Table "public.ptoassignee"
Column | Type | Modifiers
-----------+------------------------+-----------
reelno | integer | frameno | integer | name | character varying(500) | addrline1 | character varying(500) | addrline2 | character varying(500) | city | character varying(500) | state | character varying(500) | country | character varying(500) | postcode | character varying(80) |
Table "public.ptoassignor"
Column | Type | Modifiers
----------------+------------------------+-----------
reel_no | integer | frame_no | integer | assignor_name | character varying(500) | execution_date | date |
Table "public.ptoproperty"
Column | Type | Modifiers
-----------------+------------------------+-----------
reelno | integer | frameno | integer | documentid | character varying(20) | country | character varying(500) | kind | character varying(3) | filingdate | date | invention_title | character varying(500) |
Table "public.ptopatentfile"
Column | Type | Modifiers
------------------------+-----------------------+-----------
reel_no | integer | frame_no | integer | action_key_code | character varying(10) | uspto_transaction_date | date | uspto_date_produced | date | version | numeric | This section explains the series of steps that were taken to clean and to take note of problems in the data. Additionally, this section includes the codes for new tables that combine patent properties from different tables in the original assignment data.  ===Table Cleanup===
==Data Cleanup Progress==The five original assignment tables contain duplicates that were deleted. Five new tables were made and used as templates for building new tables.  Ptoassignmentnd Table:   SELECT COUNT(*) FROM ptoassignment; --8676322  DROP ptoassignmentnd; CREATE TABLE ptoassignmentnd AS SELECT reelno, frameno, max(last_update_date) as last_update_date, purge_indicator, recorded_date, correspondent_name, correspondent_address_1, correspondent_address_2, correspondent_address_3, correspondent_address_4, conveyance_text FROM ptoassignment GROUP BY reelno, frameno, purge_indicator, recorded_date, correspondent_name, correspondent_address_1, correspondent_address_2, correspondent_address_3, correspondent_address_4, conveyance_text; --6988575 Ptoassigneend Table:   SELECT COUNT(*) FROM ptoassignee; --8983280  DROP ptoassigneend; CREATE TABLE ptoassigneend AS SELECT DISTINCT reelno, frameno, name, addrline1, addrline2, city, state, country, postcode FROM ptoassignee; --7234001 Ptoassignornd Table:   SELECT COUNT(*) FROM ptoassignor; --20062463  DROP ptoassignornd; CREATE TABLE ptoassinornd AS SELECT DISTINCT reel_no, frame_no, assignor_name, execution_date FROM ptoassignor; --16126903 Ptoproperty_cleaned Table:   SELECT COUNT(*) FROM ptoproperty; --65214396  DROP TABLE ptoproperty_cleaned; CREATE TABLE ptoproperty_cleaned AS SELECT DISTINCT reelno, frameno, documentid, country, kind, filingdate, invention_title FROM ptoproperty; --8696149 Ptopatentfilend Table:   SELECT COUNT(*) FROM ptopatentfile; --8676317  DROP ptopatentfilend; CREATE TABLE ptopatentfilend AS SELECT DISTINCT reel_no, frame_no, action_key_code, uspto_transaction_date, uspto_date_produced, version FROM ptopatentfile; --7159725
===Patent Number Cleanup===
WHERE (M1.reelno = M2.reelno) AND (M1.frameno = M2.frameno);
--8699074
 
In making the ptotracking table, it is important to note that the classification of documentids as B1 and B2 causes duplicates in the entries. B1 and B2 classifications mean that the patent was granted with and without a published application.
Ptotracking2 adds the assignee to the transaction, allowing the user to track ownership of the entity and of the patent.
WHERE (M1.reelno = M2.reelno) AND (M1.frameno = M2.frameno);
--9613927
 
The document ids in the PTO assignment data had not yet been verified as matching to the main patent table in our database (psql patent). The document ids in the PTO assignment data are stored as character strings whereas the patents in the patent table are stored as integers. Unlike the ptoprpoperty_cleaned table, all patent numbers in the patent table are unique.
 
The following two tables were made in order to verify that the documentids in the ptoproperty_cleaned table match to the patent table.
 
DROP TABLE edcheck;
CREATE TABLE edcheck AS
SELECT CAST (documentid AS INT) FROM ptotracking2;
 
SELECT COUNT(DISTINCT documentid) FROM edcheck;
--2343765
 
DROP TABLE edcheck2;
CREATE TABLE edcheck2 AS
SELECT M1.documentid, M2.patent
FROM edcheck M1, patent M2
WHERE (M1.documentid = M2.patent);
--2238305
 
DROP TABLE edcheck;
CREATE TABLE edcheck AS
SELECT DISTINCT documentid FROM ptotracking2;
--2343765
 
DROP TABLE edcheck2;
CREATE TABLE edcheck2 AS
SELECT CAST(documentid AS INT)FROM edcheck;
--2343765
 
DROP TABLE edcheck3;
CREATE TABLE edcheck3 AS
SELECT M1.documentid, M2.patent FROM edcheck2 M1, patent M2 WHERE M1.documentid = M2.patent;
--2238305
 
Based on the iterations of these tables, we could conclude that our original patent data forms the majority of the patents undergoing reassignments or transactions.
===US ONLY Patent Assignee Table===
SELECT COUNT(*) FROM (SELECT DISTINCT patentno FROM ptoassignee_us_patent) AS P;
--2345763
 
===Current Assignee using Recorded Date===
 
Each assignment has three dates: filingdate, recorded_date, last_update_date. The filingdate corresponds to the filing of the assignment with the USPTO. The recorded_date is the date the transaction was recorded. The last_update_date is the date the USPTO verifies that the assignment still holds. In the ptoassignee_us_patent table, the last_update_date is used to find the current assignee.
 
Prior to Sonia's work with the ptoassignee table address data, the table ptoassignee_current was made using the most recent recorded_date. This method though is flawed given that additional transactions could have current previously that are still in effect as patents can have multiple assignees. These codes can be used for constructing similar tables using the address data Sonia has cleaned in the following sections of this project.
 
To begin with, the ptoproperty_patent table was cleaned to drop all duplicates. Then the table was matched with the assignee table.
 
DROP TABLE ptoassigneev1;
CREATE TABLE ptoassigneev1 AS
SELECT M1.reelno, M1.frameno, M1.documentid, M1.country, M1.filingdate, M2.last_update_date,
M2.recorded_date
FROM ptoproperty_patent2 M1, ptoassignmentnd M2
WHERE (M1.reelno = M2.reelno) AND (M1.frameno = M2.frameno);
 
DROP TABLE ptoassigneev2;
CREATE TABLE ptoassigneev2 AS
SELECT M1.reelno, M1.frameno, M1.documentid, M2.name, M1.country, M1.last_update_date, M1.recorded_date,
M2.addrline1, M2.addrline2, M2.city, M2.state, M2.postcode
FROM ptoassigneev1 M1, ptoassigneend M2
WHERE (M1.reelno = M2.reelno) AND (M1.frameno = M2.frameno);
--9634942
 
Once all the location and address fields from the ptoassignee table have been added to the ptoproperty_patent fields, the max recorded_date was identified from the ptoassignee_patent table and from ptoassigneev2 for comparison.
 
DROP TABLE datecheck;
CREATE TABLE datecheck AS
SELECT documentid, max(recorded_date) as recorded_date FROM ptoassignee_patent GROUP BY documentid;
--2343765
 
DROP TABLE datecheck;
CREATE TABLE datecheck AS
SELECT documentid, max(recorded_date) as recorded_date FROM ptoassigneev2 GROUP BY documentid;
--4374885
 
DROP TABLE ptoassignee_patent;
CREATE TABLE ptoassignee_patent AS
SELECT M1.reelno, M1.frameno, M1.documentid, M1.name, M1.last_update_date, M1.recorded_date, M2.addrline1,
M2.addrline2, M2.city, M2.state, M2.country, M2.postcode
FROM ptotracking2 M1, ptoassigneend M2 WHERE (M1.reelno = M2.reelno) AND (M1.frameno = M2.frameno);
--16581236
 
DROP TABLE ptoassignee_current;
CREATE TABLE ptoassignee_current AS
SELECT M1.reelno, M1.frameno, M2.documentid, M2.recorded_date FROM ptoassignee_patent M1, datecheck M2
WHERE (M1.documentid = M2.documentid)
AND (M1.recorded_date = M2.recorded_date);
--6729698
 
A final version of the ptoassignee_current table was made using ptoassigneev2 given the larger pool of documentids included in the table by matching using documentid and recorded dates from datecheck.
 
DROP TABLE ptoassignee_current;
CREATE TABLE ptoassignee_current AS
SELECT M1.reelno, M1.frameno, M2.documentid, M1.name, M1.last_update_date, M2.recorded_date, M1.addrline1,
M1.addrline2, M1.country, M1.city, M1.state, M1.postcode
FROM ptoassigneev2 M1, datecheck M2
WHERE (M1.documentid = M2.documentid) AND (M1.recorded_date = M2.recorded_date);
--4994869
 
These codes should be used to recreate this table using Sonia's updated address information.
 
===Matching Application and Publication Numbers===
The ptoproperty_cleaned documentids to verify the kind of different patents as specified in the ptoproperty tables.
 
First the table ptopropertynd was made, including only the distinct documentids in ptoproperty_cleaned.
 
DROP ptopropertynd;
CREATE TABLE ptopropertynd AS
SELECT DISTINCT * FROM ptoproperty;
--27266638
 
By creating this table, I also address the duplications caused by the kind XO.
===Final Table (name TBD)===
SQL code and other things are in:
E:/McNair/Projects/PatentAddress/RestructureAddressInfo(First Stage).sql
IO files are on the dbase server in:
SQL code is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
====State====
SQL code is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
====City====
SQL code is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
====Output (Tables)====
SQL code is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
===Clean Address Info (Master Table)===
SQL code is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
For records of which 'addrline1', 'addrline2' and 'city' don't contain postcode info, just clean the 'postcode' as the 'postcode_cleaned'
SQL code is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
All the cleaned states for U.S. patents are stored in ptoassigneend_us_cleaned (see feature state_cleaned).
SQL code is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
All the cleaned cities for U.S. patents are stored in ptoassigneend_us_cleaned. (see feature city_cleaned)
All the SQL is in:
E:/McNair/Projects/PatentAddress/FunctionsRestructureAddressInfo(First Stage).sql
==== Cleaning ====
SQL code and other things are in:
E:/McNair/Projects/PatentAddress/Cleaning_Step2RestructureAddressInfo(Second Stage).sql
IO files are on the dbase server in:
==== Output: ptoassigneend_us_identify0 ====
As mentionedin Section 3, the ptoassigneend_us_extracted is cleanedclean. Copy all the records in ptoassigneend_us_extracted to ptoassigneend_us_identify0.
Store remaining records in ptoassigneend_us_temp.
==== Output: ptoassigneend_us_identify1 ====
The following section works on the remaining records which are stored in ptoassigneend_us_temp.
First, filter Filter out records with city that is a city, zip that is a zip, state that is a state.
Note: The consistency between city and state or city and postcode is not checked in this section.
* ptoassigneend_us_citylist
Select Copy clean city records in ptoassigneend_us_extracted and store them in to ptoassigneend_us_citylist (775).
Since the city list is not long, I briefly cleaned the list by hand, and updated the ptoassigneend_us_citylist (730).
* zip that is a zip
Match the pattern 55d-4 4d or 5 digits.
*state that is a state
*city that is a city
One option method to identify clean city is to find city records that match ptoassigneend_us_citylist.
SQL Code:
-- SELECT 2603422
* The table ptoassigneend_us_identify1 stores records that meet all the requirements above: zip with 5-4 or 5 digits, state not null or and not spaces, and city in ptoasigneend_us_citylist.
SQL Code:
==== Output: ptoassigneend_us_identify2 ====
Part of 'city' contains commaat the end. Remove comma, and then match 'city' with ptoassigneend_us_citylist.
SELECT *, replace(city, ',', '') clean_city
# SELECT 14508
Store remaining data (excluding data in ptoassigneend_us_identify0, ptoassigneend_us_identify1 & ptoassigneend_us_identify2) in ptoassigneend_temp3ptoassigneend_us_temp3.
=== Clean Address: more patterns ===
ObjectTable: ptoassigneend_temp3 ptoassigneend_us_temp3
SQL code is in E:\McNair\Projects\PatentAddress\Cleaning_Step2RestructureAddressInfo(Second Stage).sql
====Clean Postcode====
Identifying five-digit postcode is risky because of the existence of P.O. BOX #, SUITE #, etc.
One option is to identify state and postcode together with the following SQL codefunction: (take 'addrline1' as an example)
SQL function:
CREATE OR REPLACE FUNCTION ExtractPostcode2(adr text) RETURNS text AS $$
SELECT CASE WHEN (adr ~* '([,]|[.])\s\w{2,}\s{0,}\w{0,}\s{1,}\d{5}' OR
767 FIFTH AVE., NEW YORK, NY 10153 | 10153
Even excluding the P.O. BOX # and SUITE #, noise Noise still exists.
After extracting postcode, next, the following function is used to get clean postcode.
The priority is 'postcode' if it is '\d{5}', postcode_addr1, postcode_addr2, postcode_city
CREATE OR REPLACE FUNCTION PostcodeClean2 (text,text,text,text) RETURNS text AS $$
$pri1=$_[0];
$pri2=$_[1];
if ($pri3) {return $pri3;}
return undef;
$$ LANGUAGE plperl;
The details and SQL function are in E:\McNair\Projects\PatentAddress\Cleang_Step2RestructureAddressInfo(Second Stage).sql
The output is table ptoassigneend_us_postex which include a new feature 'postcode_extracted'.
====Clean 'city'====
'city' can be is cleaned using the following patterns.
*Pattern 1: 'city' is like ~ 'city name, state ID'
*Pattern 2: 'city' is like ~ 'city name, state postcode (5 digits)'
*Pattern 3: 'city' is like ~ 'city name,'
The SQL function is:
$$ LANGUAGE SQL;
The details and SQL function are in E:\McNair\Projects\PatentAddress\Cleang_Step2RestructureAddressInfo(Second Stage).sql
The output is table ptoassigneend_us_postex2 which include a new feature 'city_extracted' and 'postcode_extracted'.
===Identify Clean Data (Round Two)===
A new list of clean city is extracted in Section 4.3.2. This list, combined with 'ptoassigneend_us_citylist', creates a new city list 'ptoassigneend_us_citylist2' which can be used to identify clean data.
Since the city list is not long, I briefly cleaned the list it by hand, and stored it in ptoassigneend_us_citylist2.
* Actually, we can buy find a full list of U.S. cities online: https://www.uscitieslist.org/.
====Output: ptoassigneend_us_identify3====
Similar to Section 4.2, identify clean data that meets all the requirements: postcode_extracted with 5-4 or 5 digits, state not null or and not spaces, and city_extracted in ptoasigneend_us_citylist2.
SQL Code:
====Output: ptoassigneend_us_identify4====
Some of the city records contain dots. Remove dots, and then match 'city' with ptoassigneend_us_citylist2.
SQL Code:
CREATE TABLE ptoassigneend_us_identify4 AS
The remaining records are stored in ptoassigneend_us_temp5.
====Output: ptoassigneend_us_identify5=Summary===
One problem for the REMAINING records is that the Table Name | Records # ----------------------------------------------------|------------- ptoassigneend_allus | 3572605 ----------------------------------------------------|------------- ptoassigneend_us_identify0 | 5343 ptoassigneend_us_temp | 3567261 ptoassigneend_us_identify1 | 2511356 ptoassigneend_us_temp2 | 1055874 ptoassigneend_us_identify2 | 14508 ptoassigneend_us_temp3 | 1041366 ptoassigneend_us_identify3 | 664524 ptoassigneend_us_temp4 | 376835 ptoassigneend_us_identify4 | 38 ptoassigneend_us_temp5 | 376797 ----------------------------------------------------|------------- ptoassigneend_us_identify_subtotal | 3195769 ----------------------------------------------------|------------- ptoassigneend_us_candid1 (city and state are clean) | 136958 ptoassigneend_us_candid2 (postcode is missing. clean) | 184123
If we relax the requirements for postcode, we'll get clean data (city that is a city, state that is a state) stored in ptoassigneend_us_identify4.====Output: ptoassigneend_us_identify_subtotal====
SQL code: CREATE TABLE ptoassigneend_us_identify5 AS SELECT * FROM ptoassigneend_us_temp5 WHERE city_extracted2 IN ( SELECT citylist FROM ptoassigneend_us_citylist2) AND state IS NOT NULL AND state != ''; SELECT 136958  Remaining records are in table ptoassigneend_us_temp6 (SELECT 239837). ===Summary===  Table Name | Records # ---------------------------|------------- ptoassigneend_allus | 3572605 ---------------------------|------------- ptoassigneend_us_identify0 | 5343 ptoassigneend_us_temp | 3567261 ptoassigneend_us_identify1 | 2511356 ptoassigneend_us_temp2 | 1055874 ptoassigneend_us_identify2 | 14508 ptoassigneend_us_temp3 | 1041366 ptoassigneend_us_identify3 | 664524 ptoassigneend_us_temp4 | 376835 ptoassigneend_us_identify4 | 38 ptoassigneend_us_temp5 | 376797 ptoassigneend_us_identify5 | 136958 ptoassigneend_us_temp6 | 239837 Union ptoassigneend_us_identify(0-4) to get generate ptoassigneend_us_identify_subtotal (3195769)with clean city, state and postcode. This table contains 89.5% of all the records in ptoassigneend_allus. 10.5% left in ptoassigneend_us_temp5.
Table "public.ptoassigneend_us_identify_subtotal"
postcode_cleaned | text |
====Output: ptoassigneend_us_candid1====
 
One problem of records in ptoassigneend_us_temp5 is that the postcode is missing.
 
ptoassigneend_us_candid1 is a subset of ptoassigneend_us_temp5. It contains clean city and state info, but postcode is missing.
 
SQL code:
CREATE TABLE ptoassigneend_us_candid1 AS
SELECT *
FROM ptoassigneend_us_temp5
WHERE city_extracted2 IN (
SELECT citylist
FROM ptoassigneend_us_citylist2) AND
state IS NOT NULL AND state != '';
SELECT 136958
 
Remaining records are in table ptoassigneend_us_temp6 (SELECT 239837).
 
====Output: ptoassigneend_us_candid2====
ptoassigneend_us_candid2 is also a subset of ptoassigneend_us_temp5. It contains clean postcode info, but city and state are not identified.
ptoassigneend_us_identify5 doesn't contain I randomly checked the city_extracted in ptoassigneend_us_candid2, and it is quite clean passcode info. Some city records are misspelt, but contains such as 'Oklahama City'. We may identify clean city and state info. 6.7% data left in ptoassigneend_us_temp6based on the length of records.
Note: About 60 records are missing. For example, the # of records in ptoassigneend_us_temp + # of records in ptoassigneend_us_identify0 != # ptoassigneend_allus.
About 60 records are missing. For example====To do====* Remove city, state, zip, the # of records in ptoassigneend_us_temp + # of records in ptoassigneend_us_identify0 != # ptoassigneend_alluscountry from addrline1 & addrline2 to get clean addrlines.* Maybe concatenate addrline1 and addrline to make addrline

Navigation menu